Bug 828008 - Add an UI to emulate user agent from responsive mode. r=jryans
☠☠ backed out by ab22ba41b8fc ☠ ☠
authorTim Nguyen <ntim.bugs@gmail.com>
Mon, 28 Dec 2015 12:03:00 +0100
changeset 277868 773075ac2210560980913e8f79ea6b9fcb10a1d0
parent 277867 e29ff13d30cd6e4d11c47ceb201e24dc14390cea
child 277869 6dbba51c24d2386624557368feaed125e5a32a63
push id69628
push usercbook@mozilla.com
push dateWed, 30 Dec 2015 11:16:09 +0000
treeherdermozilla-inbound@b493cf33851f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjryans
bugs828008
milestone46.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 828008 - Add an UI to emulate user agent from responsive mode. r=jryans
devtools/client/locales/en-US/responsiveUI.properties
devtools/client/responsivedesign/responsivedesign.jsm
devtools/client/themes/responsivedesign.inc.css
--- a/devtools/client/locales/en-US/responsiveUI.properties
+++ b/devtools/client/locales/en-US/responsiveUI.properties
@@ -13,16 +13,19 @@
 
 
 # LOCALIZATION NOTE  (responsiveUI.rotate2): tooltip of the rotate button.
 responsiveUI.rotate2=Rotate
 
 # LOCALIZATION NOTE  (responsiveUI.screenshot): tooltip of the screenshot button.
 responsiveUI.screenshot=Screenshot
 
+# LOCALIZATION NOTE  (responsiveUI.userAgentPlaceholder): placeholder for the user agent input.
+responsiveUI.userAgentPlaceholder=Custom User Agent
+
 # LOCALIZATION NOTE (responsiveUI.screenshotGeneratedFilename): The auto generated filename.
 # The first argument (%1$S) is the date string in yyyy-mm-dd format and the second
 # argument (%2$S) is the time string in HH.MM.SS format.
 responsiveUI.screenshotGeneratedFilename=Screen Shot %1$S at %2$S
 
 # LOCALIZATION NOTE  (responsiveUI.touch): tooltip of the touch button.
 responsiveUI.touch=Simulate touch events (page reload might be needed)
 
