Bug 749628 - Implement a Responsive Design tool. r=dcamp r=gavin
@@ -1039,6 +1039,9 @@ pref("devtools.inspector.highlighterShowInfobar", true);
|
|||||||
pref("devtools.layoutview.enabled", true);
|
pref("devtools.layoutview.enabled", true);
|
||||||
pref("devtools.layoutview.open", false);
|
pref("devtools.layoutview.open", false);
|
||||||
|
|
||||||
|
// Enable the Responsive UI tool
|
||||||
|
pref("devtools.responsiveUI.enabled", true);
|
||||||
|
|
||||||
// Enable the Debugger
|
// Enable the Debugger
|
||||||
pref("devtools.debugger.enabled", true);
|
pref("devtools.debugger.enabled", true);
|
||||||
pref("devtools.debugger.remote-enabled", false);
|
pref("devtools.debugger.remote-enabled", false);
|
||||||
|
|||||||
@@ -160,6 +160,12 @@
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
command="Tools:Inspect"
|
command="Tools:Inspect"
|
||||||
key="key_inspect"/>
|
key="key_inspect"/>
|
||||||
|
<menuitem id="appmenu_responsiveUI"
|
||||||
|
hidden="true"
|
||||||
|
label="&responsiveUI.label;"
|
||||||
|
type="checkbox"
|
||||||
|
command="Tools:ResponsiveUI"
|
||||||
|
key="key_responsiveUI"/>
|
||||||
<menuitem id="appmenu_debugger"
|
<menuitem id="appmenu_debugger"
|
||||||
hidden="true"
|
hidden="true"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
|||||||
@@ -535,6 +535,13 @@
|
|||||||
accesskey="&inspectMenu.accesskey;"
|
accesskey="&inspectMenu.accesskey;"
|
||||||
key="key_inspect"
|
key="key_inspect"
|
||||||
command="Tools:Inspect"/>
|
command="Tools:Inspect"/>
|
||||||
|
<menuitem id="menu_responsiveUI"
|
||||||
|
type="checkbox"
|
||||||
|
hidden="true"
|
||||||
|
label="&responsiveUI.label;"
|
||||||
|
accesskey="&responsiveUI.accesskey;"
|
||||||
|
key="key_responsiveUI"
|
||||||
|
command="Tools:ResponsiveUI"/>
|
||||||
<menuitem id="menu_debugger"
|
<menuitem id="menu_debugger"
|
||||||
hidden="true"
|
hidden="true"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
|||||||
@@ -96,6 +96,7 @@
|
|||||||
<command id="Tools:ChromeDebugger" oncommand="DebuggerUI.toggleChromeDebugger();" disabled="true"/>
|
<command id="Tools:ChromeDebugger" oncommand="DebuggerUI.toggleChromeDebugger();" disabled="true"/>
|
||||||
<command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true"/>
|
<command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true"/>
|
||||||
<command id="Tools:StyleEditor" oncommand="StyleEditor.openChrome();" disabled="true"/>
|
<command id="Tools:StyleEditor" oncommand="StyleEditor.openChrome();" disabled="true"/>
|
||||||
|
<command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true"/>
|
||||||
<command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
|
<command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
|
||||||
<command id="Tools:Sanitize"
|
<command id="Tools:Sanitize"
|
||||||
oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
|
oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
|
||||||
@@ -250,6 +251,13 @@
|
|||||||
modifiers="accel,alt"
|
modifiers="accel,alt"
|
||||||
#else
|
#else
|
||||||
modifiers="accel,shift"
|
modifiers="accel,shift"
|
||||||
|
#endif
|
||||||
|
/>
|
||||||
|
<key id="key_responsiveUI" key="&responsiveUI.commandkey;" command="Tools:ResponsiveUI"
|
||||||
|
#ifdef XP_MACOSX
|
||||||
|
modifiers="accel,alt"
|
||||||
|
#else
|
||||||
|
modifiers="accel,shift"
|
||||||
#endif
|
#endif
|
||||||
/>
|
/>
|
||||||
<key id="key_scratchpad" keycode="&scratchpad.keycode;" modifiers="shift"
|
<key id="key_scratchpad" keycode="&scratchpad.keycode;" modifiers="shift"
|
||||||
|
|||||||
@@ -553,6 +553,8 @@ statuspanel[inactive][previoustype=overLink] {
|
|||||||
/* highlighter */
|
/* highlighter */
|
||||||
%include highlighter.css
|
%include highlighter.css
|
||||||
|
|
||||||
|
/* gcli */
|
||||||
|
|
||||||
html|*#gcli-tooltip-frame,
|
html|*#gcli-tooltip-frame,
|
||||||
html|*#gcli-output-frame,
|
html|*#gcli-output-frame,
|
||||||
#gcli-output,
|
#gcli-output,
|
||||||
@@ -565,3 +567,26 @@ html|*#gcli-output-frame,
|
|||||||
.gclitoolbar-prompt {
|
.gclitoolbar-prompt {
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Responsive Mode */
|
||||||
|
|
||||||
|
vbox[anonid=browserContainer][responsivemode] {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-toolbar:-moz-locale-dir(rtl) {
|
||||||
|
-moz-box-pack: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack[anonid=browserStack][responsivemode] {
|
||||||
|
-moz-transition-duration: 200ms;
|
||||||
|
-moz-transition-timing-function: linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack[anonid=browserStack][responsivemode] {
|
||||||
|
-moz-transition-properties: min-width, max-width, min-height, max-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack[anonid=browserStack][responsivemode][notransition] {
|
||||||
|
-moz-transition: none;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1724,6 +1724,17 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
|||||||
document.getElementById("appmenu_charsetMenu").hidden = true;
|
document.getElementById("appmenu_charsetMenu").hidden = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Enable Responsive UI?
|
||||||
|
let responsiveUIEnabled = gPrefService.getBoolPref("devtools.responsiveUI.enabled");
|
||||||
|
if (responsiveUIEnabled) {
|
||||||
|
document.getElementById("menu_responsiveUI").hidden = false;
|
||||||
|
document.getElementById("Tools:ResponsiveUI").removeAttribute("disabled");
|
||||||
|
#ifdef MENUBAR_CAN_AUTOHIDE
|
||||||
|
document.getElementById("appmenu_responsiveUI").hidden = false;
|
||||||
|
#endif
|
||||||
|
document.getElementById("developer-toolbar-responsiveui").hidden = false;
|
||||||
|
}
|
||||||
|
|
||||||
let appMenuButton = document.getElementById("appmenu-button");
|
let appMenuButton = document.getElementById("appmenu-button");
|
||||||
let appMenuPopup = document.getElementById("appmenu-popup");
|
let appMenuPopup = document.getElementById("appmenu-popup");
|
||||||
if (appMenuButton && appMenuPopup) {
|
if (appMenuButton && appMenuPopup) {
|
||||||
@@ -9302,6 +9313,18 @@ XPCOMUtils.defineLazyGetter(Scratchpad, "ScratchpadManager", function() {
|
|||||||
return tmp.ScratchpadManager;
|
return tmp.ScratchpadManager;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var ResponsiveUI = {
|
||||||
|
toggle: function RUI_toggle() {
|
||||||
|
this.ResponsiveUIManager.toggle(window, gBrowser.selectedTab);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(ResponsiveUI, "ResponsiveUIManager", function() {
|
||||||
|
let tmp = {};
|
||||||
|
Cu.import("resource:///modules/devtools/responsivedesign.jsm", tmp);
|
||||||
|
return tmp.ResponsiveUIManager;
|
||||||
|
});
|
||||||
|
|
||||||
var StyleEditor = {
|
var StyleEditor = {
|
||||||
prefEnabledName: "devtools.styleeditor.enabled",
|
prefEnabledName: "devtools.styleeditor.enabled",
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1049,6 +1049,11 @@
|
|||||||
class="devtools-toolbarbutton"
|
class="devtools-toolbarbutton"
|
||||||
hidden="true"
|
hidden="true"
|
||||||
command="Tools:Inspect"/>
|
command="Tools:Inspect"/>
|
||||||
|
<toolbarbutton id="developer-toolbar-responsiveui"
|
||||||
|
label="&responsiveUI.label;"
|
||||||
|
class="devtools-toolbarbutton"
|
||||||
|
hidden="true"
|
||||||
|
command="Tools:ResponsiveUI"/>
|
||||||
<toolbarbutton id="developer-toolbar-debugger"
|
<toolbarbutton id="developer-toolbar-debugger"
|
||||||
label="&scriptsButton.label;"
|
label="&scriptsButton.label;"
|
||||||
class="devtools-toolbarbutton"
|
class="devtools-toolbarbutton"
|
||||||
|
|||||||
@@ -26,10 +26,12 @@
|
|||||||
onselect="if (event.target.localName == 'tabpanels') this.parentNode.updateCurrentBrowser();">
|
onselect="if (event.target.localName == 'tabpanels') this.parentNode.updateCurrentBrowser();">
|
||||||
<xul:tabpanels flex="1" class="plain" selectedIndex="0" anonid="panelcontainer">
|
<xul:tabpanels flex="1" class="plain" selectedIndex="0" anonid="panelcontainer">
|
||||||
<xul:notificationbox flex="1">
|
<xul:notificationbox flex="1">
|
||||||
<xul:stack flex="1" anonid="browserStack">
|
<xul:vbox flex="1" anonid="browserContainer">
|
||||||
<xul:browser type="content-primary" message="true" disablehistory="true"
|
<xul:stack flex="1" anonid="browserStack">
|
||||||
xbl:inherits="tooltip=contenttooltip,contextmenu=contentcontextmenu,autocompletepopup"/>
|
<xul:browser type="content-primary" message="true" disablehistory="true"
|
||||||
</xul:stack>
|
xbl:inherits="tooltip=contenttooltip,contextmenu=contentcontextmenu,autocompletepopup"/>
|
||||||
|
</xul:stack>
|
||||||
|
</xul:vbox>
|
||||||
</xul:notificationbox>
|
</xul:notificationbox>
|
||||||
</xul:tabpanels>
|
</xul:tabpanels>
|
||||||
</xul:tabbox>
|
</xul:tabbox>
|
||||||
@@ -290,6 +292,15 @@
|
|||||||
</method>
|
</method>
|
||||||
|
|
||||||
<method name="getNotificationBox">
|
<method name="getNotificationBox">
|
||||||
|
<parameter name="aBrowser"/>
|
||||||
|
<body>
|
||||||
|
<![CDATA[
|
||||||
|
return this.getBrowserContainer(aBrowser).parentNode;
|
||||||
|
]]>
|
||||||
|
</body>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="getBrowserContainer">
|
||||||
<parameter name="aBrowser"/>
|
<parameter name="aBrowser"/>
|
||||||
<body>
|
<body>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
@@ -1284,12 +1295,20 @@
|
|||||||
stack.appendChild(b);
|
stack.appendChild(b);
|
||||||
stack.setAttribute("flex", "1");
|
stack.setAttribute("flex", "1");
|
||||||
|
|
||||||
|
// Create the browserContainer
|
||||||
|
var box = document.createElementNS(
|
||||||
|
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
|
||||||
|
"vbox");
|
||||||
|
box.setAttribute("anonid", "browserContainer");
|
||||||
|
box.appendChild(stack);
|
||||||
|
box.setAttribute("flex", "1");
|
||||||
|
|
||||||
// Add the Message and the Browser to the box
|
// Add the Message and the Browser to the box
|
||||||
var notificationbox = document.createElementNS(
|
var notificationbox = document.createElementNS(
|
||||||
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
|
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
|
||||||
"notificationbox");
|
"notificationbox");
|
||||||
notificationbox.setAttribute("flex", "1");
|
notificationbox.setAttribute("flex", "1");
|
||||||
notificationbox.appendChild(stack);
|
notificationbox.appendChild(box);
|
||||||
|
|
||||||
var position = this.tabs.length - 1;
|
var position = this.tabs.length - 1;
|
||||||
var uniqueId = "panel" + Date.now() + position;
|
var uniqueId = "panel" + Date.now() + position;
|
||||||
@@ -1714,12 +1733,13 @@
|
|||||||
// (see below), which would be hindered by the potentially expensive
|
// (see below), which would be hindered by the potentially expensive
|
||||||
// browser removal. So we remove the browser and the panel in two
|
// browser removal. So we remove the browser and the panel in two
|
||||||
// steps.
|
// steps.
|
||||||
var panel = browser.parentNode.parentNode;
|
|
||||||
|
var panel = this.getNotificationBox(browser);
|
||||||
|
|
||||||
// This will unload the document. An unload handler could remove
|
// This will unload the document. An unload handler could remove
|
||||||
// dependant tabs, so it's important that the tabbrowser is now in
|
// dependant tabs, so it's important that the tabbrowser is now in
|
||||||
// a consistent state (tab removed, tab positions updated, etc.).
|
// a consistent state (tab removed, tab positions updated, etc.).
|
||||||
panel.removeChild(browser.parentNode);
|
panel.removeChild(this.getBrowserContainer(browser));
|
||||||
|
|
||||||
// Release the browser in case something is erroneously holding a
|
// Release the browser in case something is erroneously holding a
|
||||||
// reference to the tab after its removal.
|
// reference to the tab after its removal.
|
||||||
@@ -2490,7 +2510,7 @@
|
|||||||
|
|
||||||
<constructor>
|
<constructor>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
this.mCurrentBrowser = this.mPanelContainer.childNodes[0].firstChild.firstChild;
|
this.mCurrentBrowser = this.mPanelContainer.firstChild.firstChild.firstChild.firstChild;
|
||||||
this.mCurrentTab = this.tabContainer.firstChild;
|
this.mCurrentTab = this.tabContainer.firstChild;
|
||||||
document.addEventListener("keypress", this, false);
|
document.addEventListener("keypress", this, false);
|
||||||
window.addEventListener("sizemodechange", this, false);
|
window.addEventListener("sizemodechange", this, false);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ var runs = [
|
|||||||
is(tabbrowser.browsers.length, 1, "Window has one browser");
|
is(tabbrowser.browsers.length, 1, "Window has one browser");
|
||||||
is(tabbrowser.selectedTab, newTab, "Remaining tab is selected");
|
is(tabbrowser.selectedTab, newTab, "Remaining tab is selected");
|
||||||
is(tabbrowser.selectedBrowser, newBrowser, "Browser for remaining tab is selected");
|
is(tabbrowser.selectedBrowser, newBrowser, "Browser for remaining tab is selected");
|
||||||
is(tabbrowser.mTabBox.selectedPanel, newBrowser.parentNode.parentNode, "Panel for remaining tab is selected");
|
is(tabbrowser.mTabBox.selectedPanel, newBrowser.parentNode.parentNode.parentNode, "Panel for remaining tab is selected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ DIRS = \
|
|||||||
debugger \
|
debugger \
|
||||||
layoutview \
|
layoutview \
|
||||||
shared \
|
shared \
|
||||||
|
responsivedesign \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
|||||||
15
browser/devtools/responsivedesign/Makefile.in
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
DEPTH = ../../..
|
||||||
|
topsrcdir = @top_srcdir@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
include $(DEPTH)/config/autoconf.mk
|
||||||
|
|
||||||
|
ifdef ENABLE_TESTS
|
||||||
|
DIRS += test
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
|
||||||
|
libs::
|
||||||
|
$(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools
|
||||||
441
browser/devtools/responsivedesign/responsivedesign.jsm
Normal file
@@ -0,0 +1,441 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is the Mozilla Responsive UI Module.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* The Mozilla Foundation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2012
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Paul Rouget <paul@mozilla.com> (original author)
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
const Ci = Components.interfaces;
|
||||||
|
const Cu = Components.utils;
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
|
var EXPORTED_SYMBOLS = ["ResponsiveUIManager"];
|
||||||
|
|
||||||
|
const MIN_WIDTH = 50;
|
||||||
|
const MIN_HEIGHT = 50;
|
||||||
|
|
||||||
|
let ResponsiveUIManager = {
|
||||||
|
/**
|
||||||
|
* Check if the a tab is in a responsive mode.
|
||||||
|
* Leave the responsive mode if active,
|
||||||
|
* active the responsive mode if not active.
|
||||||
|
*
|
||||||
|
* @param aWindow the main window.
|
||||||
|
* @param aTab the tab targeted.
|
||||||
|
*/
|
||||||
|
toggle: function(aWindow, aTab) {
|
||||||
|
if (aTab.responsiveUI) {
|
||||||
|
aTab.responsiveUI.close();
|
||||||
|
} else {
|
||||||
|
aTab.responsiveUI = new ResponsiveUI(aWindow, aTab);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
let presets = [
|
||||||
|
// Phones
|
||||||
|
{width: 320, height: 480}, // iPhone, B2G, with <meta viewport>
|
||||||
|
{width: 360, height: 640}, // Android 4, phones, with <meta viewport>
|
||||||
|
|
||||||
|
// Tablets
|
||||||
|
{width: 768, height: 1024}, // iPad, with <meta viewport>
|
||||||
|
{width: 800, height: 1280}, // Android 4, Tablet, with <meta viewport>
|
||||||
|
|
||||||
|
// Default width for mobile browsers, no <meta viewport>
|
||||||
|
{width: 980, height: 1280},
|
||||||
|
|
||||||
|
// Computer
|
||||||
|
{width: 1280, height: 600},
|
||||||
|
{width: 1920, height: 900},
|
||||||
|
];
|
||||||
|
|
||||||
|
function ResponsiveUI(aWindow, aTab)
|
||||||
|
{
|
||||||
|
this.mainWindow = aWindow;
|
||||||
|
this.tab = aTab;
|
||||||
|
this.browser = aTab.linkedBrowser;
|
||||||
|
this.chromeDoc = aWindow.document;
|
||||||
|
this.container = aWindow.gBrowser.getBrowserContainer(this.browser);
|
||||||
|
this.stack = this.container.querySelector("[anonid=browserStack]");
|
||||||
|
|
||||||
|
// Try to load presets from prefs
|
||||||
|
if (Services.prefs.prefHasUserValue("devtools.responsiveUI.presets")) {
|
||||||
|
try {
|
||||||
|
presets = JSON.parse(Services.prefs.getCharPref("devtools.responsiveUI.presets"));
|
||||||
|
} catch(e) {
|
||||||
|
// User pref is malformated.
|
||||||
|
Cu.reportError("Could not parse pref `devtools.responsiveUI.presets`: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(presets)) {
|
||||||
|
this.presets = [{custom: true}].concat(presets)
|
||||||
|
} else {
|
||||||
|
Cu.reportError("Presets value (devtools.responsiveUI.presets) is malformated.");
|
||||||
|
this.presets = [{custom: true}];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default size. The first preset (custom) is the one that will be used.
|
||||||
|
let bbox = this.stack.getBoundingClientRect();
|
||||||
|
this.presets[0].width = bbox.width - 40; // horizontal padding of the container
|
||||||
|
this.presets[0].height = bbox.height - 80; // vertical padding + toolbar height
|
||||||
|
this.currentPreset = 0; // Custom
|
||||||
|
|
||||||
|
this.container.setAttribute("responsivemode", "true");
|
||||||
|
this.stack.setAttribute("responsivemode", "true");
|
||||||
|
|
||||||
|
// Let's bind some callbacks.
|
||||||
|
this.bound_presetSelected = this.presetSelected.bind(this);
|
||||||
|
this.bound_rotate = this.rotate.bind(this);
|
||||||
|
this.bound_startResizing = this.startResizing.bind(this);
|
||||||
|
this.bound_stopResizing = this.stopResizing.bind(this);
|
||||||
|
this.bound_onDrag = this.onDrag.bind(this);
|
||||||
|
this.bound_onKeypress = this.onKeypress.bind(this);
|
||||||
|
|
||||||
|
// Events
|
||||||
|
this.tab.addEventListener("TabClose", this);
|
||||||
|
this.tab.addEventListener("TabAttrModified", this);
|
||||||
|
this.mainWindow.addEventListener("keypress", this.bound_onKeypress, true);
|
||||||
|
|
||||||
|
this.buildUI();
|
||||||
|
this.checkMenus();
|
||||||
|
}
|
||||||
|
|
||||||
|
ResponsiveUI.prototype = {
|
||||||
|
/**
|
||||||
|
* Destroy the nodes. Remove listeners. Reset the style.
|
||||||
|
*/
|
||||||
|
close: function RUI_unload() {
|
||||||
|
this.unCheckMenus();
|
||||||
|
// Reset style of the stack.
|
||||||
|
let style = "max-width: none;" +
|
||||||
|
"min-width: 0;" +
|
||||||
|
"max-height: none;" +
|
||||||
|
"min-height: 0;";
|
||||||
|
this.stack.setAttribute("style", style);
|
||||||
|
|
||||||
|
this.stopResizing();
|
||||||
|
|
||||||
|
// Remove listeners.
|
||||||
|
this.mainWindow.removeEventListener("keypress", this.bound_onKeypress, true);
|
||||||
|
this.menulist.removeEventListener("select", this.bound_presetSelected, true);
|
||||||
|
this.tab.removeEventListener("TabClose", this);
|
||||||
|
this.tab.removeEventListener("TabAttrModified", this);
|
||||||
|
this.rotatebutton.removeEventListener("command", this.bound_rotate, true);
|
||||||
|
|
||||||
|
// Removed elements.
|
||||||
|
this.container.removeChild(this.toolbar);
|
||||||
|
this.stack.removeChild(this.resizer);
|
||||||
|
this.stack.removeChild(this.resizeBar);
|
||||||
|
|
||||||
|
// Unset the responsive mode.
|
||||||
|
this.container.removeAttribute("responsivemode");
|
||||||
|
this.stack.removeAttribute("responsivemode");
|
||||||
|
|
||||||
|
delete this.tab.responsiveUI;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle keypressed.
|
||||||
|
*
|
||||||
|
* @param aEvent
|
||||||
|
*/
|
||||||
|
onKeypress: function RUI_onKeypress(aEvent) {
|
||||||
|
if (aEvent.keyCode == this.mainWindow.KeyEvent.DOM_VK_ESCAPE &&
|
||||||
|
this.mainWindow.gBrowser.selectedBrowser == this.browser) {
|
||||||
|
aEvent.preventDefault();
|
||||||
|
aEvent.stopPropagation();
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle events
|
||||||
|
*/
|
||||||
|
handleEvent: function (aEvent) {
|
||||||
|
switch (aEvent.type) {
|
||||||
|
case "TabClose":
|
||||||
|
this.close();
|
||||||
|
break;
|
||||||
|
case "TabAttrModified":
|
||||||
|
if (this.mainWindow.gBrowser.selectedBrowser == this.browser) {
|
||||||
|
this.checkMenus();
|
||||||
|
} else {
|
||||||
|
this.unCheckMenus();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the menu items.
|
||||||
|
*/
|
||||||
|
checkMenus: function RUI_checkMenus() {
|
||||||
|
this.chromeDoc.getElementById("Tools:ResponsiveUI").setAttribute("checked", "true");
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uncheck the menu items.
|
||||||
|
*/
|
||||||
|
unCheckMenus: function RUI_unCheckMenus() {
|
||||||
|
this.chromeDoc.getElementById("Tools:ResponsiveUI").setAttribute("checked", "false");
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the toolbar and the resizers.
|
||||||
|
*
|
||||||
|
* <vbox anonid="browserContainer"> From tabbrowser.xml
|
||||||
|
* <toolbar class="devtools-toolbar devtools-responsiveui-toolbar">
|
||||||
|
* <menulist class="devtools-menulist"/> // presets
|
||||||
|
* <toolbarbutton tabindex="0" class="devtools-toolbarbutton" label="rotate"/> // rotate
|
||||||
|
* </toolbar>
|
||||||
|
* <stack anonid="browserStack"> From tabbrowser.xml
|
||||||
|
* <browser/>
|
||||||
|
* <box class="devtools-responsiveui-resizehandle" bottom="0" right="0"/>
|
||||||
|
* <box class="devtools-responsiveui-resizebar" top="0" right="0"/>
|
||||||
|
* </stack>
|
||||||
|
* </vbox>
|
||||||
|
*/
|
||||||
|
buildUI: function RUI_buildUI() {
|
||||||
|
// Toolbar
|
||||||
|
this.toolbar = this.chromeDoc.createElement("toolbar");
|
||||||
|
this.toolbar.className = "devtools-toolbar devtools-responsiveui-toolbar";
|
||||||
|
|
||||||
|
this.menulist = this.chromeDoc.createElement("menulist");
|
||||||
|
this.menulist.className = "devtools-menulist";
|
||||||
|
|
||||||
|
this.menulist.addEventListener("select", this.bound_presetSelected, true);
|
||||||
|
|
||||||
|
let menupopup = this.chromeDoc.createElement("menupopup");
|
||||||
|
this.registerPresets(menupopup);
|
||||||
|
this.menulist.appendChild(menupopup);
|
||||||
|
|
||||||
|
this.rotatebutton = this.chromeDoc.createElement("toolbarbutton");
|
||||||
|
this.rotatebutton.setAttribute("tabindex", "0");
|
||||||
|
this.rotatebutton.setAttribute("label", this.strings.GetStringFromName("responsiveUI.rotate"));
|
||||||
|
this.rotatebutton.className = "devtools-toolbarbutton";
|
||||||
|
this.rotatebutton.addEventListener("command", this.bound_rotate, true);
|
||||||
|
|
||||||
|
this.toolbar.appendChild(this.menulist);
|
||||||
|
this.toolbar.appendChild(this.rotatebutton);
|
||||||
|
|
||||||
|
// Resizers
|
||||||
|
this.resizer = this.chromeDoc.createElement("box");
|
||||||
|
this.resizer.className = "devtools-responsiveui-resizehandle";
|
||||||
|
this.resizer.setAttribute("right", "0");
|
||||||
|
this.resizer.setAttribute("bottom", "0");
|
||||||
|
this.resizer.onmousedown = this.bound_startResizing;
|
||||||
|
|
||||||
|
this.resizeBar = this.chromeDoc.createElement("box");
|
||||||
|
this.resizeBar.className = "devtools-responsiveui-resizebar";
|
||||||
|
this.resizeBar.setAttribute("top", "0");
|
||||||
|
this.resizeBar.setAttribute("right", "0");
|
||||||
|
this.resizeBar.onmousedown = this.bound_startResizing;
|
||||||
|
|
||||||
|
this.container.insertBefore(this.toolbar, this.stack);
|
||||||
|
this.stack.appendChild(this.resizer);
|
||||||
|
this.stack.appendChild(this.resizeBar);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the presets list and append it to the menupopup.
|
||||||
|
*
|
||||||
|
* @param aParent menupopup.
|
||||||
|
*/
|
||||||
|
registerPresets: function RUI_registerPresets(aParent) {
|
||||||
|
let fragment = this.chromeDoc.createDocumentFragment();
|
||||||
|
let doc = this.chromeDoc;
|
||||||
|
let self = this;
|
||||||
|
this.presets.forEach(function(preset) {
|
||||||
|
let menuitem = doc.createElement("menuitem");
|
||||||
|
self.setMenuLabel(menuitem, preset);
|
||||||
|
fragment.appendChild(menuitem);
|
||||||
|
});
|
||||||
|
aParent.appendChild(fragment);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the menuitem label of a preset.
|
||||||
|
*
|
||||||
|
* @param aMenuitem menuitem to edit.
|
||||||
|
* @param aPreset associated preset.
|
||||||
|
*/
|
||||||
|
setMenuLabel: function RUI_setMenuLabel(aMenuitem, aPreset) {
|
||||||
|
let size = Math.round(aPreset.width) + "x" + Math.round(aPreset.height);
|
||||||
|
if (aPreset.custom) {
|
||||||
|
let str = this.strings.formatStringFromName("responsiveUI.customResolution", [size], 1);
|
||||||
|
aMenuitem.setAttribute("label", str);
|
||||||
|
} else {
|
||||||
|
aMenuitem.setAttribute("label", size);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a preset is selected, apply it.
|
||||||
|
*/
|
||||||
|
presetSelected: function RUI_presetSelected() {
|
||||||
|
this.currentPreset = this.menulist.selectedIndex;
|
||||||
|
let preset = this.presets[this.currentPreset];
|
||||||
|
this.loadPreset(preset);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a preset.
|
||||||
|
*
|
||||||
|
* @param aPreset preset to apply.
|
||||||
|
*/
|
||||||
|
loadPreset: function RUI_loadPreset(aPreset) {
|
||||||
|
this.setSize(aPreset.width, aPreset.height);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap width and height.
|
||||||
|
*/
|
||||||
|
rotate: function RUI_rotate() {
|
||||||
|
this.setSize(this.currentHeight, this.currentWidth);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the size of the browser.
|
||||||
|
*
|
||||||
|
* @param aWidth width of the browser.
|
||||||
|
* @param aHeight height of the browser.
|
||||||
|
*/
|
||||||
|
setSize: function RUI_setSize(aWidth, aHeight) {
|
||||||
|
this.currentWidth = aWidth;
|
||||||
|
this.currentHeight = aHeight;
|
||||||
|
|
||||||
|
// We resize the containing stack.
|
||||||
|
let style = "max-width: %width;" +
|
||||||
|
"min-width: %width;" +
|
||||||
|
"max-height: %height;" +
|
||||||
|
"min-height: %height;";
|
||||||
|
|
||||||
|
style = style.replace(/%width/g, this.currentWidth + "px");
|
||||||
|
style = style.replace(/%height/g, this.currentHeight + "px");
|
||||||
|
|
||||||
|
this.stack.setAttribute("style", style);
|
||||||
|
|
||||||
|
if (!this.ignoreY)
|
||||||
|
this.resizeBar.setAttribute("top", Math.round(this.currentHeight / 2));
|
||||||
|
|
||||||
|
// We uptate the Custom menuitem if we are not using a preset.
|
||||||
|
if (this.presets[this.currentPreset].custom) {
|
||||||
|
let preset = this.presets[this.currentPreset];
|
||||||
|
preset.width = this.currentWidth;
|
||||||
|
preset.height = this.currentHeight;
|
||||||
|
|
||||||
|
let menuitem = this.menulist.firstChild.childNodes[this.currentPreset];
|
||||||
|
this.setMenuLabel(menuitem, preset);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the process of resizing the browser.
|
||||||
|
*
|
||||||
|
* @param aEvent
|
||||||
|
*/
|
||||||
|
startResizing: function RUI_startResizing(aEvent) {
|
||||||
|
let preset = this.presets[this.currentPreset];
|
||||||
|
if (!preset.custom) {
|
||||||
|
this.currentPreset = 0;
|
||||||
|
preset = this.presets[0];
|
||||||
|
preset.width = this.currentWidth;
|
||||||
|
preset.height = this.currentHeight;
|
||||||
|
let menuitem = this.menulist.firstChild.childNodes[0];
|
||||||
|
this.setMenuLabel(menuitem, preset);
|
||||||
|
this.menulist.selectedIndex = 0;
|
||||||
|
}
|
||||||
|
this.mainWindow.addEventListener("mouseup", this.bound_stopResizing, true);
|
||||||
|
this.mainWindow.addEventListener("mousemove", this.bound_onDrag, true);
|
||||||
|
this.container.style.pointerEvents = "none";
|
||||||
|
|
||||||
|
this.stack.setAttribute("notransition", "true");
|
||||||
|
|
||||||
|
this.lastClientX = aEvent.clientX;
|
||||||
|
this.lastClientY = aEvent.clientY;
|
||||||
|
|
||||||
|
this.ignoreY = (aEvent.target === this.resizeBar);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resizing on mouse move.
|
||||||
|
*
|
||||||
|
* @param aEvent
|
||||||
|
*/
|
||||||
|
onDrag: function RUI_onDrag(aEvent) {
|
||||||
|
let deltaX = aEvent.clientX - this.lastClientX;
|
||||||
|
let deltaY = aEvent.clientY - this.lastClientY;
|
||||||
|
|
||||||
|
if (this.ignoreY)
|
||||||
|
deltaY = 0;
|
||||||
|
|
||||||
|
let width = this.currentWidth + deltaX;
|
||||||
|
let height = this.currentHeight + deltaY;
|
||||||
|
|
||||||
|
if (width < MIN_WIDTH) {
|
||||||
|
width = MIN_WIDTH;
|
||||||
|
} else {
|
||||||
|
this.lastClientX = aEvent.clientX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (height < MIN_HEIGHT) {
|
||||||
|
height = MIN_HEIGHT;
|
||||||
|
} else {
|
||||||
|
this.lastClientY = aEvent.clientY;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setSize(width, height);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop End resizing
|
||||||
|
*/
|
||||||
|
stopResizing: function RUI_stopResizing() {
|
||||||
|
this.container.style.pointerEvents = "auto";
|
||||||
|
|
||||||
|
this.mainWindow.removeEventListener("mouseup", this.bound_stopResizing, true);
|
||||||
|
this.mainWindow.removeEventListener("mousemove", this.bound_onDrag, true);
|
||||||
|
|
||||||
|
this.stack.removeAttribute("notransition");
|
||||||
|
this.ignoreY = false;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(ResponsiveUI.prototype, "strings", function () {
|
||||||
|
return Services.strings.createBundle("chrome://browser/locale/devtools/responsiveUI.properties");
|
||||||
|
});
|
||||||
53
browser/devtools/responsivedesign/test/Makefile.in
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# ***** BEGIN LICENSE BLOCK *****
|
||||||
|
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
# the License. You may obtain a copy of the License at
|
||||||
|
# http://www.mozilla.org/MPL/
|
||||||
|
#
|
||||||
|
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
# for the specific language governing rights and limitations under the
|
||||||
|
# License.
|
||||||
|
#
|
||||||
|
# The Original Code is mozilla.org code.
|
||||||
|
#
|
||||||
|
# The Initial Developer of the Original Code is
|
||||||
|
# Mozilla Foundation.
|
||||||
|
# Portions created by the Initial Developer are Copyright (C) 2012
|
||||||
|
# the Initial Developer. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Contributor(s):
|
||||||
|
# Paul Rouget <paul@mozilla.com>
|
||||||
|
#
|
||||||
|
# Alternatively, the contents of this file may be used under the terms of
|
||||||
|
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
# of those above. If you wish to allow use of your version of this file only
|
||||||
|
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
# use your version of this file under the terms of the MPL, indicate your
|
||||||
|
# decision by deleting the provisions above and replace them with the notice
|
||||||
|
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
# the provisions above, a recipient may use your version of this file under
|
||||||
|
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK *****
|
||||||
|
|
||||||
|
DEPTH = ../../../..
|
||||||
|
topsrcdir = @top_srcdir@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
VPATH = @srcdir@
|
||||||
|
relativesrcdir = browser/devtools/responsivedesign/test
|
||||||
|
|
||||||
|
include $(DEPTH)/config/autoconf.mk
|
||||||
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
|
||||||
|
_BROWSER_FILES = \
|
||||||
|
browser_responsiveui.js \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
|
||||||
|
libs:: $(_BROWSER_FILES)
|
||||||
|
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
|
||||||
143
browser/devtools/responsivedesign/test/browser_responsiveui.js
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
let instance;
|
||||||
|
|
||||||
|
waitForExplicitFinish();
|
||||||
|
|
||||||
|
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,mop";
|
||||||
|
|
||||||
|
function startTest() {
|
||||||
|
document.getElementById("Tools:ResponsiveUI").removeAttribute("disabled");
|
||||||
|
synthesizeKeyFromKeyTag("key_responsiveUI");
|
||||||
|
executeSoon(onUIOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onUIOpen() {
|
||||||
|
// Is it open?
|
||||||
|
let 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");
|
||||||
|
|
||||||
|
instance = gBrowser.selectedTab.responsiveUI;
|
||||||
|
ok(instance, "instance of the module is attached to the tab.");
|
||||||
|
|
||||||
|
testPresets();
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPresets() {
|
||||||
|
function testOnePreset(c) {
|
||||||
|
if (c == 0) {
|
||||||
|
executeSoon(testCustom);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
instance.menulist.selectedIndex = c;
|
||||||
|
window.setTimeout(function() {
|
||||||
|
let item = instance.menulist.firstChild.childNodes[c];
|
||||||
|
let [width, height] = extractSizeFromString(item.getAttribute("label"));
|
||||||
|
is(content.innerWidth, width, "preset " + c + ": dimension valid (width)");
|
||||||
|
is(content.innerHeight, height, "preset " + c + ": dimension valid (height)");
|
||||||
|
testOnePreset(c - 1);
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
testOnePreset(instance.menulist.firstChild.childNodes.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractSizeFromString(str) {
|
||||||
|
let numbers = str.match(/(\d+)[^\d]*(\d+)/);
|
||||||
|
if (numbers) {
|
||||||
|
return [numbers[1], numbers[2]];
|
||||||
|
} else {
|
||||||
|
return [null, null];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function testCustom() {
|
||||||
|
let initialWidth = content.innerWidth;
|
||||||
|
let initialHeight = content.innerHeight;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
window.setTimeout(function() {
|
||||||
|
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(instance.menulist.selectedIndex, 0, "Custom menuitem selected");
|
||||||
|
let [width, height] = extractSizeFromString(instance.menulist.firstChild.firstChild.getAttribute("label"));
|
||||||
|
is(width, expectedWidth, "Label updated (width).");
|
||||||
|
is(height, expectedHeight, "Label updated (height).");
|
||||||
|
rotate();
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rotate() {
|
||||||
|
let initialWidth = content.innerWidth;
|
||||||
|
let initialHeight = content.innerHeight;
|
||||||
|
|
||||||
|
info("rotate");
|
||||||
|
instance.rotate();
|
||||||
|
|
||||||
|
window.setTimeout(function() {
|
||||||
|
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"));
|
||||||
|
is(width, initialHeight, "Label updated (width).");
|
||||||
|
is(height, initialWidth, "Label updated (height).");
|
||||||
|
|
||||||
|
EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||||
|
executeSoon(finishUp);
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishUp() {
|
||||||
|
|
||||||
|
// Menus are correctly updated?
|
||||||
|
is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"), "false", "menu unchecked");
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
EventUtils.synthesizeKey(name, modifiers);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -214,6 +214,10 @@ These should match what Safari and other Apple applications use on OS X Lion. --
|
|||||||
<!ENTITY inspectContextMenu.label "Inspect Element">
|
<!ENTITY inspectContextMenu.label "Inspect Element">
|
||||||
<!ENTITY inspectContextMenu.accesskey "Q">
|
<!ENTITY inspectContextMenu.accesskey "Q">
|
||||||
|
|
||||||
|
<!ENTITY responsiveUI.label "Responsive Mode">
|
||||||
|
<!ENTITY responsiveUI.accesskey "R">
|
||||||
|
<!ENTITY responsiveUI.commandkey "M">
|
||||||
|
|
||||||
<!-- LOCALIZATION NOTE (scratchpad.label): This menu item label appears
|
<!-- LOCALIZATION NOTE (scratchpad.label): This menu item label appears
|
||||||
- in the Tools menu. See bug 653093.
|
- in the Tools menu. See bug 653093.
|
||||||
- The Scratchpad is intended to provide a simple text editor for creating
|
- The Scratchpad is intended to provide a simple text editor for creating
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# LOCALIZATION NOTE These strings are used inside the Responsive Mode
|
||||||
|
# which is available from the Web Developer sub-menu -> 'Responsive Mode'.
|
||||||
|
#
|
||||||
|
# The correct localization of this file might be to keep it in
|
||||||
|
# English, or another language commonly spoken among web developers.
|
||||||
|
# You want to make that choice consistent across the developer tools.
|
||||||
|
# A good criteria is the language in which you'd find the best
|
||||||
|
# documentation on web development on the web.
|
||||||
|
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (responsiveUI.rotate): label of the rotate button.
|
||||||
|
responsiveUI.rotate=rotate
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (responsiveUI.customResolution): label of the first item
|
||||||
|
# in the menulist at the beginning of the toolbar. For %S is replace with the
|
||||||
|
# current size of the page. For example: "400x600".
|
||||||
|
responsiveUI.customResolution=%S (custom)
|
||||||
@@ -36,6 +36,7 @@
|
|||||||
locale/browser/devtools/sourceeditor.properties (%chrome/browser/devtools/sourceeditor.properties)
|
locale/browser/devtools/sourceeditor.properties (%chrome/browser/devtools/sourceeditor.properties)
|
||||||
locale/browser/devtools/sourceeditor.dtd (%chrome/browser/devtools/sourceeditor.dtd)
|
locale/browser/devtools/sourceeditor.dtd (%chrome/browser/devtools/sourceeditor.dtd)
|
||||||
locale/browser/devtools/layoutview.dtd (%chrome/browser/devtools/layoutview.dtd)
|
locale/browser/devtools/layoutview.dtd (%chrome/browser/devtools/layoutview.dtd)
|
||||||
|
locale/browser/devtools/responsiveUI.properties (%chrome/browser/devtools/responsiveUI.properties)
|
||||||
locale/browser/newTab.dtd (%chrome/browser/newTab.dtd)
|
locale/browser/newTab.dtd (%chrome/browser/newTab.dtd)
|
||||||
locale/browser/newTab.properties (%chrome/browser/newTab.properties)
|
locale/browser/newTab.properties (%chrome/browser/newTab.properties)
|
||||||
locale/browser/openLocation.dtd (%chrome/browser/openLocation.dtd)
|
locale/browser/openLocation.dtd (%chrome/browser/openLocation.dtd)
|
||||||
|
|||||||
@@ -2477,3 +2477,49 @@ html|*#gcli-output-frame {
|
|||||||
.gcli-in-closebrace {
|
.gcli-in-closebrace {
|
||||||
color: hsl(0,0%,80%);
|
color: hsl(0,0%,80%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Responsive Mode */
|
||||||
|
|
||||||
|
vbox[anonid=browserContainer][responsivemode] {
|
||||||
|
background: #2a3643 url("chrome://browser/skin/devtools/responsive-background.png");
|
||||||
|
box-shadow: 0 0 7px black inset;
|
||||||
|
padding: 0 20px 20px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack[anonid=browserStack][responsivemode] {
|
||||||
|
box-shadow: 0 0 7px black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-toolbar {
|
||||||
|
background: transparent;
|
||||||
|
margin: 10px 0;
|
||||||
|
padding: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-toolbar > menulist,
|
||||||
|
.devtools-responsiveui-toolbar > toolbarbutton {
|
||||||
|
min-width: 22px;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-toolbar:-moz-locale-dir(ltr) > *:first-child,
|
||||||
|
.devtools-responsiveui-toolbar:-moz-locale-dir(rtl) > *:last-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-resizebar {
|
||||||
|
width: 7px;
|
||||||
|
height: 24px;
|
||||||
|
cursor: ew-resize;
|
||||||
|
-moz-transform: translate(12px, -12px);
|
||||||
|
background-image: url("chrome://browser/skin/devtools/responsive-vertical-resizer.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-resizehandle {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
cursor: se-resize;
|
||||||
|
-moz-transform: translate(12px, 12px);
|
||||||
|
background-image: url("chrome://browser/skin/devtools/responsive-se-resizer.png");
|
||||||
|
}
|
||||||
|
|||||||
BIN
browser/themes/gnomestripe/devtools/responsive-background.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
browser/themes/gnomestripe/devtools/responsive-se-resizer.png
Normal file
|
After Width: | Height: | Size: 269 B |
|
After Width: | Height: | Size: 174 B |
@@ -157,6 +157,9 @@ browser.jar:
|
|||||||
skin/classic/browser/devtools/debugger-step-out.png (devtools/debugger-step-out.png)
|
skin/classic/browser/devtools/debugger-step-out.png (devtools/debugger-step-out.png)
|
||||||
skin/classic/browser/devtools/debugger-step-over.png (devtools/debugger-step-over.png)
|
skin/classic/browser/devtools/debugger-step-over.png (devtools/debugger-step-over.png)
|
||||||
skin/classic/browser/devtools/inspector-option-icon.png (devtools/inspector-option-icon.png)
|
skin/classic/browser/devtools/inspector-option-icon.png (devtools/inspector-option-icon.png)
|
||||||
|
skin/classic/browser/devtools/responsive-se-resizer.png (devtools/responsive-se-resizer.png)
|
||||||
|
skin/classic/browser/devtools/responsive-vertical-resizer.png (devtools/responsive-vertical-resizer.png)
|
||||||
|
skin/classic/browser/devtools/responsive-background.png (devtools/responsive-background.png)
|
||||||
#ifdef MOZ_SERVICES_SYNC
|
#ifdef MOZ_SERVICES_SYNC
|
||||||
skin/classic/browser/sync-16-throbber.png
|
skin/classic/browser/sync-16-throbber.png
|
||||||
skin/classic/browser/sync-16.png
|
skin/classic/browser/sync-16.png
|
||||||
|
|||||||
@@ -3218,3 +3218,49 @@ html|*#gcli-output-frame {
|
|||||||
.gcli-in-closebrace {
|
.gcli-in-closebrace {
|
||||||
color: hsl(0,0%,80%);
|
color: hsl(0,0%,80%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Responsive Mode */
|
||||||
|
|
||||||
|
vbox[anonid=browserContainer][responsivemode] {
|
||||||
|
background: #2a3643 url("chrome://browser/skin/devtools/responsive-background.png");
|
||||||
|
box-shadow: 0 0 7px black inset;
|
||||||
|
padding: 0 20px 20px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack[anonid=browserStack][responsivemode] {
|
||||||
|
box-shadow: 0 0 7px black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-toolbar {
|
||||||
|
background: transparent;
|
||||||
|
margin: 10px 0;
|
||||||
|
padding: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-toolbar > menulist,
|
||||||
|
.devtools-responsiveui-toolbar > toolbarbutton {
|
||||||
|
min-width: 22px;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-toolbar:-moz-locale-dir(ltr) > *:first-child,
|
||||||
|
.devtools-responsiveui-toolbar:-moz-locale-dir(rtl) > *:last-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-resizebar {
|
||||||
|
width: 7px;
|
||||||
|
height: 24px;
|
||||||
|
cursor: ew-resize;
|
||||||
|
-moz-transform: translate(12px, -12px);
|
||||||
|
background-image: url("chrome://browser/skin/devtools/responsive-vertical-resizer.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-resizehandle {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
cursor: se-resize;
|
||||||
|
-moz-transform: translate(12px, 12px);
|
||||||
|
background-image: url("chrome://browser/skin/devtools/responsive-se-resizer.png");
|
||||||
|
}
|
||||||
|
|||||||
BIN
browser/themes/pinstripe/devtools/responsive-background.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
browser/themes/pinstripe/devtools/responsive-se-resizer.png
Normal file
|
After Width: | Height: | Size: 269 B |
|
After Width: | Height: | Size: 174 B |
@@ -197,7 +197,10 @@ browser.jar:
|
|||||||
skin/classic/browser/devtools/debugger-step-in.png (devtools/debugger-step-in.png)
|
skin/classic/browser/devtools/debugger-step-in.png (devtools/debugger-step-in.png)
|
||||||
skin/classic/browser/devtools/debugger-step-out.png (devtools/debugger-step-out.png)
|
skin/classic/browser/devtools/debugger-step-out.png (devtools/debugger-step-out.png)
|
||||||
skin/classic/browser/devtools/debugger-step-over.png (devtools/debugger-step-over.png)
|
skin/classic/browser/devtools/debugger-step-over.png (devtools/debugger-step-over.png)
|
||||||
skin/classic/browser/devtools/inspector-option-icon.png (devtools/inspector-option-icon.png)
|
skin/classic/browser/devtools/inspector-option-icon.png (devtools/inspector-option-icon.png)
|
||||||
|
skin/classic/browser/devtools/responsive-se-resizer.png (devtools/responsive-se-resizer.png)
|
||||||
|
skin/classic/browser/devtools/responsive-vertical-resizer.png (devtools/responsive-vertical-resizer.png)
|
||||||
|
skin/classic/browser/devtools/responsive-background.png (devtools/responsive-background.png)
|
||||||
#ifdef MOZ_SERVICES_SYNC
|
#ifdef MOZ_SERVICES_SYNC
|
||||||
skin/classic/browser/sync-throbber.png
|
skin/classic/browser/sync-throbber.png
|
||||||
skin/classic/browser/sync-16.png
|
skin/classic/browser/sync-16.png
|
||||||
|
|||||||
@@ -3150,3 +3150,50 @@ html|*#gcli-output-frame {
|
|||||||
.gcli-in-closebrace {
|
.gcli-in-closebrace {
|
||||||
color: hsl(0,0%,80%);
|
color: hsl(0,0%,80%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Responsive Mode */
|
||||||
|
|
||||||
|
vbox[anonid=browserContainer][responsivemode] {
|
||||||
|
background: #2a3643 url("chrome://browser/skin/devtools/responsive-background.png");
|
||||||
|
box-shadow: 0 0 7px black inset;
|
||||||
|
padding: 0 20px 20px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack[anonid=browserStack][responsivemode] {
|
||||||
|
box-shadow: 0 0 7px black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-toolbar {
|
||||||
|
background: transparent;
|
||||||
|
margin: 10px 0;
|
||||||
|
padding: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
border-bottom-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-toolbar > menulist,
|
||||||
|
.devtools-responsiveui-toolbar > toolbarbutton {
|
||||||
|
min-width: 22px;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-toolbar:-moz-locale-dir(ltr) > *:first-child,
|
||||||
|
.devtools-responsiveui-toolbar:-moz-locale-dir(rtl) > *:last-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-resizebar {
|
||||||
|
width: 7px;
|
||||||
|
height: 24px;
|
||||||
|
cursor: ew-resize;
|
||||||
|
-moz-transform: translate(12px, -12px);
|
||||||
|
background-image: url("chrome://browser/skin/devtools/responsive-vertical-resizer.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
.devtools-responsiveui-resizehandle {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
cursor: se-resize;
|
||||||
|
-moz-transform: translate(12px, 12px);
|
||||||
|
background-image: url("chrome://browser/skin/devtools/responsive-se-resizer.png");
|
||||||
|
}
|
||||||
|
|||||||
BIN
browser/themes/winstripe/devtools/responsive-background.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
browser/themes/winstripe/devtools/responsive-se-resizer.png
Normal file
|
After Width: | Height: | Size: 269 B |
|
After Width: | Height: | Size: 174 B |
@@ -184,6 +184,9 @@ browser.jar:
|
|||||||
skin/classic/browser/devtools/debugger-step-out.png (devtools/debugger-step-out.png)
|
skin/classic/browser/devtools/debugger-step-out.png (devtools/debugger-step-out.png)
|
||||||
skin/classic/browser/devtools/debugger-step-over.png (devtools/debugger-step-over.png)
|
skin/classic/browser/devtools/debugger-step-over.png (devtools/debugger-step-over.png)
|
||||||
skin/classic/browser/devtools/inspector-option-icon.png (devtools/inspector-option-icon.png)
|
skin/classic/browser/devtools/inspector-option-icon.png (devtools/inspector-option-icon.png)
|
||||||
|
skin/classic/browser/devtools/responsive-se-resizer.png (devtools/responsive-se-resizer.png)
|
||||||
|
skin/classic/browser/devtools/responsive-vertical-resizer.png (devtools/responsive-vertical-resizer.png)
|
||||||
|
skin/classic/browser/devtools/responsive-background.png (devtools/responsive-background.png)
|
||||||
#ifdef MOZ_SERVICES_SYNC
|
#ifdef MOZ_SERVICES_SYNC
|
||||||
skin/classic/browser/sync-throbber.png
|
skin/classic/browser/sync-throbber.png
|
||||||
skin/classic/browser/sync-16.png
|
skin/classic/browser/sync-16.png
|
||||||
@@ -378,7 +381,10 @@ browser.jar:
|
|||||||
skin/classic/aero/browser/devtools/debugger-step-in.png (devtools/debugger-step-in.png)
|
skin/classic/aero/browser/devtools/debugger-step-in.png (devtools/debugger-step-in.png)
|
||||||
skin/classic/aero/browser/devtools/debugger-step-out.png (devtools/debugger-step-out.png)
|
skin/classic/aero/browser/devtools/debugger-step-out.png (devtools/debugger-step-out.png)
|
||||||
skin/classic/aero/browser/devtools/debugger-step-over.png (devtools/debugger-step-over.png)
|
skin/classic/aero/browser/devtools/debugger-step-over.png (devtools/debugger-step-over.png)
|
||||||
skin/classic/aero/browser/devtools/inspector-option-icon.png (devtools/inspector-option-icon.png)
|
skin/classic/aero/browser/devtools/inspector-option-icon.png (devtools/inspector-option-icon.png)
|
||||||
|
skin/classic/aero/browser/devtools/responsive-se-resizer.png (devtools/responsive-se-resizer.png)
|
||||||
|
skin/classic/aero/browser/devtools/responsive-vertical-resizer.png (devtools/responsive-vertical-resizer.png)
|
||||||
|
skin/classic/aero/browser/devtools/responsive-background.png (devtools/responsive-background.png)
|
||||||
#ifdef MOZ_SERVICES_SYNC
|
#ifdef MOZ_SERVICES_SYNC
|
||||||
skin/classic/aero/browser/sync-throbber.png
|
skin/classic/aero/browser/sync-throbber.png
|
||||||
skin/classic/aero/browser/sync-16.png
|
skin/classic/aero/browser/sync-16.png
|
||||||
|
|||||||