--- a/mobile/chrome/content/browser-ui.js
+++ b/mobile/chrome/content/browser-ui.js
@@ -692,17 +692,18 @@ var BrowserUI = {
this.activePanel = null;
Browser.selectedTab = aTab;
},
undoCloseTab: function undoCloseTab(aIndex) {
let tab = null;
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
if (ss.getClosedTabCount(window) > (aIndex || 0)) {
- tab = ss.undoCloseTab(window, aIndex || 0);
+ let chromeTab = ss.undoCloseTab(window, aIndex || 0);
+ tab = Browser.getTabFromChrome(chromeTab);
}
return tab;
},
isTabsVisible: function isTabsVisible() {
// The _1, _2 and _3 are to make the js2 emacs mode happy
let [leftvis,_1,_2,_3] = Browser.computeSidebarVisibility();
return (leftvis > 0.002);
@@ -1116,40 +1117,45 @@ var BrowserUI = {
break;
}
}
}
};
var TapHighlightHelper = {
get _overlay() {
- delete this._overlay;
- return this._overlay = document.getElementById("content-overlay");
+ if (Browser.selectedTab)
+ return Browser.selectedTab.overlay;
+ return null;
},
show: function show(aRects) {
+ let overlay = this._overlay;
+ if (!overlay)
+ return;
+
let browser = getBrowser();
let scroll = browser.getPosition();
let canvasArea = aRects.reduce(function(a, b) {
return a.expandToContain(b);
}, new Rect(0, 0, 0, 0)).map(function(val) val * browser.scale)
.translate(-scroll.x, -scroll.y);
- let overlay = this._overlay;
overlay.setAttribute("width", canvasArea.width);
overlay.setAttribute("height", canvasArea.height);
let ctx = overlay.getContext("2d");
ctx.save();
ctx.translate(-canvasArea.left, -canvasArea.top);
ctx.scale(browser.scale, browser.scale);
overlay.setAttribute("left", canvasArea.left);
overlay.setAttribute("top", canvasArea.top);
+ ctx.clearRect(0, 0, canvasArea.width, canvasArea.height);
ctx.fillStyle = "rgba(0, 145, 255, .5)";
for (let i = aRects.length - 1; i >= 0; i--) {
let rect = aRects[i];
ctx.fillRect(rect.left - scroll.x / browser.scale, rect.top - scroll.y / browser.scale, rect.width, rect.height);
}
ctx.restore();
overlay.style.display = "block";
@@ -1157,17 +1163,17 @@ var TapHighlightHelper = {
mozRequestAnimationFrame();
},
/**
* Hide the highlight. aGuaranteeShowMsecs specifies how many milliseconds the
* highlight should be shown before it disappears.
*/
hide: function hide(aGuaranteeShowMsecs) {
- if (this._overlay.style.display == "none")
+ if (!this._overlay || this._overlay.style.display == "none")
return;
this._guaranteeShow = Math.max(0, aGuaranteeShowMsecs);
if (this._guaranteeShow) {
// _shownAt is set once highlight has been painted
if (this._shownAt)
setTimeout(this._hide.bind(this),
Math.max(0, this._guaranteeShow - (mozAnimationStartTime - this._shownAt)));
--- a/mobile/chrome/content/browser.css
+++ b/mobile/chrome/content/browser.css
@@ -41,17 +41,18 @@ setting[type="integer"] {
setting[type="control"] {
-moz-binding: url("chrome://browser/content/bindings/setting.xml#setting-control");
}
setting[type="string"] {
-moz-binding: url("chrome://browser/content/bindings/setting.xml#setting-string");
}
-notificationbox {
+#browsers > notificationbox {
+ -moz-binding: url("chrome://browser/content/notification.xml#stacked-notificationbox");
overflow: -moz-hidden-unscrollable;
}
notification {
-moz-binding: url("chrome://browser/content/notification.xml#notification");
}
notification[type="geo"] {
--- a/mobile/chrome/content/browser.js
+++ b/mobile/chrome/content/browser.js
@@ -136,17 +136,17 @@ function onDebugKeyPress(ev) {
CommandUpdater.doCommand("cmd_menu");
break;
#ifndef MOZ_PLATFORM_MAEMO
case p:
function dispatchMagnifyEvent(aName, aDelta) {
let e = document.createEvent("SimpleGestureEvent");
e.initSimpleGestureEvent("MozMagnifyGesture"+aName, true, true, window, null,
0, 0, 0, 0, false, false, false, false, 0, null, 0, aDelta);
- document.getElementById("inputhandler-overlay").dispatchEvent(e);
+ Browser.selectedTab.inputHandler.dispatchEvent(e);
}
dispatchMagnifyEvent("Start", 0);
let frame = 0;
let timer = new Util.Timeout();
timer.interval(100, function() {
dispatchMagnifyEvent("Update", 20);
if (++frame > 10) {
@@ -188,23 +188,22 @@ var Browser = {
} catch (e) {
// XXX whatever is calling startup needs to dump errors!
dump("###########" + e + "\n");
}
// XXX change
/* handles dispatching clicks on browser into clicks in content or zooms */
- let inputHandlerOverlay = document.getElementById("inputhandler-overlay");
- inputHandlerOverlay.customDragger = new Browser.MainDragger();
-
- let keySender = new ContentCustomKeySender(inputHandlerOverlay);
+ Elements.browsers.customDragger = new Browser.MainDragger();
+
+ let keySender = new ContentCustomKeySender(Elements.browsers);
let mouseModule = new MouseModule();
let gestureModule = new GestureModule();
- let scrollWheelModule = new ScrollwheelModule(inputHandlerOverlay);
+ let scrollWheelModule = new ScrollwheelModule(Elements.browsers);
ContentTouchHandler.init();
// Warning, total hack ahead. All of the real-browser related scrolling code
// lies in a pretend scrollbox here. Let's not land this as-is. Maybe it's time
// to redo all the dragging code.
this.contentScrollbox = Elements.browsers;
this.contentScrollboxScroller = {
@@ -715,17 +714,17 @@ var Browser = {
tab = this.getTabFromChrome(tab);
if (!tab)
return;
if (this._selectedTab == tab) {
// Deck does not update its selectedIndex when children
// are removed. See bug 602708
- Elements.browsers.selectedPanel = tab.browser;
+ Elements.browsers.selectedPanel = tab.notification;
return;
}
TapHighlightHelper.hide();
if (this._selectedTab) {
this._selectedTab.pageScrollOffset = this.getScrollboxPosition(this.pageScrollboxScroller);
@@ -741,22 +740,20 @@ var Browser = {
this._selectedTab = tab;
// Lock the toolbar if the new tab is still loading
if (this._selectedTab.isLoading())
BrowserUI.lockToolbar();
if (lastTab)
- lastTab.updateBrowser(false);
+ lastTab.active = false;
if (tab)
- tab.updateBrowser(true);
-
- document.getElementById("tabs").selectedTab = tab.chromeTab;
+ tab.active = true;
if (!isFirstTab) {
// Update all of our UI to reflect the new tab's location
BrowserUI.updateURI();
getIdentityHandler().checkIdentity();
let event = document.createEvent("Events");
event.initEvent("TabSelect", true, false);
@@ -1492,17 +1489,17 @@ const ContentTouchHandler = {
this._contextMenu = null;
},
/**
* Check if the event concern the browser content
*/
_targetIsContent: function _targetIsContent(aEvent) {
let target = aEvent.target;
- return target && target.id == "inputhandler-overlay";
+ return target && target.classList.contains("inputHandler");
},
_dispatchMouseEvent: function _dispatchMouseEvent(aName, aX, aY, aModifiers) {
let aX = aX || 0;
let aY = aY || 0;
let browser = getBrowser();
let pos = browser.transformClientToBrowser(aX, aY);
browser.messageManager.sendAsyncMessage(aName, {
@@ -2464,16 +2461,17 @@ var OfflineApps = {
this.offlineAppRequested(aMessage.json, aMessage.target);
}
}
};
function Tab(aURI, aParams) {
this._id = null;
this._browser = null;
+ this._notification = null;
this._state = null;
this._listener = null;
this._loading = false;
this._chromeTab = null;
this._metadata = null;
this.owner = null;
// Set to 0 since new tabs that have not been viewed yet are good tabs to
@@ -2485,24 +2483,40 @@ function Tab(aURI, aParams) {
this.create(aURI, aParams || {});
}
Tab.prototype = {
get browser() {
return this._browser;
},
+ get notification() {
+ return this._notification;
+ },
+
get chromeTab() {
return this._chromeTab;
},
get metadata() {
return this._metadata || kDefaultMetadata;
},
+ get inputHandler() {
+ if (!this._notification)
+ return null;
+ return this._notification.inputHandler;
+ },
+
+ get overlay() {
+ if (!this._notification)
+ return null;
+ return this._notification.overlay;
+ },
+
/** Update browser styles when the viewport metadata changes. */
updateViewportMetadata: function updateViewportMetadata(aMetadata) {
this._metadata = aMetadata;
this.updateViewportSize();
},
/**
* Update browser size when the metadata or the window size changes.
@@ -2612,16 +2626,17 @@ Tab.prototype = {
},
_createBrowser: function _createBrowser(aURI, aInsertBefore) {
if (this._browser)
throw "Browser already exists";
// Create a notification box around the browser
let notification = this._notification = document.createElement("notificationbox");
+ notification.classList.add("inputHandler");
// Create the browser using the current width the dynamically size the height
let browser = this._browser = document.createElement("browser");
browser.setAttribute("class", "window-width window-height");
this._chromeTab.linkedBrowser = browser;
browser.setAttribute("type", "content");
@@ -2649,25 +2664,27 @@ Tab.prototype = {
this._listener = new ProgressController(this);
browser.webProgress.addProgressListener(this._listener, flags);
return browser;
},
_destroyBrowser: function _destroyBrowser() {
if (this._browser) {
+ let notification = this._notification;
let browser = this._browser;
browser.removeProgressListener(this._listener);
browser.messageManager.sendAsyncMessage("Browser:Blur", {});
+ this._notification = null;
this._browser = null;
this._listener = null;
this._loading = false;
- Elements.browsers.removeChild(browser);
+ Elements.browsers.removeChild(notification);
}
},
clampZoomLevel: function clampZoomLevel(aScale) {
let browser = this._browser;
let bounded = Util.clamp(aScale, ZoomManager.MIN, ZoomManager.MAX);
let md = this.metadata;
@@ -2746,31 +2763,41 @@ Tab.prototype = {
// set yet. This also blows up for async canvas draws.
if (!browser.contentWindowWidth || !browser.contentWindowHeight)
return;
this._thumbnailWindowId = browser.contentWindowId;
this._chromeTab.updateThumbnail(browser, browser.contentWindowWidth, browser.contentWindowHeight);
},
- updateBrowser: function updateBrowser(aDisplay) {
+ set active(aActive) {
+ if (!this._browser)
+ return;
+
let notification = this._notification;
let browser = this._browser;
- if (aDisplay) {
+
+ if (aActive) {
browser.setAttribute("type", "content-primary");
- notification.style.display = "";
+ Elements.browsers.selectedPanel = notification;
browser.messageManager.sendAsyncMessage("Browser:Focus", {});
+ document.getElementById("tabs").selectedTab = this._chromeTab;
}
else {
browser.setAttribute("type", "content");
- notification.style.display = "none";
browser.messageManager.sendAsyncMessage("Browser:Blur", {});
}
},
+ get active() {
+ if (!this._browser)
+ return false;
+ return this._browser.getAttribute("type") == "content-primary";
+ },
+
toString: function() {
return "[Tab " + (this._browser ? this._browser.currentURI.spec : "(no browser)") + "]";
}
};
// Helper used to hide IPC / non-IPC differences for rendering to a canvas
function rendererFactory(aBrowser, aCanvas) {
let wrapper = {};
--- a/mobile/chrome/content/browser.xul
+++ b/mobile/chrome/content/browser.xul
@@ -272,22 +272,18 @@
</toolbar>
</box>
</box>
<notificationbox id="notifications" class="window-width"/>
<!-- Content viewport -->
<vbox id="content-viewport" class="window-width window-height">
- <stack id="content-stack" flex="1">
<!-- Content viewport -->
- <deck id="browsers" flex="1"/>
- <html:canvas id="content-overlay" style="display: none; z-index: 1000;" left="0" top="0"/>
- <html:div id="inputhandler-overlay" style="z-index: 1001" tabindex="-1"/>
- </stack>
+ <deck id="browsers" flex="1"/>
<box id="content-navigator-spacer" hidden="true"/>
</vbox>
</vbox>
</scrollbox>
<!-- popup for content navigator helper -->
<vbox id="content-navigator" class="window-width" top="0" spacer="content-navigator-spacer">
<arrowscrollbox id="form-helper-autofill" collapsed="true" align="center" flex="1" orient="horizontal"
--- a/mobile/chrome/content/input.js
+++ b/mobile/chrome/content/input.js
@@ -520,27 +520,27 @@ var ScrollUtils = {
let qinterface = null;
for (; elem; elem = elem.parentNode) {
try {
if (elem.scrollBoxObject) {
scrollbox = elem;
qinterface = elem.scrollBoxObject;
break;
+ } else if (elem.customDragger) {
+ scrollbox = elem;
+ break;
} else if (elem.boxObject) {
let qi = (elem._cachedSBO) ? elem._cachedSBO
: elem.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
if (qi) {
scrollbox = elem;
scrollbox._cachedSBO = qinterface = qi;
break;
}
- } else if (elem.customDragger) {
- scrollbox = elem;
- break;
}
} catch (e) { /* we aren't here to deal with your exceptions, we'll just keep
traversing until we find something more well-behaved, as we
prefer default behaviour to whiny scrollers. */ }
}
return [scrollbox, qinterface, (scrollbox ? (scrollbox.customDragger || this._defaultDragger) : null)];
},
@@ -1067,18 +1067,17 @@ GestureModule.prototype = {
return;
// Cancel other touch sequence events, and be courteous by allowing them
// to say no.
let event = document.createEvent("Events");
event.initEvent("CancelTouchSequence", true, true);
let success = aEvent.target.dispatchEvent(event);
- if (!success || (aEvent.target instanceof XULElement) ||
- !Browser.selectedTab.allowZoom)
+ if (!success || (aEvent.target instanceof XULElement) || !Browser.selectedTab.allowZoom)
return;
// create the AnimatedZoom object for fast arbitrary zooming
this._pinchZoom = AnimatedZoom;
this._pinchStartRect = AnimatedZoom.getStartRect();
this._pinchDelta = 0;
let browser = getBrowser();
--- a/mobile/chrome/content/notification.xml
+++ b/mobile/chrome/content/notification.xml
@@ -3,17 +3,51 @@
<!ENTITY % notificationDTD SYSTEM
"chrome://browser/locale/notification.dtd">
%notificationDTD;
]>
<bindings
xmlns="http://www.mozilla.org/xbl"
xmlns:xbl="http://www.mozilla.org/xbl"
- xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml">
+
+ <binding id="stacked-notificationbox" extends="chrome://global/content/bindings/notification.xml#notificationbox">
+ <content>
+ <xul:stack xbl:inherits="hidden=notificationshidden">
+ <xul:spacer/>
+ <children includes="notification"/>
+ </xul:stack>
+ <xul:stack flex="1">
+ <children/>
+ <html:canvas anonid="content-overlay"/>
+ <html:div flex="1" class="input-overlay" anonid="input-overlay"/>
+ </xul:stack>
+ </content>
+ <implementation>
+ <property name="inputHandler">
+ <getter>
+ return document.getAnonymousElementByAttribute(this, "anonid", "input-overlay");
+ </getter>
+ </property>
+
+ <property name="overlay">
+ <getter>
+ return document.getAnonymousElementByAttribute(this, "anonid", "content-overlay");
+ </getter>
+ </property>
+
+ <property name="customDragger">
+ <getter>
+ return this.parentNode.customDragger;
+ </getter>
+ </property>
+ </implementation>
+ </binding>
<binding id="notification" extends="chrome://global/content/bindings/notification.xml#notification">
<resources>
<stylesheet src="chrome://browser/skin/notification.css"/>
</resources>
<content>
<xul:hbox class="notification-inner outset" flex="1" xbl:inherits="type">
--- a/mobile/chrome/tests/browser_tabs.js
+++ b/mobile/chrome/tests/browser_tabs.js
@@ -36,60 +36,60 @@ function load_tabs() {
//Check tab switch
new_tab_01.browser.addEventListener("load", tab_switch_01, true);
}
function tab_switch_01() {
BrowserUI.selectTab(new_tab_01);
is(Browser.selectedTab.browser.currentURI.spec, testURL_01, "Tab Switch 01 URL Matches");
- is(Browser.selectedTab.browser, Elements.browsers.selectedPanel, "Deck has correct browser");
+ is(Browser.selectedTab.notification, Elements.browsers.selectedPanel, "Deck has correct browser");
//Add new tab
new_tab_02 = Browser.addTab(testURL_02,false);
new_tab_02.browser.addEventListener("load", tab_switch_02, true);
- is(Browser.selectedTab.browser, Elements.browsers.selectedPanel, "Deck has correct browser");
+ is(Browser.selectedTab.notification, Elements.browsers.selectedPanel, "Deck has correct browser");
}
function tab_switch_02() {
BrowserUI.selectTab(new_tab_02);
is(Browser.selectedTab.browser.currentURI.spec, testURL_02, "Tab Switch 02 URL Matches");
- is(Browser.selectedTab.browser, Elements.browsers.selectedPanel, "Deck has correct browser");
+ is(Browser.selectedTab.notification, Elements.browsers.selectedPanel, "Deck has correct browser");
BrowserUI.selectTab(new_tab_01);
is(Browser.selectedTab.browser.currentURI.spec, testURL_01, "Tab Switch 01 URL Matches");
- is(Browser.selectedTab.browser, Elements.browsers.selectedPanel, "Deck has correct browser");
+ is(Browser.selectedTab.notification, Elements.browsers.selectedPanel, "Deck has correct browser");
//Add new tab
new_tab_03 = Browser.addTab(testURL_03, true, new_tab_01);
new_tab_03.browser.addEventListener("load", tab_switch_03, true);
}
function tab_switch_03() {
is(Browser.selectedTab.browser.currentURI.spec, testURL_03, "Tab Switch 03 URL Matches");
is(new_tab_03.owner, new_tab_01, "Tab 03 owned by tab 01");
- is(Browser.selectedTab.browser, Elements.browsers.selectedPanel, "Deck has correct browser");
+ is(Browser.selectedTab.notification, Elements.browsers.selectedPanel, "Deck has correct browser");
Browser.closeTab(new_tab_03);
is(Browser.selectedTab, new_tab_01, "Closing tab 03 returns to owner");
- is(Browser.selectedTab.browser, Elements.browsers.selectedPanel, "Deck has correct browser");
+ is(Browser.selectedTab.notification, Elements.browsers.selectedPanel, "Deck has correct browser");
new_tab_03 = Browser.addTab(testURL_03, true, new_tab_01);
new_tab_03.browser.addEventListener("load", tab_switch_04, true);
}
function tab_switch_04() {
is(Browser.selectedTab.browser.currentURI.spec, testURL_03, "Tab Switch 03 URL Matches");
is(new_tab_03.owner, new_tab_01, "Tab 03 owned by tab 01");
- is(Browser.selectedTab.browser, Elements.browsers.selectedPanel, "Deck has correct browser");
+ is(Browser.selectedTab.notification, Elements.browsers.selectedPanel, "Deck has correct browser");
Browser.closeTab(new_tab_01);
is(Browser.selectedTab, new_tab_03, "Closing tab 01 keeps selectedTab");
is(new_tab_03.owner, null, "Closing tab 01 nulls tab3 owner");
- is(Browser.selectedTab.browser, Elements.browsers.selectedPanel, "Deck has correct browser");
+ is(Browser.selectedTab.notification, Elements.browsers.selectedPanel, "Deck has correct browser");
done();
}
function done() {
//Close new tab
Browser.closeTab(new_tab_01);
Browser.closeTab(new_tab_02);