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:
aleth 2014-11-08 03:24:01 +01:00
Родитель be3a745b52
Коммит 08ca2258a4
8 изменённых файлов: 451 добавлений и 37 удалений

Просмотреть файл

@ -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;
}