1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /* eslint-env browser */
9 const { BrowserLoader } = ChromeUtils.import(
10 "resource://devtools/client/shared/browser-loader.js"
12 const { require } = BrowserLoader({
13 baseURI: "resource://devtools/client/responsive/",
16 const Services = require("Services");
17 const Telemetry = require("devtools/client/shared/telemetry");
22 } = require("devtools/client/shared/vendor/react");
23 const ReactDOM = require("devtools/client/shared/vendor/react-dom");
24 const { Provider } = require("devtools/client/shared/vendor/react-redux");
26 const message = require("./utils/message");
27 const App = createFactory(require("./components/App"));
28 const Store = require("./store");
29 const { loadDevices, restoreDeviceState } = require("./actions/devices");
34 } = require("./actions/viewports");
35 const { changeDisplayPixelRatio } = require("./actions/ui");
37 // Exposed for use by tests
38 window.require = require;
40 if (Services.prefs.getBoolPref("devtools.responsive.browserUI.enabled")) {
41 // Tell the ResponsiveUIManager that the frame script has begun initializing.
42 message.post(window, "script-init");
46 telemetry: new Telemetry(),
51 // responsive is not connected with a toolbox so we pass -1 as the
52 // toolbox session id.
53 this.telemetry.toolOpened("responsive", -1, this);
55 const store = (this.store = Store());
56 const provider = createElement(Provider, { store }, App());
57 ReactDOM.render(provider, document.querySelector("#root"));
58 message.post(window, "init:done");
64 // responsive is not connected with a toolbox so we pass -1 as the
65 // toolbox session id.
66 this.telemetry.toolClosed("responsive", -1, this);
67 this.telemetry = null;
71 * While most actions will be dispatched by React components, some external
72 * APIs that coordinate with the larger browser UI may also have actions to
73 * to dispatch. They can do so here.
77 // If actions are dispatched after store is destroyed, ignore them. This
78 // can happen in tests that close the tool quickly while async tasks like
79 // initDevices() below are still pending.
82 this.store.dispatch(action);
86 // manager.js sends a message to signal init
87 message.wait(window, "init").then(() => bootstrap.init());
89 // manager.js sends a message to signal init is done, which can be used for delayed
90 // startup work that shouldn't block initial load
91 message.wait(window, "post-init").then(() => {
92 bootstrap.store.dispatch(loadDevices()).then(() => {
93 bootstrap.dispatch(restoreDeviceState());
97 window.addEventListener(
105 // Allows quick testing of actions from the console
106 window.dispatch = action => bootstrap.dispatch(action);
108 // Expose the store on window for testing
109 Object.defineProperty(window, "store", {
110 get: () => bootstrap.store,
114 // Dispatch a `changeDisplayPixelRatio` action when the browser's pixel ratio is changing.
115 // This is usually triggered when the user changes the monitor resolution, or when the
116 // browser's window is dragged to a different display with a different pixel ratio.
117 // TODO: It would be better to move this watching into the actor, so that it can be
118 // better synchronized with any overrides that might be applied. Also, reading a single
119 // value like this makes less sense with multiple viewports.
120 function onDevicePixelRatioChange() {
121 const dpr = window.devicePixelRatio;
122 const mql = window.matchMedia(`(resolution: ${dpr}dppx)`);
124 function listener() {
125 bootstrap.dispatch(changeDisplayPixelRatio(window.devicePixelRatio));
126 mql.removeListener(listener);
127 onDevicePixelRatioChange();
130 mql.addListener(listener);
134 * Called by manager.js to add the initial viewport based on the original page.
136 window.addInitialViewport = ({ userContextId }) => {
138 onDevicePixelRatioChange();
139 bootstrap.dispatch(changeDisplayPixelRatio(window.devicePixelRatio));
140 bootstrap.dispatch(addViewport(userContextId));
147 * Called by manager.js when tests want to check the viewport size.
149 window.getViewportSize = () => {
150 const { viewports } = bootstrap.store.getState();
151 if (!viewports.length) {
155 const { width, height } = viewports[0];
156 return { width, height };
160 * Called by manager.js to set viewport size from tests, etc.
162 window.setViewportSize = ({ width, height }) => {
164 bootstrap.dispatch(resizeViewport(0, width, height));
171 * Called by manager.js to access the viewport's browser, either for testing
172 * purposes or to reload it when touch simulation is enabled.
173 * A messageManager getter is added on the object to provide an easy access
174 * to the message manager without pulling the frame loader.
176 window.getViewportBrowser = () => {
177 const browser = document.querySelector("iframe.browser");
178 if (!browser.messageManager) {
179 Object.defineProperty(browser, "messageManager", {
181 return this.frameLoader.messageManager;
191 * Called by manager.js to zoom the viewport.
193 window.setViewportZoom = zoom => {
195 bootstrap.dispatch(zoomViewport(0, zoom));