--- a/devtools/client/responsivedesign/responsivedesign.jsm
+++ b/devtools/client/responsivedesign/responsivedesign.jsm
@@ -2,30 +2,33 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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 Cu = Components.utils;
 
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://devtools/client/framework/gDevTools.jsm");
-Cu.import("resource://devtools/shared/event-emitter.js");
-Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
-                                  "resource://gre/modules/SystemAppProxy.jsm");
-
-var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
+var {require, loader} = Cu.import("resource://devtools/shared/Loader.jsm", {});
+var Services = require("Services");
+var {gDevTools} = require("resource://devtools/client/framework/gDevTools.jsm");
+var EventEmitter = require("devtools/shared/event-emitter");
+var {ViewHelpers} =
+    require("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
 var Telemetry = require("devtools/client/shared/telemetry");
-var { showDoorhanger } = require("devtools/client/shared/doorhanger");
-var { TouchEventSimulator } = require("devtools/shared/touch/simulator");
-var { Task } = require("resource://gre/modules/Task.jsm");
+var {showDoorhanger} = require("devtools/client/shared/doorhanger");
+var {TouchEventSimulator} = require("devtools/shared/touch/simulator");
+var {Task} = require("resource://gre/modules/Task.jsm");
 var promise = require("promise");
+loader.lazyImporter(this, "SystemAppProxy",
+                          "resource://gre/modules/SystemAppProxy.jsm");
+loader.lazyRequireGetter(this, "DebuggerClient",
+                         "devtools/shared/client/main", true);
+loader.lazyRequireGetter(this, "DebuggerServer",
+                         "devtools/server/main", true);
 
 this.EXPORTED_SYMBOLS = ["ResponsiveUIManager"];
 
 const MIN_WIDTH = 50;
 const MIN_HEIGHT = 50;
 
 const MAX_WIDTH = 10000;
 const MAX_HEIGHT = 10000;
@@ -204,16 +207,17 @@ function ResponsiveUI(aWindow, aTab)
   this.bound_removePreset = this.removePreset.bind(this);
   this.bound_rotate = this.rotate.bind(this);
   this.bound_screenshot = () => this.screenshot();
   this.bound_touch = this.toggleTouch.bind(this);
   this.bound_close = this.close.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_changeUA = this.changeUA.bind(this);
 
   // Events
   this.tab.addEventListener("TabClose", this);
   this.tabContainer.addEventListener("TabSelect", this);
 
   this.buildUI();
   this.checkMenus();
 
@@ -232,32 +236,54 @@ function ResponsiveUI(aWindow, aTab)
   this.touchEventSimulator = new TouchEventSimulator(this.browser);
 
   // Hook to display promotional Developer Edition doorhanger. Only displayed once.
   showDoorhanger({
     window: this.mainWindow,
     type: "deveditionpromo",
     anchor: this.chromeDoc.querySelector("#content")
   });
+
+  this.connectToServer();
 }
 
 ResponsiveUI.prototype = {
   _transitionsEnabled: true,
   get transitionsEnabled() {
     return this._transitionsEnabled;
   },
   set transitionsEnabled(aValue) {
     this._transitionsEnabled = aValue;
     if (aValue && !this._resizing && this.stack.hasAttribute("responsivemode")) {
       this.stack.removeAttribute("notransition");
     } else if (!aValue) {
       this.stack.setAttribute("notransition", "true");
     }
   },
 
+  connectToServer: function() {
+    if (!DebuggerServer.initialized) {
+      DebuggerServer.init();
+      DebuggerServer.addBrowserActors();
+    }
+    this.client = new DebuggerClient(DebuggerServer.connectPipe());
+    this.client.connect(() => {
+      this.client.getTab().then(({tab}) => {
+        this.client.attachTab(tab.actor, (response, tabClient) => {
+          if (!tabClient) {
+            Cu.reportError("Responsive mode error: failed to attach tab");
+            return;
+          }
+          this.tabClient = tabClient;
+          this.userAgentInput.hidden = false;
+        });
+      });
+    });
+  },
+
   /**
    * Destroy the nodes. Remove listeners. Reset the style.
    */
   close: function RUI_close() {
     if (this.closing)
       return;
     this.closing = true;
 
@@ -299,16 +325,17 @@ ResponsiveUI.prototype = {
     // Unset the responsive mode.
     this.container.removeAttribute("responsivemode");
     this.stack.removeAttribute("responsivemode");
 
     ActiveTabs.delete(this.tab);
     if (this.touchEventSimulator) {
       this.touchEventSimulator.stop();
     }
+    this.client.close();
     this._telemetry.toolClosed("responsive");
     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");
   },
@@ -452,16 +479,24 @@ ResponsiveUI.prototype = {
     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);
 
+    this.userAgentInput = this.chromeDoc.createElement("textbox");
+    this.userAgentInput.className = "devtools-responsiveui-textinput";
+    this.userAgentInput.setAttribute("placeholder",
+      this.strings.GetStringFromName("responsiveUI.userAgentPlaceholder"));
+    this.userAgentInput.addEventListener("blur", this.bound_changeUA, true);
+    this.userAgentInput.hidden = true;
+    this.toolbar.appendChild(this.userAgentInput);
+
     // Resizers
     let resizerTooltip = this.strings.GetStringFromName("responsiveUI.resizerTooltip");
     this.resizer = this.chromeDoc.createElement("box");
     this.resizer.className = "devtools-responsiveui-resizehandle";
     this.resizer.setAttribute("right", "0");
     this.resizer.setAttribute("bottom", "0");
     this.resizer.setAttribute("tooltiptext", resizerTooltip);
     this.resizer.onmousedown = this.bound_startResizing;
@@ -847,16 +882,26 @@ ResponsiveUI.prototype = {
            "responsive-ui-need-reload",
            null,
            nbox.PRIORITY_INFO_LOW,
            buttons);
        }
      }
    }),
 
+  changeUA: function() {
+    var value = this.userAgentInput.value;
+    if (value !== "") {
+      this.userAgentInput.setAttribute("attention", "true");
+    } else {
+      this.userAgentInput.removeAttribute("attention", "true");
+    }
+    this.tabClient.reconfigure({customUserAgent: value});
+  },
+
   /**
    * 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.setWidth(aWidth);
@@ -1022,11 +1067,11 @@ ResponsiveUI.prototype = {
     let registeredPresets = this.presets.filter(function (aPreset) {
       return !aPreset.custom;
     });
 
     Services.prefs.setCharPref("devtools.responsiveUI.presets", JSON.stringify(registeredPresets));
   },
 }
 
-XPCOMUtils.defineLazyGetter(ResponsiveUI.prototype, "strings", function () {
+loader.lazyGetter(ResponsiveUI.prototype, "strings", function () {
   return Services.strings.createBundle("chrome://devtools/locale/responsiveUI.properties");
 });
--- a/devtools/client/themes/responsivedesign.inc.css
+++ b/devtools/client/themes/responsivedesign.inc.css
@@ -23,16 +23,32 @@
    */
   color: hsl(210,30%,85%);
   margin: 10px 0;
   padding: 0;
   box-shadow: none;
   border-bottom-width: 0;
 }
 
+.devtools-responsiveui-textinput {
+  -moz-appearance: none;
+  background: #333;
+  color: #fff;
+  border: 1px solid #111;
+  border-radius: 2px;
+  padding: 5px;
+  width: 200px;
+  margin: 0;
+}
+
+.devtools-responsiveui-textinput[attention] {
+  border-color: #38ace6;
+  background: rgba(56,172,230,0.4);
+}
+
 .devtools-responsiveui-menulist,
 .devtools-responsiveui-toolbarbutton {
   -moz-appearance: none;
   -moz-box-align: center;
   min-width: 32px;
   min-height: 22px;
   text-shadow: 0 -1px 0 hsla(210,8%,5%,.45);
   border: 1px solid hsla(210,8%,5%,.45);