/* 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/. */
/** * Describes how the tab ended up in this mute state. May be any of: * * - undefined: The tabs mute state has never changed. * - null: The mute state was last changed through the UI. * - Any string: The ID was changed through an extension API. The string * must be the ID of the extension which changed it.
*/ this.muteReason = undefined;
set _selected(val) { // in e10s we want to only pseudo-select a tab before its rendering is done, so that // the rest of the system knows that the tab is selected, but we don't want to update its // visual status to selected until after we receive confirmation that its content has painted. if (val) { this.setAttribute("selected", "true");
} else { this.removeAttribute("selected");
}
// If we're non-e10s we need to update the visual selection at the same // time, otherwise AsyncTabSwitcher will take care of this. if (!gMultiProcessBrowser) { this._visuallySelected = val;
}
}
get pinned() { returnthis.hasAttribute("pinned");
}
get isOpen() { return ( this.isConnected && !this.closing && this != FirefoxViewHandler.tab
);
}
get visible() { returnthis.isOpen && !this.hidden && !this.group?.collapsed;
}
get hidden() { // This getter makes `hidden` read-only returnsuper.hidden;
}
get muted() { returnthis.hasAttribute("muted");
}
get multiselected() { returnthis.hasAttribute("multiselected");
}
get userContextId() { returnthis.hasAttribute("usercontextid")
? parseInt(this.getAttribute("usercontextid"))
: 0;
}
get soundPlaying() { returnthis.hasAttribute("soundplaying");
}
get pictureinpicture() { returnthis.hasAttribute("pictureinpicture");
}
get activeMediaBlocked() { returnthis.hasAttribute("activemedia-blocked");
}
get undiscardable() { returnthis.hasAttribute("undiscardable");
}
get isEmpty() { // Determines if a tab is "empty", usually used in the context of determining // if it's ok to close the tab. if (this.hasAttribute("busy")) { returnfalse;
}
if (this.hasAttribute("customizemode")) { returnfalse;
}
let browser = this.linkedBrowser; if (!isBlankPageURL(browser.currentURI.spec)) { returnfalse;
}
if (!BrowserUIUtils.checkEmptyPageOrigin(browser)) { returnfalse;
}
if (browser.canGoForward || browser.canGoBack) { returnfalse;
}
/** * Returns a timestamp which attempts to represent the last time the user saw this tab. * If the tab has not been active in this session, any lastAccessed is used. We * differentiate between selected and explicitly visible; a selected tab in a hidden * window is last seen when that window and tab were last visible. * We use the application start time as a fallback value when no other suitable value * is available.
*/
get lastSeenActive() { const isForegroundWindow = this.ownerGlobal ==
BrowserWindowTracker.getTopWindow({ allowPopups: true }); // the timestamp for the selected tab in the active window is always now if (isForegroundWindow && this.selected) { return Date.now();
} if (this._lastSeenActive) { returnthis._lastSeenActive;
}
if (
!this._lastAccessed || this._lastAccessed >= this.container.startupTime
) { // When the tab was created this session but hasn't been seen by the user, // default to the application start time. returnthis.container.startupTime;
} // The tab was restored from a previous session but never seen. // Use the lastAccessed as the best proxy for when the user might have seen it. returnthis._lastAccessed;
}
get _overPlayingIcon() { returnthis.overlayIcon?.matches(":hover");
}
get _overAudioButton() { returnthis.audioButton?.matches(":hover");
}
get overlayIcon() { returnthis.querySelector(".tab-icon-overlay");
}
get audioButton() { returnthis.querySelector(".tab-audio-button");
}
get throbber() { returnthis.querySelector(".tab-throbber");
}
get iconImage() { returnthis.querySelector(".tab-icon-image");
}
get sharingIcon() { returnthis.querySelector(".tab-sharing-icon-overlay");
}
get textLabel() { returnthis.querySelector(".tab-label");
}
get closeButton() { returnthis.querySelector(".tab-close-button");
}
get group() { if (this.parentElement?.tagName == "tab-group") { returnthis.parentElement;
} returnnull;
}
on_mouseover(event) { if (event.target.classList.contains("tab-close-button")) { this.mOverCloseButton = true;
}
if (!this.visible) { return;
}
let tabToWarm = this.mOverCloseButton
? gBrowser._findTabToBlurTo(this)
: this;
gBrowser.warmupTab(tabToWarm);
// If the previous target wasn't part of this tab then this is a mouseenter event. if (!this.contains(event.relatedTarget)) { this._mouseenter();
}
}
on_mouseout(event) { if (event.target.classList.contains("tab-close-button")) { this.mOverCloseButton = false;
}
// If the new target is not part of this tab then this is a mouseleave event. if (!this.contains(event.relatedTarget)) { this._mouseleave();
}
}
on_dragstart(event) { // We use "failed" drag end events that weren't cancelled by the user // to detach tabs. Ensure that we do not show the drag image returning // to its point of origin when this happens, as it makes the drag // finishing feel very slow.
event.dataTransfer.mozShowFailAnimation = false; if (event.eventPhase == Event.CAPTURING_PHASE) { this.style.MozUserFocus = "";
} elseif ( this.mOverCloseButton ||
gSharedTabWarning.willShowSharedTabWarning(this)
) {
event.stopPropagation();
}
}
on_mousedown(event) {
let eventMaySelectTab = true;
let tabContainer = this.container;
if (event.button == 1) {
gBrowser.warmupTab(gBrowser._findTabToBlurTo(this));
}
if (event.button == 0) {
let shiftKey = event.shiftKey;
let accelKey = event.getModifierState("Accel"); if (shiftKey) {
eventMaySelectTab = false; const lastSelectedTab = gBrowser.lastMultiSelectedTab; if (!accelKey) {
gBrowser.selectedTab = lastSelectedTab;
// Make sure selection is cleared when tab-switch doesn't happen.
gBrowser.clearMultiSelectedTabs();
}
gBrowser.addRangeToMultiSelectedTabs(lastSelectedTab, this);
} elseif (accelKey) { // Ctrl (Cmd for mac) key is pressed
eventMaySelectTab = false; if (this.multiselected) {
gBrowser.removeFromMultiSelectedTabs(this);
} elseif (this != gBrowser.selectedTab) {
gBrowser.addToMultiSelectedTabs(this);
gBrowser.lastMultiSelectedTab = this;
}
} elseif (!this.selected && this.multiselected) {
gBrowser.lockClearMultiSelectionOnce();
}
}
if (gSharedTabWarning.willShowSharedTabWarning(this)) {
eventMaySelectTab = false;
}
if (eventMaySelectTab) { super.on_mousedown(event);
}
}
on_mouseup() { // Make sure that clear-selection is released. // Otherwise selection using Shift key may be broken.
gBrowser.unlockClearMultiSelection();
this.style.MozUserFocus = "";
}
on_click(event) { if (event.button != 0) { return;
}
if (event.getModifierState("Accel") || event.shiftKey) { return;
}
if (
gBrowser.multiSelectedTabsCount > 0 &&
!event.target.classList.contains("tab-close-button") &&
!event.target.classList.contains("tab-icon-overlay") &&
!event.target.classList.contains("tab-audio-button")
) { // Tabs were previously multi-selected and user clicks on a tab // without holding Ctrl/Cmd Key
gBrowser.clearMultiSelectedTabs();
}
if (
event.target.classList.contains("tab-icon-overlay") ||
event.target.classList.contains("tab-audio-button")
) { if (this.activeMediaBlocked) { if (this.multiselected) {
gBrowser.resumeDelayedMediaOnMultiSelectedTabs(this);
} else { this.resumeDelayedMedia();
}
} elseif (this.soundPlaying || this.muted) { if (this.multiselected) {
gBrowser.toggleMuteAudioOnMultiSelectedTabs(this);
} else { this.toggleMuteAudio();
}
} return;
}
if (event.target.classList.contains("tab-close-button")) { if (this.multiselected) {
gBrowser.removeMultiSelectedTabs();
} else {
gBrowser.removeTab(this, {
animate: true,
triggeringEvent: event,
});
} // This enables double-click protection for the tab container // (see tabbrowser-tabs 'click' handler).
gBrowser.tabContainer._blockDblClick = true;
}
}
on_dblclick(event) { if (event.button != 0) { return;
}
// for the one-close-button case if (event.target.classList.contains("tab-close-button")) {
event.stopPropagation();
}
on_animationstart(event) { if (!event.animationName.startsWith("tab-throbber-animation")) { return;
} // The animation is on a pseudo-element so we need to use `subtree: true` // to get our hands on it. for (let animation of event.target.getAnimations({ subtree: true })) { if (animation.animationName === event.animationName) { // Ensure all tab throbber animations are synchronized by sharing an // start time.
animation.startTime = 0;
}
}
}
on_animationend(event) { if (event.target.classList.contains("tab-loading-burst")) { this.removeAttribute("bursting");
}
}
_mouseenter() { this._hover = true;
if (this.selected) { this.container._handleTabSelect();
} elseif (this.linkedPanel) { this.linkedBrowser.unselectedTabHover(true);
}
// Prepare connection to host beforehand.
SessionStore.speculativeConnectOnTabHover(this);
toggleMuteAudio(aMuteReason) {
let browser = this.linkedBrowser; if (browser.audioMuted) { if (this.linkedPanel) { // "Lazy Browser" should not invoke its unmute method
browser.unmute();
} this.removeAttribute("muted");
} else { if (this.linkedPanel) { // "Lazy Browser" should not invoke its mute method
browser.mute();
} this.toggleAttribute("muted", true);
} this.muteReason = aMuteReason || null;
gBrowser._tabAttrModified(this, ["muted"]);
}
setUserContextId(aUserContextId) { if (aUserContextId) { if (this.linkedBrowser) { this.linkedBrowser.setAttribute("usercontextid", aUserContextId);
} this.setAttribute("usercontextid", aUserContextId);
} else { if (this.linkedBrowser) { this.linkedBrowser.removeAttribute("usercontextid");
} this.removeAttribute("usercontextid");
}
ContextualIdentityService.setTabStyle(this);
}
updateA11yDescription() {
let prevDescTab = gBrowser.tabContainer.querySelector( "tab[aria-describedby]"
); if (prevDescTab) { // We can only have a description for the focused tab.
prevDescTab.removeAttribute("aria-describedby");
}
let desc = document.getElementById("tabbrowser-tab-a11y-desc");
desc.textContent = gBrowser.getTabTooltip(this, false); this.setAttribute("aria-describedby", "tabbrowser-tab-a11y-desc");
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.