Bug 1067145 - Make responsive design e10s-ready. r=ochameau

This commit is contained in:
Paul Rouget 2015-01-07 22:47:00 -05:00
Родитель 04ab8bfb89
Коммит 6ccd40c82a
16 изменённых файлов: 598 добавлений и 605 удалений

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

@ -117,7 +117,7 @@ function checkDebuggerPort() {
function initResponsiveDesign() {
Cu.import('resource:///modules/devtools/responsivedesign.jsm');
ResponsiveUIManager.on('on', function(event, {tab:tab}) {
let responsive = tab.__responsiveUI;
let responsive = ResponsiveUIManager.getResponsiveUIForTab(tab);
let document = tab.ownerDocument;
// Only tweak reponsive mode for shell.html tabs.
@ -137,7 +137,7 @@ function initResponsiveDesign() {
}, true);
// Enable touch events
browserWindow.gBrowser.selectedTab.__responsiveUI.enableTouch();
responsive.enableTouch();
});
// Automatically toggle responsive design mode

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

@ -148,7 +148,8 @@ window.addEventListener('ContentStart', function() {
let chromewidth = window.outerWidth - window.innerWidth;
let chromeheight = window.outerHeight - window.innerHeight + controlsHeight;
if (isMulet) {
let responsive = browserWindow.gBrowser.selectedTab.__responsiveUI;
let tab = browserWindow.gBrowser.selectedTab;
let responsive = ResponsiveUIManager.getResponsiveUIForTab(tab);
responsive.setSize((Math.round(width * scale) + 16*2),
(Math.round(height * scale) + controlsHeight + 61));
} else {

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

@ -4,7 +4,8 @@
EXTRA_JS_MODULES.devtools += [
'resize-commands.js',
'responsivedesign.jsm',
'responsivedesign-child.js',
'responsivedesign.jsm'
]
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']

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

@ -0,0 +1,130 @@
/* 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/. */
const Ci = Components.interfaces;
const gDeviceSizeWasPageSize = docShell.deviceSizeIsPageSize;
const gFloatingScrollbarsStylesheet = Services.io.newURI("chrome://browser/skin/devtools/floating-scrollbars.css", null, null);
let gRequiresFloatingScrollbars;
let active = false;
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
addMessageListener("ResponsiveMode:Start", startResponsiveMode);
addMessageListener("ResponsiveMode:Stop", stopResponsiveMode);
function startResponsiveMode({data:data}) {
if (active) {
return;
}
addMessageListener("ResponsiveMode:RequestScreenshot", screenshot);
addMessageListener("ResponsiveMode:NotifyOnResize", notifiyOnResize);
webProgress.addProgressListener(WebProgressListener, Ci.nsIWebProgress.NOTIFY_ALL);
docShell.deviceSizeIsPageSize = true;
gRequiresFloatingScrollbars = data.requiresFloatingScrollbars;
// At this point, a content viewer might not be loaded for this
// docshell. makeScrollbarsFloating will be triggered by onLocationChange.
if (docShell.contentViewer) {
makeScrollbarsFloating();
}
active = true;
sendAsyncMessage("ResponsiveMode:Start:Done");
}
function notifiyOnResize() {
content.addEventListener("resize", () => {
sendAsyncMessage("ResponsiveMode:OnContentResize");
}, false);
sendAsyncMessage("ResponsiveMode:NotifyOnResize:Done");
}
function stopResponsiveMode() {
if (!active) {
return;
}
active = false;
removeMessageListener("ResponsiveMode:RequestScreenshot", screenshot);
removeMessageListener("ResponsiveMode:NotifyOnResize", notifiyOnResize);
webProgress.removeProgressListener(WebProgressListener);
docShell.deviceSizeIsPageSize = gDeviceSizeWasPageSize;
restoreScrollbars();
sendAsyncMessage("ResponsiveMode:Stop:Done");
}
function makeScrollbarsFloating() {
if (!gRequiresFloatingScrollbars) {
return;
}
let allDocShells = [docShell];
for (let i = 0; i < docShell.childCount; i++) {
let child = docShell.getChildAt(i).QueryInterface(Ci.nsIDocShell);
allDocShells.push(child);
}
for (let d of allDocShells) {
let win = d.contentViewer.DOMDocument.defaultView;
let winUtils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
try {
winUtils.loadSheet(gFloatingScrollbarsStylesheet, win.AGENT_SHEET);
} catch(e) { }
}
flushStyle();
}
function restoreScrollbars() {
let allDocShells = [docShell];
for (let i = 0; i < docShell.childCount; i++) {
allDocShells.push(docShell.getChildAt(i).QueryInterface(Ci.nsIDocShell));
}
for (let d of allDocShells) {
let win = d.contentViewer.DOMDocument.defaultView;
let winUtils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
try {
winUtils.removeSheet(gFloatingScrollbarsStylesheet, win.AGENT_SHEET);
} catch(e) { }
}
flushStyle();
}
function flushStyle() {
// Force presContext destruction
let isSticky = docShell.contentViewer.sticky;
docShell.contentViewer.sticky = false;
docShell.contentViewer.hide();
docShell.contentViewer.show();
docShell.contentViewer.sticky = isSticky;
}
function screenshot() {
let canvas = content.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
let width = content.innerWidth;
let height = content.innerHeight;
canvas.mozOpaque = true;
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext("2d");
ctx.drawWindow(content, content.scrollX, content.scrollY, width, height, "#fff");
sendAsyncMessage("ResponsiveMode:RequestScreenshot:Done", canvas.toDataURL());
}
let WebProgressListener = {
onLocationChange: function onLocationChange(aWebProgress) {
makeScrollbarsFloating();
},
QueryInterface: function QueryInterface(aIID) {
if (aIID.equals(Ci.nsIWebProgressListener) ||
aIID.equals(Ci.nsISupportsWeakReference) ||
aIID.equals(Ci.nsISupports)) {
return this;
}
throw Components.results.NS_ERROR_NO_INTERFACE;
}
};
sendAsyncMessage("ResponsiveMode:ChildScriptReady");

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

@ -10,8 +10,8 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/devtools/gDevTools.jsm");
Cu.import("resource:///modules/devtools/FloatingScrollbars.jsm");
Cu.import("resource://gre/modules/devtools/event-emitter.js");
let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
"resource://gre/modules/SystemAppProxy.jsm");
@ -33,6 +33,8 @@ const ROUND_RATIO = 10;
const INPUT_PARSER = /(\d+)[^\d]+(\d+)/;
let ActiveTabs = new Map();
this.ResponsiveUIManager = {
/**
* Check if the a tab is in a responsive mode.
@ -43,8 +45,8 @@ this.ResponsiveUIManager = {
* @param aTab the tab targeted.
*/
toggle: function(aWindow, aTab) {
if (aTab.__responsiveUI) {
aTab.__responsiveUI.close();
if (this.isActiveForTab(aTab)) {
ActiveTabs.get(aTab).close();
} else {
new ResponsiveUI(aWindow, aTab);
}
@ -56,7 +58,14 @@ this.ResponsiveUIManager = {
* @param aTab the tab targeted.
*/
isActiveForTab: function(aTab) {
return !!aTab.__responsiveUI;
return ActiveTabs.has(aTab);
},
/**
* Return the responsive UI controller for a tab.
*/
getResponsiveUIForTab: function(aTab) {
return ActiveTabs.get(aTab);
},
/**
@ -70,19 +79,19 @@ this.ResponsiveUIManager = {
handleGcliCommand: function(aWindow, aTab, aCommand, aArgs) {
switch (aCommand) {
case "resize to":
if (!aTab.__responsiveUI) {
if (!this.isActiveForTab(aTab)) {
new ResponsiveUI(aWindow, aTab);
}
aTab.__responsiveUI.setSize(aArgs.width, aArgs.height);
ActiveTabs.get(aTab).setSize(aArgs.width, aArgs.height);
break;
case "resize on":
if (!aTab.__responsiveUI) {
if (!this.isActiveForTab(aTab)) {
new ResponsiveUI(aWindow, aTab);
}
break;
case "resize off":
if (aTab.__responsiveUI) {
aTab.__responsiveUI.close();
if (this.isActiveForTab(aTab)) {
ActiveTabs.get(aTab).close();
}
break;
case "resize toggle":
@ -115,13 +124,28 @@ function ResponsiveUI(aWindow, aTab)
{
this.mainWindow = aWindow;
this.tab = aTab;
this.mm = this.tab.linkedBrowser.messageManager;
this.tabContainer = aWindow.gBrowser.tabContainer;
this.browser = aTab.linkedBrowser;
this.chromeDoc = aWindow.document;
this.container = aWindow.gBrowser.getBrowserContainer(this.browser);
this.stack = this.container.querySelector(".browserStack");
this._telemetry = new Telemetry();
this._floatingScrollbars = !this.mainWindow.matchMedia("(-moz-overlay-scrollbars)").matches;
this.e10s = !this.browser.contentWindow;
let childOn = () => {
this.mm.removeMessageListener("ResponsiveMode:Start:Done", childOn);
ResponsiveUIManager.emit("on", { tab: this.tab });
}
this.mm.addMessageListener("ResponsiveMode:Start:Done", childOn);
let requiresFloatingScrollbars = !this.mainWindow.matchMedia("(-moz-overlay-scrollbars)").matches;
this.mm.loadFrameScript("resource:///modules/devtools/responsivedesign-child.js", true);
this.mm.addMessageListener("ResponsiveMode:ChildScriptReady", () => {
this.mm.sendAsyncMessage("ResponsiveMode:Start", {
requiresFloatingScrollbars: requiresFloatingScrollbars
});
});
// Try to load presets from prefs
if (Services.prefs.prefHasUserValue("devtools.responsiveUI.presets")) {
@ -163,8 +187,6 @@ function ResponsiveUI(aWindow, aTab)
this.stack.setAttribute("responsivemode", "true");
// Let's bind some callbacks.
this.bound_onPageLoad = this.onPageLoad.bind(this);
this.bound_onPageUnload = this.onPageUnload.bind(this);
this.bound_presetSelected = this.presetSelected.bind(this);
this.bound_handleManualInput = this.handleManualInput.bind(this);
this.bound_addPreset = this.addPreset.bind(this);
@ -184,41 +206,22 @@ function ResponsiveUI(aWindow, aTab)
this.buildUI();
this.checkMenus();
this.docShell = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
this._deviceSizeWasPageSize = this.docShell.deviceSizeIsPageSize;
this.docShell.deviceSizeIsPageSize = true;
try {
if (Services.prefs.getBoolPref("devtools.responsiveUI.rotate")) {
this.rotate();
}
} catch(e) {}
if (this._floatingScrollbars)
switchToFloatingScrollbars(this.tab);
this.tab.__responsiveUI = this;
ActiveTabs.set(aTab, this);
this._telemetry.toolOpened("responsive");
// Touch events support
this.touchEnableBefore = false;
this.touchEventHandler = new TouchEventHandler(this.browser);
this.browser.addEventListener("load", this.bound_onPageLoad, true);
this.browser.addEventListener("unload", this.bound_onPageUnload, true);
if (this.browser.contentWindow.document &&
this.browser.contentWindow.document.readyState == "complete") {
this.onPageLoad();
if (!this.e10s) {
// Touch events support
this.touchEnableBefore = false;
this.touchEventHandler = new TouchEventHandler(this.browser);
}
// E10S: We should be using target here. See bug 1028234
ResponsiveUIManager.emit("on", { tab: this.tab });
// Hook to display promotional Developer Edition doorhanger. Only displayed once.
showDoorhanger({
window: this.mainWindow,
@ -239,45 +242,14 @@ ResponsiveUI.prototype = {
}
},
/**
* Window onload / onunload
*/
onPageLoad: function() {
this.touchEventHandler = new TouchEventHandler(this.browser);
if (this.touchEnableBefore) {
this.enableTouch();
}
},
onPageUnload: function(evt) {
// Ignore sub frames unload events
if (evt.target != this.browser.contentDocument)
return;
if (this.closing)
return;
if (this.touchEventHandler) {
this.touchEnableBefore = this.touchEventHandler.enabled;
this.disableTouch();
delete this.touchEventHandler;
}
},
/**
* Destroy the nodes. Remove listeners. Reset the style.
*/
close: function RUI_unload() {
close: function RUI_close() {
if (this.closing)
return;
this.closing = true;
this.docShell.deviceSizeIsPageSize = this._deviceSizeWasPageSize;
this.browser.removeEventListener("load", this.bound_onPageLoad, true);
this.browser.removeEventListener("unload", this.bound_onPageUnload, true);
if (this._floatingScrollbars)
switchToNativeScrollbars(this.tab);
this.unCheckMenus();
// Reset style of the stack.
let style = "max-width: none;" +
@ -296,10 +268,12 @@ ResponsiveUI.prototype = {
this.tabContainer.removeEventListener("TabSelect", this);
this.rotatebutton.removeEventListener("command", this.bound_rotate, true);
this.screenshotbutton.removeEventListener("command", this.bound_screenshot, true);
this.touchbutton.removeEventListener("command", this.bound_touch, true);
this.closebutton.removeEventListener("command", this.bound_close, true);
this.addbutton.removeEventListener("command", this.bound_addPreset, true);
this.removebutton.removeEventListener("command", this.bound_removePreset, true);
if (!this.e10s) {
this.touchbutton.removeEventListener("command", this.bound_touch, true);
}
// Removed elements.
this.container.removeChild(this.toolbar);
@ -317,13 +291,40 @@ ResponsiveUI.prototype = {
this.container.removeAttribute("responsivemode");
this.stack.removeAttribute("responsivemode");
delete this.docShell;
delete this.tab.__responsiveUI;
if (this.touchEventHandler)
ActiveTabs.delete(this.tab);
if (!this.e10s && this.touchEventHandler) {
this.touchEventHandler.stop();
}
this._telemetry.toolClosed("responsive");
// E10S: We should be using target here. See bug 1028234
ResponsiveUIManager.emit("off", { tab: this.tab });
let childOff = () => {
this.mm.removeMessageListener("ResponsiveMode:Stop:Done", childOff);
ResponsiveUIManager.emit("off", { tab: this.tab });
}
this.mm.addMessageListener("ResponsiveMode:Stop:Done", childOff);
this.tab.linkedBrowser.messageManager.sendAsyncMessage("ResponsiveMode:Stop");
},
/**
* Notify when the content has been resized. Only used in tests.
*/
_test_notifyOnResize: function() {
let deferred = promise.defer();
let mm = this.mm;
this.bound_onContentResize = this.onContentResize.bind(this);
mm.addMessageListener("ResponsiveMode:OnContentResize", this.bound_onContentResize);
mm.sendAsyncMessage("ResponsiveMode:NotifyOnResize");
mm.addMessageListener("ResponsiveMode:NotifyOnResize:Done", function onListeningResize() {
mm.removeMessageListener("ResponsiveMode:NotifyOnResize:Done", onListeningResize);
deferred.resolve();
});
return deferred.promise;
},
onContentResize: function() {
ResponsiveUIManager.emit("contentResize", { tab: this.tab });
},
/**
@ -427,12 +428,6 @@ ResponsiveUI.prototype = {
this.screenshotbutton.className = "devtools-responsiveui-toolbarbutton devtools-responsiveui-screenshot";
this.screenshotbutton.addEventListener("command", this.bound_screenshot, true);
this.touchbutton = this.chromeDoc.createElement("toolbarbutton");
this.touchbutton.setAttribute("tabindex", "0");
this.touchbutton.setAttribute("tooltiptext", this.strings.GetStringFromName("responsiveUI.touch"));
this.touchbutton.className = "devtools-responsiveui-toolbarbutton devtools-responsiveui-touch";
this.touchbutton.addEventListener("command", this.bound_touch, true);
this.closebutton = this.chromeDoc.createElement("toolbarbutton");
this.closebutton.setAttribute("tabindex", "0");
this.closebutton.className = "devtools-responsiveui-toolbarbutton devtools-responsiveui-close";
@ -442,7 +437,16 @@ ResponsiveUI.prototype = {
this.toolbar.appendChild(this.closebutton);
this.toolbar.appendChild(this.menulist);
this.toolbar.appendChild(this.rotatebutton);
this.toolbar.appendChild(this.touchbutton);
if (!this.e10s) {
this.touchbutton = this.chromeDoc.createElement("toolbarbutton");
this.touchbutton.setAttribute("tabindex", "0");
this.touchbutton.setAttribute("tooltiptext", this.strings.GetStringFromName("responsiveUI.touch"));
this.touchbutton.className = "devtools-responsiveui-toolbarbutton devtools-responsiveui-touch";
this.touchbutton.addEventListener("command", this.bound_touch, true);
this.toolbar.appendChild(this.touchbutton);
}
this.toolbar.appendChild(this.screenshotbutton);
// Resizers
@ -583,8 +587,9 @@ ResponsiveUI.prototype = {
this.selectedItem = menuitem;
}
if (preset.custom)
if (preset.custom) {
this.customMenuitem = menuitem;
}
this.setMenuLabel(menuitem, preset);
fragment.appendChild(menuitem);
@ -662,9 +667,7 @@ ResponsiveUI.prototype = {
if (!promptOk) {
// Prompt has been cancelled
let menuitem = this.customMenuitem;
this.menulist.selectedItem = menuitem;
this.currentPresetKey = this.customPreset.key;
this.menulist.selectedItem = this.selectedItem;
return;
}
@ -762,21 +765,7 @@ ResponsiveUI.prototype = {
* @param aFileName name of the screenshot file (used for tests).
*/
screenshot: function RUI_screenshot(aFileName) {
let window = this.browser.contentWindow;
let document = window.document;
let canvas = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
let width = window.innerWidth;
let height = window.innerHeight;
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext("2d");
ctx.drawWindow(window, window.scrollX, window.scrollY, width, height, "#fff");
let filename = aFileName;
if (!filename) {
let date = new Date();
let month = ("0" + (date.getMonth() + 1)).substr(-2, 2);
@ -785,12 +774,15 @@ ResponsiveUI.prototype = {
let timeString = date.toTimeString().replace(/:/g, ".").split(" ")[0];
filename = this.strings.formatStringFromName("responsiveUI.screenshotGeneratedFilename", [dateString, timeString], 2);
}
canvas.toBlob(blob => {
let chromeWindow = this.chromeDoc.defaultView;
let url = chromeWindow.URL.createObjectURL(blob);
chromeWindow.saveURL(url, filename + ".png", null, true, true, document.documentURIObject, document);
});
let mm = this.tab.linkedBrowser.messageManager;
let chromeWindow = this.chromeDoc.defaultView;
let doc = chromeWindow.document;
function onScreenshot(aMessage) {
mm.removeMessageListener("ResponsiveMode:RequestScreenshot:Done", onScreenshot);
chromeWindow.saveURL(aMessage.data, filename + ".png", null, true, true, doc.documentURIObject, doc);
}
mm.addMessageListener("ResponsiveMode:RequestScreenshot:Done", onScreenshot);
mm.sendAsyncMessage("ResponsiveMode:RequestScreenshot");
},
/**

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

@ -1,5 +1,4 @@
[DEFAULT]
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
subsuite = devtools
support-files =
head.js
@ -7,8 +6,11 @@ support-files =
[browser_responsive_cmd.js]
[browser_responsivecomputedview.js]
skip-if = e10s # Bug ??????
[browser_responsiveruleview.js]
skip-if = e10s # Bug ??????
[browser_responsiveui.js]
[browser_responsiveui_touch.js]
skip-if = e10s # Bug ?????? - [e10s] re-introduce touch feature in responsive mode
[browser_responsiveuiaddcustompreset.js]
[browser_responsive_devicewidth.js]

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

@ -10,10 +10,11 @@ thisTestLeaksUncaughtRejectionsAndShouldBeFixed("destroy");
function test() {
function isOpen() {
return !!gBrowser.selectedTab.__responsiveUI;
return gBrowser.getBrowserContainer(gBrowser.selectedTab.linkedBrowser)
.hasAttribute("responsivemode");
}
helpers.addTabWithToolbar("about:blank", function(options) {
helpers.addTabWithToolbar("data:text/html;charset=utf-8,hi", function(options) {
return helpers.audit(options, [
{
setup: "resize toggle",

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

@ -7,21 +7,19 @@ function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedTab = gBrowser.addTab("about:logo");
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
waitForFocus(startTest, content);
startTest();
}, true);
content.location = "data:text/html,mop";
function startTest() {
mgr.once("on", function() {executeSoon(onUIOpen)});
document.getElementById("Tools:ResponsiveUI").doCommand();
}
function onUIOpen() {
instance = gBrowser.selectedTab.__responsiveUI;
instance = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
instance.stack.setAttribute("notransition", "true");
ok(instance, "instance of the module is attached to the tab.");

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

@ -8,11 +8,12 @@ function test() {
let inspector;
waitForExplicitFinish();
let mgr = ResponsiveUI.ResponsiveUIManager;
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
waitForFocus(startTest, content);
startTest();
}, true);
content.location = "data:text/html;charset=utf-8,<html><style>" +
@ -43,7 +44,7 @@ function test() {
}
function onUIOpen() {
instance = gBrowser.selectedTab.__responsiveUI;
instance = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
ok(instance, "instance of the module is attached to the tab.");
instance.stack.setAttribute("notransition", "true");

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

@ -11,10 +11,7 @@ function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
waitForFocus(startTest, content);
}, true);
gBrowser.selectedBrowser.addEventListener("load", startTest, true);
content.location = "data:text/html;charset=utf-8,<html><style>" +
"div {" +
@ -34,12 +31,13 @@ function test() {
}
function startTest() {
gBrowser.selectedBrowser.removeEventListener("load", startTest, true);
document.getElementById("Tools:ResponsiveUI").doCommand();
executeSoon(onUIOpen);
}
function onUIOpen() {
instance = gBrowser.selectedTab.__responsiveUI;
instance = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
ok(instance, "instance of the module is attached to the tab.");
instance.stack.setAttribute("notransition", "true");

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

@ -2,26 +2,33 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let instance, widthBeforeClose, heightBeforeClose;
let mgr = ResponsiveUI.ResponsiveUIManager;
waitForExplicitFinish();
SimpleTest.requestCompleteLog();
Task.spawn(function() {
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
waitForFocus(startTest, content);
}, true);
function extractSizeFromString(str) {
let numbers = str.match(/(\d+)[^\d]*(\d+)/);
if (numbers) {
return [numbers[1], numbers[2]];
} else {
return [null, null];
}
}
content.location = "data:text/html,mop";
function processStringAsKey(str) {
for (let i = 0, l = str.length; i < l; i++) {
EventUtils.synthesizeKey(str.charAt(i), {});
}
}
yield addTab("data:text/html,mop");
let mgr = ResponsiveUI.ResponsiveUIManager;
function startTest() {
document.getElementById("Tools:ResponsiveUI").removeAttribute("disabled");
mgr.once("on", function() {executeSoon(onUIOpen)});
synthesizeKeyFromKeyTag("key_responsiveUI");
}
function onUIOpen() {
yield once(mgr, "on");
// Is it open?
let container = gBrowser.getBrowserContainer();
is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
@ -29,75 +36,58 @@ function test() {
// Menus are correctly updated?
is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"), "true", "menus checked");
instance = gBrowser.selectedTab.__responsiveUI;
let instance = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
ok(instance, "instance of the module is attached to the tab.");
if (instance._floatingScrollbars) {
ensureScrollbarsAreFloating();
}
let originalWidth = content.innerWidth;
content.location = "data:text/html;charset=utf-8,mop<div style%3D'height%3A5000px'><%2Fdiv>";
let newWidth = content.innerWidth;
is(originalWidth, newWidth, "Floating scrollbars are presents");
yield instance._test_notifyOnResize();
yield nextTick();
instance.transitionsEnabled = false;
testPresets();
}
function ensureScrollbarsAreFloating() {
let body = gBrowser.contentDocument.body;
let html = gBrowser.contentDocument.documentElement;
let originalWidth = body.getBoundingClientRect().width;
html.style.overflowY = "scroll"; // Force scrollbars
// Flush. Should not be needed as getBoundingClientRect() should flush,
// but just in case.
gBrowser.contentWindow.getComputedStyle(html).overflowY;
let newWidth = body.getBoundingClientRect().width;
is(originalWidth, newWidth, "Floating scrollbars are presents");
}
function testPresets() {
function testOnePreset(c) {
if (c == 0) {
executeSoon(testCustom);
return;
}
instance.menulist.selectedIndex = c;
// Starting from length - 4 because last 3 items are not presets : separator, addbutton and removebutton
for (let c = instance.menulist.firstChild.childNodes.length - 4; c >= 0; c--) {
let item = instance.menulist.firstChild.childNodes[c];
let [width, height] = extractSizeFromString(item.getAttribute("label"));
let onContentResize = once(mgr, "contentResize");
instance.menulist.selectedIndex = c;
yield onContentResize;
is(content.innerWidth, width, "preset " + c + ": dimension valid (width)");
is(content.innerHeight, height, "preset " + c + ": dimension valid (height)");
testOnePreset(c - 1);
}
// Starting from length - 4 because last 3 items are not presets : separator, addbutton and removebutton
testOnePreset(instance.menulist.firstChild.childNodes.length - 4);
}
function extractSizeFromString(str) {
let numbers = str.match(/(\d+)[^\d]*(\d+)/);
if (numbers) {
return [numbers[1], numbers[2]];
} else {
return [null, null];
}
}
// test custom
instance.setSize(100, 100);
yield once(mgr, "contentResize");
function testCustom() {
let initialWidth = content.innerWidth;
let initialHeight = content.innerHeight;
is(initialWidth, 100, "Width reset to 100");
is(initialHeight, 100, "Height reset to 100");
let x = 2, y = 2;
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mousedown"}, window);
x += 20; y += 10;
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mousemove"}, window);
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mouseup"}, window);
yield once(mgr, "contentResize");
let expectedWidth = initialWidth + 20;
let expectedHeight = initialHeight + 10;
info("initial width: " + initialWidth);
info("initial height: " + initialHeight);
is(content.innerWidth, expectedWidth, "Size correcty updated (width).");
is(content.innerHeight, expectedHeight, "Size correcty updated (height).");
is(content.innerWidth, expectedWidth, "Size correctly updated (width).");
is(content.innerHeight, expectedHeight, "Size correctly updated (height).");
is(instance.menulist.selectedIndex, -1, "Custom menuitem cannot be selected");
let label = instance.menulist.firstChild.firstChild.getAttribute("label");
let value = instance.menulist.value;
@ -108,71 +98,80 @@ function test() {
[width, height] = extractSizeFromString(value);
is(width, expectedWidth, "Value updated (width).");
is(height, expectedHeight, "Value updated (height).");
testCustom2();
}
function testCustom2() {
let initialWidth = content.innerWidth;
let initialHeight = content.innerHeight;
// With "shift" key pressed
let x = 2, y = 2;
instance.setSize(100, 100);
yield once(mgr, "contentResize");
initialWidth = content.innerWidth;
initialHeight = content.innerHeight;
x = 2; y = 2;
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mousedown"}, window);
x += 23; y += 13;
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mousemove", shiftKey: true}, window);
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mouseup"}, window);
let expectedWidth = initialWidth + 20;
let expectedHeight = initialHeight + 10;
is(content.innerWidth, expectedWidth, "with shift: Size correcty updated (width).");
is(content.innerHeight, expectedHeight, "with shift: Size correcty updated (height).");
yield once(mgr, "contentResize");
expectedWidth = initialWidth + 20;
expectedHeight = initialHeight + 10;
is(content.innerWidth, expectedWidth, "with shift: Size correctly updated (width).");
is(content.innerHeight, expectedHeight, "with shift: Size correctly updated (height).");
is(instance.menulist.selectedIndex, -1, "with shift: Custom menuitem cannot be selected");
let label = instance.menulist.firstChild.firstChild.getAttribute("label");
let value = instance.menulist.value;
isnot(label, value, "Label from the menulist item is different than the value of the menulist")
let [width, height] = extractSizeFromString(label);
label = instance.menulist.firstChild.firstChild.getAttribute("label");
value = instance.menulist.value;
isnot(label, value, "Label from the menulist item is different than the value of the menulist");
[width, height] = extractSizeFromString(label);
is(width, expectedWidth, "Label updated (width).");
is(height, expectedHeight, "Label updated (height).");
[width, height] = extractSizeFromString(value);
is(width, expectedWidth, "Value updated (width).");
is(height, expectedHeight, "Value updated (height).");
testCustom3();
}
function testCustom3() {
let initialWidth = content.innerWidth;
let initialHeight = content.innerHeight;
let x = 2, y = 2;
// With "ctrl" key pressed
instance.setSize(100, 100);
yield once(mgr, "contentResize");
initialWidth = content.innerWidth;
initialHeight = content.innerHeight;
x = 2; y = 2;
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mousedown"}, window);
x += 60; y += 30;
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mousemove", ctrlKey: true}, window);
EventUtils.synthesizeMouse(instance.resizer, x, y, {type: "mouseup"}, window);
let expectedWidth = initialWidth + 10;
let expectedHeight = initialHeight + 5;
is(content.innerWidth, expectedWidth, "with ctrl: Size correcty updated (width).");
is(content.innerHeight, expectedHeight, "with ctrl: Size correcty updated (height).");
yield once(mgr, "contentResize");
expectedWidth = initialWidth + 10;
expectedHeight = initialHeight + 5;
is(content.innerWidth, expectedWidth, "with ctrl: Size correctly updated (width).");
is(content.innerHeight, expectedHeight, "with ctrl: Size correctly updated (height).");
is(instance.menulist.selectedIndex, -1, "with ctrl: Custom menuitem cannot be selected");
let label = instance.menulist.firstChild.firstChild.getAttribute("label");
let value = instance.menulist.value;
isnot(label, value, "Label from the menulist item is different than the value of the menulist")
let [width, height] = extractSizeFromString(label);
label = instance.menulist.firstChild.firstChild.getAttribute("label");
value = instance.menulist.value;
isnot(label, value, "Label from the menulist item is different than the value of the menulist");
[width, height] = extractSizeFromString(label);
is(width, expectedWidth, "Label updated (width).");
is(height, expectedHeight, "Label updated (height).");
[width, height] = extractSizeFromString(value);
is(width, expectedWidth, "Value updated (width).");
is(height, expectedHeight, "Value updated (height).");
testCustomInput();
}
function testCustomInput() {
let initialWidth = content.innerWidth;
let initialHeight = content.innerHeight;
let expectedWidth = initialWidth - 20;
let expectedHeight = initialHeight - 10;
// Test custom input
initialWidth = content.innerWidth;
initialHeight = content.innerHeight;
expectedWidth = initialWidth - 20;
expectedHeight = initialHeight - 10;
let index = instance.menulist.selectedIndex;
let label, value, width, height;
let userInput = expectedWidth + " x " + expectedHeight;
@ -187,6 +186,8 @@ function test() {
// Only the `change` event must change the size
EventUtils.synthesizeKey("VK_RETURN", {});
yield once(mgr, "contentResize");
is(content.innerWidth, expectedWidth, "Size correctly updated (width).");
is(content.innerHeight, expectedHeight, "Size correctly updated (height).");
is(instance.menulist.selectedIndex, -1, "Custom menuitem cannot be selected");
@ -200,17 +201,17 @@ function test() {
is(width, expectedWidth, "Value updated (width).");
is(height, expectedHeight, "Value updated (height).");
testCustomInput2();
}
function testCustomInput2() {
let initialWidth = content.innerWidth;
let initialHeight = content.innerHeight;
let index = instance.menulist.selectedIndex;
// Invalid input
initialWidth = content.innerWidth;
initialHeight = content.innerHeight;
index = instance.menulist.selectedIndex;
let expectedValue = initialWidth + "x" + initialHeight;
let expectedLabel = instance.menulist.firstChild.firstChild.getAttribute("label");
let userInput = "I'm wrong";
userInput = "I'm wrong";
instance.menulist.inputField.value = "";
instance.menulist.focus();
@ -221,93 +222,75 @@ function test() {
is(content.innerHeight, initialHeight, "Size hasn't changed (height).");
is(instance.menulist.selectedIndex, index, "Selected item hasn't changed.");
is(instance.menulist.value, expectedValue, "Value has been reset")
let label = instance.menulist.firstChild.firstChild.getAttribute("label");
label = instance.menulist.firstChild.firstChild.getAttribute("label");
is(label, expectedLabel, "Custom menuitem's label hasn't changed");
rotate();
}
function rotate() {
let initialWidth = content.innerWidth;
let initialHeight = content.innerHeight;
// Rotate
initialWidth = content.innerWidth;
initialHeight = content.innerHeight;
info("rotate");
instance.rotate();
yield once(mgr, "contentResize");
is(content.innerWidth, initialHeight, "The width is now the height.");
is(content.innerHeight, initialWidth, "The height is now the width.");
let [width, height] = extractSizeFromString(instance.menulist.firstChild.firstChild.getAttribute("label"));
[width, height] = extractSizeFromString(instance.menulist.firstChild.firstChild.getAttribute("label"));
is(width, initialHeight, "Label updated (width).");
is(height, initialWidth, "Label updated (height).");
widthBeforeClose = content.innerWidth;
heightBeforeClose = content.innerHeight;
let widthBeforeClose = content.innerWidth;
let heightBeforeClose = content.innerHeight;
info("XXX BUG 851296: instance.closing: " + !!instance.closing);
// Restart
mgr.once("off", function() {
info("XXX BUG 851296: 'off' received.");
executeSoon(restart);
});
mgr.toggle(window, gBrowser.selectedTab);
}
function restart() {
info("XXX BUG 851296: restarting.");
info("XXX BUG 851296: __responsiveUI: " + gBrowser.selectedTab.__responsiveUI);
mgr.once("on", function() {
info("XXX BUG 851296: 'on' received.");
executeSoon(onUIOpen2);
});
//XXX BUG 851296: synthesizeKeyFromKeyTag("key_responsiveUI");
yield once(mgr, "off");
mgr.toggle(window, gBrowser.selectedTab);
info("XXX BUG 851296: restart() finished.");
}
function onUIOpen2() {
info("XXX BUG 851296: onUIOpen2.");
let container = gBrowser.getBrowserContainer();
yield once(mgr, "on");
container = gBrowser.getBrowserContainer();
is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
// Menus are correctly updated?
is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"), "true", "menus checked");
is(content.innerWidth, widthBeforeClose, "width restored.");
is(content.innerHeight, heightBeforeClose, "height restored.");
mgr.once("off", function() {executeSoon(testScreenshot)});
mgr.toggle(window, gBrowser.selectedTab);
}
// Screenshot
function testScreenshot() {
let isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
if (isWinXP) {
// We have issues testing this on Windows XP.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=848760#c17
return finishUp();
}
if (!isWinXP) {
info("screenshot");
instance.screenshot("responsiveui");
let FileUtils = (Cu.import("resource://gre/modules/FileUtils.jsm", {})).FileUtils;
info("screenshot");
instance.screenshot("responsiveui");
let FileUtils = (Cu.import("resource://gre/modules/FileUtils.jsm", {})).FileUtils;
// while(1) until we find the file.
// no need for a timeout, the test will get killed anyway.
info("checking if file exists in 200ms");
function checkIfFileExist() {
let file = FileUtils.getFile("DfltDwnld", [ "responsiveui.png" ]);
if (file.exists()) {
ok(true, "Screenshot file exists");
file.remove(false);
finishUp();
} else {
setTimeout(checkIfFileExist, 200);
while(true) {
// while(true) until we find the file.
// no need for a timeout, the test will get killed anyway.
let file = FileUtils.getFile("DfltDwnld", [ "responsiveui.png" ]);
if (file.exists()) {
ok(true, "Screenshot file exists");
file.remove(false);
break;
}
info("checking if file exists in 200ms");
yield wait(200);
}
}
checkIfFileExist();
}
function finishUp() {
mgr.toggle(window, gBrowser.selectedTab);
yield once(mgr, "off");
// Menus are correctly updated?
is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"), "false", "menu unchecked");
@ -315,39 +298,6 @@ function test() {
delete instance;
gBrowser.removeCurrentTab();
finish();
}
function synthesizeKeyFromKeyTag(aKeyId) {
let key = document.getElementById(aKeyId);
isnot(key, null, "Successfully retrieved the <key> node");
let modifiersAttr = key.getAttribute("modifiers");
let name = null;
if (key.getAttribute("keycode"))
name = key.getAttribute("keycode");
else if (key.getAttribute("key"))
name = key.getAttribute("key");
isnot(name, null, "Successfully retrieved keycode/key");
let modifiers = {
shiftKey: modifiersAttr.match("shift"),
ctrlKey: modifiersAttr.match("ctrl"),
altKey: modifiersAttr.match("alt"),
metaKey: modifiersAttr.match("meta"),
accelKey: modifiersAttr.match("accel")
}
info("XXX BUG 851296: key name: " + name);
info("XXX BUG 851296: key modifiers: " + JSON.stringify(modifiers));
EventUtils.synthesizeKey(name, modifiers);
}
function processStringAsKey(str) {
for (let i = 0, l = str.length; i < l; i++) {
EventUtils.synthesizeKey(str.charAt(i), {});
}
}
});
}

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

@ -34,7 +34,7 @@ function test() {
}
function testWithTouch() {
gBrowser.selectedTab.__responsiveUI.enableTouch();
mgr.getResponsiveUIForTab(gBrowser.selectedTab).enableTouch();
let div = content.document.querySelector("div");
let x = 2, y = 2;
EventUtils.synthesizeMouse(div, x, y, {type: "mousedown", isSynthesized: false}, content);
@ -47,7 +47,7 @@ function test() {
}
function testWithTouchAgain() {
gBrowser.selectedTab.__responsiveUI.disableTouch();
mgr.getResponsiveUIForTab(gBrowser.selectedTab).disableTouch();
let div = content.document.querySelector("div");
let x = 2, y = 2;
EventUtils.synthesizeMouse(div, x, y, {type: "mousedown", isSynthesized: false}, content);

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

@ -2,170 +2,10 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let instance, deletedPresetA, deletedPresetB, oldPrompt;
let mgr = ResponsiveUI.ResponsiveUIManager;
waitForExplicitFinish();
SimpleTest.requestCompleteLog();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
waitForFocus(startTest, content);
}, true);
content.location = "data:text/html;charset=utf8,test custom presets in responsive mode";
// This test uses executeSoon() when responsive mode is initialized and when
// it is destroyed such that we get out of the init/destroy loops. If we try
// to init/destroy immediately, without waiting for the next loop, we get
// intermittent test failures.
function startTest() {
// Mocking prompt
oldPrompt = Services.prompt;
Services.prompt = {
value: "",
returnBool: true,
prompt: function(aParent, aDialogTitle, aText, aValue, aCheckMsg, aCheckState) {
aValue.value = this.value;
return this.returnBool;
}
};
registerCleanupFunction(() => Services.prompt = oldPrompt);
info("test started, waiting for responsive mode to activate");
document.getElementById("Tools:ResponsiveUI").removeAttribute("disabled");
mgr.once("on", onUIOpen);
synthesizeKeyFromKeyTag("key_responsiveUI");
}
function onUIOpen() {
// Is it open?
let container = gBrowser.getBrowserContainer();
is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
instance = gBrowser.selectedTab.__responsiveUI;
ok(instance, "instance of the module is attached to the tab.");
instance.transitionsEnabled = false;
testAddCustomPreset();
}
function testAddCustomPreset() {
// Tries to add a custom preset and cancel the prompt
let idx = instance.menulist.selectedIndex;
let presetCount = instance.presets.length;
Services.prompt.value = "";
Services.prompt.returnBool = false;
instance.addbutton.doCommand();
is(idx, instance.menulist.selectedIndex, "selected item didn't change after add preset and cancel");
is(presetCount, instance.presets.length, "number of presets didn't change after add preset and cancel");
let customHeight = 123, customWidth = 456;
instance.setSize(customWidth, customHeight);
// Adds the custom preset with "Testing preset"
Services.prompt.value = "Testing preset";
Services.prompt.returnBool = true;
instance.addbutton.doCommand();
instance.menulist.selectedIndex = 1;
info("waiting for responsive mode to turn off");
mgr.once("off", restart);
// Force document reflow to avoid intermittent failures.
info("document height " + document.height);
// We're still in the loop of initializing the responsive mode.
// Let's wait next loop to stop it.
executeSoon(function() {
instance.close();
});
}
function restart() {
info("Restarting Responsive Mode");
mgr.once("on", function() {
let container = gBrowser.getBrowserContainer();
is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
instance = gBrowser.selectedTab.__responsiveUI;
testCustomPresetInList();
});
// We're still in the loop of destroying the responsive mode.
// Let's wait next loop to start it.
executeSoon(function() {
synthesizeKeyFromKeyTag("key_responsiveUI");
});
}
function testCustomPresetInList() {
let customPresetIndex = getPresetIndex("456x123 (Testing preset)");
ok(customPresetIndex >= 0, "is the previously added preset (idx = " + customPresetIndex + ") in the list of items");
instance.menulist.selectedIndex = customPresetIndex;
is(content.innerWidth, 456, "add preset, and selected in the list, dimension valid (width)");
is(content.innerHeight, 123, "add preset, and selected in the list, dimension valid (height)");
testDeleteCustomPresets();
}
function testDeleteCustomPresets() {
instance.removebutton.doCommand();
instance.menulist.selectedIndex = 2;
deletedPresetA = instance.menulist.selectedItem.getAttribute("label");
instance.removebutton.doCommand();
instance.menulist.selectedIndex = 2;
deletedPresetB = instance.menulist.selectedItem.getAttribute("label");
instance.removebutton.doCommand();
info("waiting for responsive mode to turn off");
mgr.once("off", restartAgain);
// We're still in the loop of initializing the responsive mode.
// Let's wait next loop to stop it.
executeSoon(() => instance.close());
}
function restartAgain() {
info("waiting for responsive mode to turn on");
mgr.once("on", () => {
instance = gBrowser.selectedTab.__responsiveUI;
testCustomPresetsNotInListAnymore();
});
// We're still in the loop of destroying the responsive mode.
// Let's wait next loop to start it.
executeSoon(() => synthesizeKeyFromKeyTag("key_responsiveUI"));
}
function testCustomPresetsNotInListAnymore() {
let customPresetIndex = getPresetIndex(deletedPresetA);
is(customPresetIndex, -1, "deleted preset " + deletedPresetA + " is not in the list anymore");
customPresetIndex = getPresetIndex(deletedPresetB);
is(customPresetIndex, -1, "deleted preset " + deletedPresetB + " is not in the list anymore");
executeSoon(finishUp);
}
function finishUp() {
delete instance;
gBrowser.removeCurrentTab();
finish();
}
let instance, deletedPresetA, deletedPresetB, oldPrompt;
function getPresetIndex(presetLabel) {
function testOnePreset(c) {
@ -199,4 +39,121 @@ function test() {
key.doCommand();
}
Task.spawn(function() {
yield addTab("data:text/html;charset=utf8,test custom presets in responsive mode");
let mgr = ResponsiveUI.ResponsiveUIManager;
synthesizeKeyFromKeyTag("key_responsiveUI");
yield once(mgr, "on");
oldPrompt = Services.prompt;
Services.prompt = {
value: "",
returnBool: true,
prompt: function(aParent, aDialogTitle, aText, aValue, aCheckMsg, aCheckState) {
aValue.value = this.value;
return this.returnBool;
}
};
registerCleanupFunction(() => Services.prompt = oldPrompt);
// Is it open?
let container = gBrowser.getBrowserContainer();
is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
instance = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
ok(instance, "instance of the module is attached to the tab.");
instance.transitionsEnabled = false;
yield instance._test_notifyOnResize();
// Tries to add a custom preset and cancel the prompt
let idx = instance.menulist.selectedIndex;
let presetCount = instance.presets.length;
Services.prompt.value = "";
Services.prompt.returnBool = false;
instance.addbutton.doCommand();
is(idx, instance.menulist.selectedIndex, "selected item didn't change after add preset and cancel");
is(presetCount, instance.presets.length, "number of presets didn't change after add preset and cancel");
// Adds the custom preset with "Testing preset"
Services.prompt.value = "Testing preset";
Services.prompt.returnBool = true;
let customHeight = 123, customWidth = 456;
instance.startResizing({});
instance.setSize(customWidth, customHeight);
instance.stopResizing({});
instance.addbutton.doCommand();
// Force document reflow to avoid intermittent failures.
info("document height " + document.height);
instance.close();
info("waiting for responsive mode to turn off");
yield once(mgr, "off");
// We're still in the loop of initializing the responsive mode.
// Let's wait next loop to stop it.
yield nextTick();
synthesizeKeyFromKeyTag("key_responsiveUI");
yield once(mgr, "on");
is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
instance = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
let customPresetIndex = getPresetIndex("456x123 (Testing preset)");
info(customPresetIndex);
ok(customPresetIndex >= 0, "is the previously added preset (idx = " + customPresetIndex + ") in the list of items");
instance.menulist.selectedIndex = customPresetIndex;
is(content.innerWidth, 456, "add preset, and selected in the list, dimension valid (width)");
is(content.innerHeight, 123, "add preset, and selected in the list, dimension valid (height)");
instance.removebutton.doCommand();
instance.menulist.selectedIndex = 2;
deletedPresetA = instance.menulist.selectedItem.getAttribute("label");
instance.removebutton.doCommand();
instance.menulist.selectedIndex = 2;
deletedPresetB = instance.menulist.selectedItem.getAttribute("label");
instance.removebutton.doCommand();
yield nextTick();
instance.close();
yield once(mgr, "off");
synthesizeKeyFromKeyTag("key_responsiveUI");
info("waiting for responsive mode to turn on");
yield once(mgr, "on");
instance = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
customPresetIndex = getPresetIndex(deletedPresetA);
is(customPresetIndex, -1, "deleted preset " + deletedPresetA + " is not in the list anymore");
customPresetIndex = getPresetIndex(deletedPresetB);
is(customPresetIndex, -1, "deleted preset " + deletedPresetB + " is not in the list anymore");
yield nextTick();
gBrowser.removeCurrentTab();
finish();
});
}

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

@ -123,3 +123,92 @@ function openComputedView() {
function openRuleView() {
return openInspectorSideBar("ruleview");
}
/**
* Add a new test tab in the browser and load the given url.
* @param {String} url The url to be loaded in the new tab
* @return a promise that resolves to the tab object when the url is loaded
*/
let addTab = Task.async(function* (url) {
info("Adding a new tab with URL: '" + url + "'");
window.focus();
let tab = gBrowser.selectedTab = gBrowser.addTab(url);
let browser = tab.linkedBrowser;
yield once(browser, "load", true);
info("URL '" + url + "' loading complete");
return tab;
});
/**
* Wait for eventName on target.
* @param {Object} target An observable object that either supports on/off or
* addEventListener/removeEventListener
* @param {String} eventName
* @param {Boolean} useCapture Optional, for addEventListener/removeEventListener
* @return A promise that resolves when the event has been handled
*/
function once(target, eventName, useCapture=false) {
info("Waiting for event: '" + eventName + "' on " + target + ".");
let deferred = promise.defer();
for (let [add, remove] of [
["addEventListener", "removeEventListener"],
["addListener", "removeListener"],
["on", "off"]
]) {
if ((add in target) && (remove in target)) {
target[add](eventName, function onEvent(...aArgs) {
info("Got event: '" + eventName + "' on " + target + ".");
target[remove](eventName, onEvent, useCapture);
deferred.resolve.apply(deferred, aArgs);
}, useCapture);
break;
}
}
return deferred.promise;
}
function wait(ms) {
let def = promise.defer();
setTimeout(def.resolve, ms);
return def.promise;
}
function synthesizeKeyFromKeyTag(aKeyId) {
let key = document.getElementById(aKeyId);
isnot(key, null, "Successfully retrieved the <key> node");
let modifiersAttr = key.getAttribute("modifiers");
let name = null;
if (key.getAttribute("keycode"))
name = key.getAttribute("keycode");
else if (key.getAttribute("key"))
name = key.getAttribute("key");
isnot(name, null, "Successfully retrieved keycode/key");
let modifiers = {
shiftKey: modifiersAttr.match("shift"),
ctrlKey: modifiersAttr.match("ctrl"),
altKey: modifiersAttr.match("alt"),
metaKey: modifiersAttr.match("meta"),
accelKey: modifiersAttr.match("accel")
}
EventUtils.synthesizeKey(name, modifiers);
}
function nextTick() {
let def = promise.defer();
executeSoon(() => def.resolve())
return def.promise;
}

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

@ -1,126 +0,0 @@
/* 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/. */
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
this.EXPORTED_SYMBOLS = [ "switchToFloatingScrollbars", "switchToNativeScrollbars" ];
Cu.import("resource://gre/modules/Services.jsm");
let URL = Services.io.newURI("chrome://browser/skin/devtools/floating-scrollbars.css", null, null);
let trackedTabs = new WeakMap();
/**
* Switch to floating scrollbars, à la mobile.
*
* @param aTab the targeted tab.
*
*/
this.switchToFloatingScrollbars = function switchToFloatingScrollbars(aTab) {
let mgr = trackedTabs.get(aTab);
if (!mgr) {
mgr = new ScrollbarManager(aTab);
}
mgr.switchToFloating();
}
/**
* Switch to original native scrollbars.
*
* @param aTab the targeted tab.
*
*/
this.switchToNativeScrollbars = function switchToNativeScrollbars(aTab) {
let mgr = trackedTabs.get(aTab);
if (mgr) {
mgr.reset();
}
}
function ScrollbarManager(aTab) {
trackedTabs.set(aTab, this);
this.attachedTab = aTab;
this.attachedBrowser = aTab.linkedBrowser;
this.reset = this.reset.bind(this);
this.switchToFloating = this.switchToFloating.bind(this);
this.attachedTab.addEventListener("TabClose", this.reset, true);
this.attachedBrowser.addEventListener("DOMContentLoaded", this.switchToFloating, true);
}
ScrollbarManager.prototype = {
get win() {
return this.attachedBrowser.contentWindow;
},
/*
* Change the look of the scrollbars.
*/
switchToFloating: function() {
let windows = this.getInnerWindows(this.win);
windows.forEach(this.injectStyleSheet);
this.forceStyle();
},
/*
* Reset the look of the scrollbars.
*/
reset: function() {
let windows = this.getInnerWindows(this.win);
windows.forEach(this.removeStyleSheet);
this.forceStyle(this.attachedBrowser);
this.attachedBrowser.removeEventListener("DOMContentLoaded", this.switchToFloating, true);
this.attachedTab.removeEventListener("TabClose", this.reset, true);
trackedTabs.delete(this.attachedTab);
},
/*
* Toggle the display property of the window to force the style to be applied.
*/
forceStyle: function() {
let parentWindow = this.attachedBrowser.ownerDocument.defaultView;
let display = parentWindow.getComputedStyle(this.attachedBrowser).display; // Save display value
this.attachedBrowser.style.display = "none";
parentWindow.getComputedStyle(this.attachedBrowser).display; // Flush
this.attachedBrowser.style.display = display; // Restore
},
/*
* return all the window objects present in the hiearchy of a window.
*/
getInnerWindows: function(win) {
let iframes = win.document.querySelectorAll("iframe");
let innerWindows = [];
for (let iframe of iframes) {
innerWindows = innerWindows.concat(this.getInnerWindows(iframe.contentWindow));
}
return [win].concat(innerWindows);
},
/*
* Append the new scrollbar style.
*/
injectStyleSheet: function(win) {
let winUtils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
try {
winUtils.loadSheet(URL, win.AGENT_SHEET);
}catch(e) {}
},
/*
* Remove the injected stylesheet.
*/
removeStyleSheet: function(win) {
let winUtils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
try {
winUtils.removeSheet(URL, win.AGENT_SHEET);
}catch(e) {}
},
}

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

@ -12,7 +12,6 @@ EXTRA_JS_MODULES.devtools += [
'Curl.jsm',
'DeveloperToolbar.jsm',
'DOMHelpers.jsm',
'FloatingScrollbars.jsm',
'Jsbeautify.jsm',
'Parser.jsm',
'SplitView.jsm',