Bug 954845 - Get rid of the status bar: Port status panels from Firefox. r=clokep
--HG-- extra : histedit_source : 480b87de0c6af8ca3d6361e2a8f1ef02fbd85eed
This commit is contained in:
Родитель
be3a745b52
Коммит
08ca2258a4
|
@ -10,8 +10,10 @@
|
|||
|
||||
<binding id="aboutPanel">
|
||||
<content flex="1">
|
||||
<xul:browser anonid="aboutBrowser" disablehistory="true" type="content"
|
||||
flex="1" tooltip="imTooltip"/>
|
||||
<xul:vbox flex="1">
|
||||
<xul:browser anonid="aboutBrowser" disablehistory="true" type="content"
|
||||
flex="1" tooltip="imTooltip"/>
|
||||
</xul:vbox>
|
||||
</content>
|
||||
|
||||
<implementation>
|
||||
|
|
|
@ -65,13 +65,21 @@ function getTabBrowser() document.getElementById("conversations")
|
|||
|
||||
function getBrowser() getTabBrowser().selectedBrowser
|
||||
|
||||
// Copied from mozilla/browser/base/content/utilityOverlay.js
|
||||
function trimURL(aURL) {
|
||||
// This function must not modify the given URL such that calling
|
||||
// nsIURIFixup::createFixupURI with the result will produce a different URI.
|
||||
return aURL /* remove single trailing slash for http/https/ftp URLs */
|
||||
.replace(/^((?:http|https|ftp):\/\/[^/]+)\/$/, "$1")
|
||||
/* remove http:// unless the host starts with "ftp\d*\." or contains "@" */
|
||||
.replace(/^http:\/\/((?!ftp\d*\.)[^\/@]+(?:\/|$))/, "$1");
|
||||
}
|
||||
|
||||
// Copied from mozilla/browser/base/content/browser.js (and simplified)
|
||||
var XULBrowserWindow = {
|
||||
// Stored Status
|
||||
status: "",
|
||||
defaultStatus: "",
|
||||
jsStatus: "",
|
||||
jsDefaultStatus: "",
|
||||
overLink: "",
|
||||
statusText: "",
|
||||
|
||||
|
@ -84,8 +92,7 @@ var XULBrowserWindow = {
|
|||
},
|
||||
|
||||
get statusTextField () {
|
||||
delete this.statusTextField;
|
||||
return this.statusTextField = document.getElementById("statusbar-display");
|
||||
return getTabBrowser().getStatusPanel();
|
||||
},
|
||||
|
||||
setStatus: function (status) {
|
||||
|
@ -93,14 +100,8 @@ var XULBrowserWindow = {
|
|||
this.updateStatusField();
|
||||
},
|
||||
|
||||
setJSStatus: function (status) {
|
||||
this.jsStatus = status;
|
||||
this.updateStatusField();
|
||||
},
|
||||
|
||||
setJSDefaultStatus: function (status) {
|
||||
this.jsDefaultStatus = status;
|
||||
this.updateStatusField();
|
||||
setJSStatus: function () {
|
||||
// unsupported
|
||||
},
|
||||
|
||||
setDefaultStatus: function (status) {
|
||||
|
@ -108,39 +109,161 @@ var XULBrowserWindow = {
|
|||
this.updateStatusField();
|
||||
},
|
||||
|
||||
setOverLink: function (link, b) {
|
||||
setOverLink: function (url, anchorElt) {
|
||||
// Encode bidirectional formatting characters.
|
||||
// (RFC 3987 sections 3.2 and 4.1 paragraph 6)
|
||||
this.overLink = link.replace(/[\u200e\u200f\u202a\u202b\u202c\u202d\u202e]/g,
|
||||
encodeURIComponent);
|
||||
this.updateStatusField();
|
||||
url = url.replace(/[\u200e\u200f\u202a\u202b\u202c\u202d\u202e]/g,
|
||||
encodeURIComponent);
|
||||
|
||||
// if (gURLBar && gURLBar._mayTrimURLs /* corresponds to browser.urlbar.trimURLs */)
|
||||
// This pref is true by default for Firefox, let's follow that.
|
||||
url = trimURL(url);
|
||||
|
||||
this.overLink = url;
|
||||
LinkTargetDisplay.update();
|
||||
},
|
||||
|
||||
// Called before links are navigated to, allows us to retarget them if needed.
|
||||
onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {
|
||||
// Simplified for IB.
|
||||
return originalTarget;
|
||||
},
|
||||
|
||||
setStatusEnd: function (aStatusEndText, aError) {
|
||||
let field = document.getElementById("statusbar-display-end");
|
||||
field.label = aStatusEndText;
|
||||
field.hidden = !aStatusEndText;
|
||||
if (aError)
|
||||
field.setAttribute("error", "true");
|
||||
else
|
||||
field.removeAttribute("error");
|
||||
},
|
||||
|
||||
updateStatusField: function () {
|
||||
var text = this.overLink || this.status || this.jsStatus || this.jsDefaultStatus || this.defaultStatus;
|
||||
var text, type, types = ["overLink"];
|
||||
if (this._busyUI)
|
||||
types.push("status");
|
||||
types.push("defaultStatus");
|
||||
for (type of types) {
|
||||
text = this[type];
|
||||
if (text)
|
||||
break;
|
||||
}
|
||||
|
||||
// check the current value so we don't trigger an attribute change
|
||||
// and cause needless (slow!) UI updates
|
||||
if (this.statusText != text) {
|
||||
this.statusTextField.label = text;
|
||||
let field = this.statusTextField;
|
||||
field.setAttribute("previoustype", field.getAttribute("type"));
|
||||
field.setAttribute("type", type);
|
||||
field.label = text;
|
||||
field.setAttribute("crop", type == "overLink" ? "center" : "end");
|
||||
this.statusText = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Copied from mozilla/browser/base/content/browser.js
|
||||
var LinkTargetDisplay = {
|
||||
DELAY_SHOW: 80, // Services.prefs.getIntPref("browser.overlink-delay");
|
||||
DELAY_HIDE: 250,
|
||||
_timer: 0,
|
||||
|
||||
get _isVisible () XULBrowserWindow.statusTextField.label != "",
|
||||
|
||||
update: function () {
|
||||
clearTimeout(this._timer);
|
||||
window.removeEventListener("mousemove", this, true);
|
||||
|
||||
if (!XULBrowserWindow.overLink) {
|
||||
if (XULBrowserWindow.hideOverLinkImmediately)
|
||||
this._hide();
|
||||
else
|
||||
this._timer = setTimeout(this._hide.bind(this), this.DELAY_HIDE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._isVisible) {
|
||||
XULBrowserWindow.updateStatusField();
|
||||
} else {
|
||||
// Let the display appear when the mouse doesn't move within the delay
|
||||
this._showDelayed();
|
||||
window.addEventListener("mousemove", this, true);
|
||||
}
|
||||
},
|
||||
|
||||
handleEvent: function (event) {
|
||||
switch (event.type) {
|
||||
case "mousemove":
|
||||
// Restart the delay since the mouse was moved
|
||||
clearTimeout(this._timer);
|
||||
this._showDelayed();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_showDelayed: function () {
|
||||
this._timer = setTimeout(function (self) {
|
||||
XULBrowserWindow.updateStatusField();
|
||||
window.removeEventListener("mousemove", self, true);
|
||||
}, this.DELAY_SHOW, this);
|
||||
},
|
||||
|
||||
_hide: function () {
|
||||
clearTimeout(this._timer);
|
||||
|
||||
XULBrowserWindow.updateStatusField();
|
||||
}
|
||||
};
|
||||
|
||||
// Copied from mozilla/browser/base/content/browser.js
|
||||
var MousePosTracker = {
|
||||
_listeners: new Set(),
|
||||
_x: 0,
|
||||
_y: 0,
|
||||
get _windowUtils() {
|
||||
delete this._windowUtils;
|
||||
return this._windowUtils = window.getInterface(Ci.nsIDOMWindowUtils);
|
||||
},
|
||||
|
||||
addListener: function (listener) {
|
||||
if (this._listeners.has(listener))
|
||||
return;
|
||||
|
||||
listener._hover = false;
|
||||
this._listeners.add(listener);
|
||||
|
||||
this._callListener(listener);
|
||||
},
|
||||
|
||||
removeListener: function (listener) {
|
||||
this._listeners.delete(listener);
|
||||
},
|
||||
|
||||
handleEvent: function (event) {
|
||||
var fullZoom = this._windowUtils.fullZoom;
|
||||
this._x = event.screenX / fullZoom - window.mozInnerScreenX;
|
||||
this._y = event.screenY / fullZoom - window.mozInnerScreenY;
|
||||
|
||||
this._listeners.forEach(function (listener) {
|
||||
try {
|
||||
this._callListener(listener);
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
_callListener: function (listener) {
|
||||
let rect = listener.getMouseTargetRect();
|
||||
let hover = this._x >= rect.left &&
|
||||
this._x <= rect.right &&
|
||||
this._y >= rect.top &&
|
||||
this._y <= rect.bottom;
|
||||
|
||||
if (hover == listener._hover)
|
||||
return;
|
||||
|
||||
listener._hover = hover;
|
||||
|
||||
if (hover) {
|
||||
if (listener.onMouseEnter)
|
||||
listener.onMouseEnter();
|
||||
} else {
|
||||
if (listener.onMouseLeave)
|
||||
listener.onMouseLeave();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.addEventListener("load", convWindow.load);
|
||||
|
|
|
@ -196,9 +196,4 @@
|
|||
</svg:mask>
|
||||
</svg:svg>
|
||||
#endif
|
||||
|
||||
<statusbar id="convWindow-statusbar">
|
||||
<statusbarpanel id="statusbar-display" label="" crop="end" flex="1"/>
|
||||
<statusbarpanel id="statusbar-display-end" label=""/>
|
||||
</statusbar>
|
||||
</window>
|
||||
|
|
|
@ -52,3 +52,54 @@ tabconversation {
|
|||
#context_tabSpecificStartSeparator + #context_tabSpecificEndSeparator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Status panel */
|
||||
|
||||
statuspanel {
|
||||
-moz-binding: url("chrome://instantbird/content/tabbrowser.xml#statuspanel");
|
||||
position: fixed;
|
||||
margin-top: -3em;
|
||||
max-width: calc(100% - 5px);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
statuspanel:-moz-locale-dir(ltr)[mirror],
|
||||
statuspanel:-moz-locale-dir(rtl):not([mirror]) {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
statuspanel[sizelimit] {
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
statuspanel[type=status] {
|
||||
min-width: 23em;
|
||||
}
|
||||
|
||||
@media all and (max-width: 800px) {
|
||||
statuspanel[type=status] {
|
||||
min-width: 33%;
|
||||
}
|
||||
}
|
||||
|
||||
statuspanel[type=overLink] {
|
||||
transition: opacity 120ms ease-out;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
statuspanel[inactive] {
|
||||
transition: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
statuspanel[inactive][previoustype=overLink] {
|
||||
transition: opacity 200ms ease-out;
|
||||
}
|
||||
|
||||
.statuspanel-inner {
|
||||
height: 3em;
|
||||
width: 100%;
|
||||
-moz-box-align: end;
|
||||
}
|
||||
|
||||
|
|
|
@ -436,6 +436,10 @@
|
|||
prevent a previously focused element from retaining focus and continuing
|
||||
to receive input.
|
||||
|
||||
If the panel contains a browser, it should set the browser property and
|
||||
ensure that it has a parent element in the binding, so the status panel
|
||||
can be attached after it.
|
||||
|
||||
Panels can implement the following methods to customize behavior in certain situations:
|
||||
destroy:
|
||||
Called before panel is removed.
|
||||
|
@ -480,6 +484,8 @@
|
|||
|
||||
var t = this.mTabContainer.addTab();
|
||||
aPanel.tab = t;
|
||||
if (aPanel.browser)
|
||||
t.linkedBrowser = aPanel.browser;
|
||||
|
||||
if (aConv) {
|
||||
aConv.QueryInterface(Components.interfaces.imIConversation);
|
||||
|
@ -494,7 +500,6 @@
|
|||
aPanel.setAttribute("autoscrollpopup", this._autoScrollPopup.id);
|
||||
aPanel.conv = aConv;
|
||||
t.linkedConversation = aPanel;
|
||||
t.linkedBrowser = aPanel.browser;
|
||||
// We start our browsers out as inactive, and then maintain
|
||||
// activeness in updateCurrentTab.
|
||||
aPanel.browser.docShell.isActive = false;
|
||||
|
@ -873,6 +878,41 @@
|
|||
</setter>
|
||||
</property>
|
||||
|
||||
<method name="getStatusPanel">
|
||||
<body><![CDATA[
|
||||
// These two methods are kept close to the original, but note
|
||||
// that unlike the tabbrowser.xml in browser/, we need to add
|
||||
// a statuspanel to all tab panels with a browser element.
|
||||
|
||||
if (!this.selectedBrowser) {
|
||||
Components.utils.reportError("Browser element in a tab panel " +
|
||||
"without a browser property");
|
||||
return null;
|
||||
}
|
||||
|
||||
let panel = this.selectedPanel;
|
||||
if (!panel._statusPanel) {
|
||||
panel._statusPanel =
|
||||
document.createElementNS(this.namespaceURI, "statuspanel");
|
||||
panel._statusPanel.setAttribute("inactive", "true");
|
||||
panel._statusPanel.setAttribute("layer", "true");
|
||||
this._appendStatusPanel();
|
||||
}
|
||||
return panel._statusPanel;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_appendStatusPanel">
|
||||
<body><![CDATA[
|
||||
let panel = this.selectedPanel;
|
||||
if (panel && panel._statusPanel) {
|
||||
let browser = this.selectedBrowser;
|
||||
let browserContainer = browser.parentNode;
|
||||
browserContainer.insertBefore(panel._statusPanel, browser.nextSibling);
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<property name="selectedBrowser"
|
||||
onget="return this.mCurrentTab.linkedBrowser || null;"
|
||||
readonly="true"/>
|
||||
|
@ -1457,6 +1497,120 @@
|
|||
</implementation>
|
||||
</binding>
|
||||
|
||||
<binding id="statuspanel" display="xul:hbox">
|
||||
<content>
|
||||
<xul:hbox class="statuspanel-inner">
|
||||
<xul:label class="statuspanel-label"
|
||||
role="status"
|
||||
aria-live="off"
|
||||
xbl:inherits="value=label,crop,mirror"
|
||||
flex="1"
|
||||
crop="end"/>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
|
||||
<implementation implements="nsIDOMEventListener">
|
||||
<constructor><![CDATA[
|
||||
window.addEventListener("resize", this, false);
|
||||
]]></constructor>
|
||||
|
||||
<destructor><![CDATA[
|
||||
window.removeEventListener("resize", this, false);
|
||||
MousePosTracker.removeListener(this);
|
||||
]]></destructor>
|
||||
|
||||
<property name="label">
|
||||
<setter><![CDATA[
|
||||
if (!this.label) {
|
||||
this.removeAttribute("mirror");
|
||||
this.removeAttribute("sizelimit");
|
||||
}
|
||||
|
||||
this.style.minWidth = this.getAttribute("type") == "status" &&
|
||||
this.getAttribute("previoustype") == "status"
|
||||
? getComputedStyle(this).width : "";
|
||||
|
||||
if (val) {
|
||||
this.setAttribute("label", val);
|
||||
this.removeAttribute("inactive");
|
||||
this._calcMouseTargetRect();
|
||||
MousePosTracker.addListener(this);
|
||||
} else {
|
||||
this.setAttribute("inactive", "true");
|
||||
MousePosTracker.removeListener(this);
|
||||
}
|
||||
|
||||
return val;
|
||||
]]></setter>
|
||||
<getter>
|
||||
return this.hasAttribute("inactive") ? "" : this.getAttribute("label");
|
||||
</getter>
|
||||
</property>
|
||||
|
||||
<method name="getMouseTargetRect">
|
||||
<body><![CDATA[
|
||||
return this._mouseTargetRect;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="onMouseEnter">
|
||||
<body>
|
||||
this._mirror();
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="onMouseLeave">
|
||||
<body>
|
||||
this._mirror();
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="handleEvent">
|
||||
<parameter name="event"/>
|
||||
<body><![CDATA[
|
||||
if (!this.label)
|
||||
return;
|
||||
|
||||
switch (event.type) {
|
||||
case "resize":
|
||||
this._calcMouseTargetRect();
|
||||
break;
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_calcMouseTargetRect">
|
||||
<body><![CDATA[
|
||||
let container = this.parentNode;
|
||||
let alignRight = (getComputedStyle(container).direction == "rtl");
|
||||
let panelRect = this.getBoundingClientRect();
|
||||
let containerRect = container.getBoundingClientRect();
|
||||
|
||||
this._mouseTargetRect = {
|
||||
top: panelRect.top,
|
||||
bottom: panelRect.bottom,
|
||||
left: alignRight ? containerRect.right - panelRect.width : containerRect.left,
|
||||
right: alignRight ? containerRect.right : containerRect.left + panelRect.width
|
||||
};
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_mirror">
|
||||
<body>
|
||||
if (this.hasAttribute("mirror"))
|
||||
this.removeAttribute("mirror");
|
||||
else
|
||||
this.setAttribute("mirror", "true");
|
||||
|
||||
if (!this.hasAttribute("sizelimit")) {
|
||||
this.setAttribute("sizelimit", "true");
|
||||
this._calcMouseTargetRect();
|
||||
}
|
||||
</body>
|
||||
</method>
|
||||
</implementation>
|
||||
</binding>
|
||||
|
||||
<binding id="tabbrowser-arrowscrollbox" extends="chrome://global/content/bindings/scrollbox.xml#arrowscrollbox-clicktoscroll">
|
||||
<implementation>
|
||||
<!-- Override scrollbox.xml method, since our scrollbox's children are
|
||||
|
|
|
@ -222,3 +222,31 @@
|
|||
/* box-shadow instead of background-color to work around native styling */
|
||||
box-shadow: inset -5px 0 ThreeDShadow;
|
||||
}
|
||||
|
||||
|
||||
/* Status panel */
|
||||
|
||||
.statuspanel-label {
|
||||
margin: 0;
|
||||
padding: 2px 4px;
|
||||
background: linear-gradient(#fff, #ddd);
|
||||
border: 1px none #ccc;
|
||||
border-top-style: solid;
|
||||
color: #333;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.statuspanel-label:-moz-locale-dir(ltr):not([mirror]),
|
||||
.statuspanel-label:-moz-locale-dir(rtl)[mirror] {
|
||||
border-right-style: solid;
|
||||
border-top-right-radius: .3em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.statuspanel-label:-moz-locale-dir(rtl):not([mirror]),
|
||||
.statuspanel-label:-moz-locale-dir(ltr)[mirror] {
|
||||
border-left-style: solid;
|
||||
border-top-left-radius: .3em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
|
|
|
@ -584,3 +584,31 @@ statusbarpanel#statusbar-display {
|
|||
/* box-shadow instead of background-color to work around native styling */
|
||||
box-shadow: inset -5px 0 ThreeDShadow;
|
||||
}
|
||||
|
||||
|
||||
/* Status panel */
|
||||
|
||||
.statuspanel-label {
|
||||
margin: 0;
|
||||
padding: 2px 4px;
|
||||
background: linear-gradient(#fff, #ddd);
|
||||
border: 1px none #ccc;
|
||||
border-top-style: solid;
|
||||
color: #333;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.statuspanel-label:-moz-locale-dir(ltr):not([mirror]),
|
||||
.statuspanel-label:-moz-locale-dir(rtl)[mirror] {
|
||||
border-right-style: solid;
|
||||
border-top-right-radius: .3em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.statuspanel-label:-moz-locale-dir(rtl):not([mirror]),
|
||||
.statuspanel-label:-moz-locale-dir(ltr)[mirror] {
|
||||
border-left-style: solid;
|
||||
border-top-left-radius: .3em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
|
|
|
@ -336,3 +336,36 @@ toolbarbutton > .toolbarbutton-icon {
|
|||
.tabs-closebutton:hover:active {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
}
|
||||
|
||||
|
||||
/* Status panel */
|
||||
|
||||
.statuspanel-label {
|
||||
margin: 0;
|
||||
padding: 2px 4px;
|
||||
background: linear-gradient(#fff, #ddd);
|
||||
border: 1px none #ccc;
|
||||
border-top-style: solid;
|
||||
color: #333;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
.statuspanel-label:-moz-locale-dir(ltr):not([mirror]),
|
||||
.statuspanel-label:-moz-locale-dir(rtl)[mirror] {
|
||||
border-right-style: solid;
|
||||
/* disabled for triggering grayscale AA (bug 659213)
|
||||
border-top-right-radius: .3em;
|
||||
*/
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.statuspanel-label:-moz-locale-dir(rtl):not([mirror]),
|
||||
.statuspanel-label:-moz-locale-dir(ltr)[mirror] {
|
||||
border-left-style: solid;
|
||||
/* disabled for triggering grayscale AA (bug 659213)
|
||||
border-top-left-radius: .3em;
|
||||
*/
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче