Bug 1326138 - Add a new profile item binding. r=MattN
authorRay Lin <ralin@mozilla.com>
Tue, 24 Jan 2017 23:32:17 +0800
changeset 343262 bd3f65389f27a9effc74b36dc7c03672e84a661d
parent 343261 b25738421d6e3390548b27c224cdcd2dfa613133
child 343263 b64ce70deb6f56bd2812791252b77ffdc68b9b24
push id31374
push userkwierso@gmail.com
push dateThu, 16 Feb 2017 17:26:30 +0000
treeherdermozilla-central@4158b1d8bb2a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1326138
milestone54.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 1326138 - Add a new profile item binding. r=MattN MozReview-Commit-ID: KzbnQteM1pY
browser/extensions/formautofill/bootstrap.js
browser/extensions/formautofill/content/formautofill.css
browser/extensions/formautofill/content/formautofill.xml
--- a/browser/extensions/formautofill/bootstrap.js
+++ b/browser/extensions/formautofill/bootstrap.js
@@ -2,30 +2,86 @@
  * 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";
 
 /* exported startup, shutdown, install, uninstall */
 
 const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
+const STYLESHEET_URI = "chrome://formautofill/content/formautofill.css";
+const CACHED_STYLESHEETS = new WeakMap();
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "FormAutofillParent",
                                   "resource://formautofill/FormAutofillParent.jsm");
 
+function insertStyleSheet(domWindow, url) {
+  let doc = domWindow.document;
+  let styleSheetAttr = `href="${url}" type="text/css"`;
+  let styleSheet = doc.createProcessingInstruction("xml-stylesheet", styleSheetAttr);
+
+  doc.insertBefore(styleSheet, doc.documentElement);
+
+  if (CACHED_STYLESHEETS.has(domWindow)) {
+    CACHED_STYLESHEETS.get(domWindow).push(styleSheet);
+  } else {
+    CACHED_STYLESHEETS.set(domWindow, [styleSheet]);
+  }
+}
+
+let windowListener = {
+  onOpenWindow(aWindow) {
+    let domWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+
+    domWindow.addEventListener("load", function onWindowLoaded() {
+      insertStyleSheet(domWindow, STYLESHEET_URI);
+    }, {once: true});
+  },
+};
+
 function startup() {
   // Besides this pref, we'll need dom.forms.autocomplete.experimental enabled
   // as well to make sure form autocomplete works correctly.
   if (!Services.prefs.getBoolPref("browser.formautofill.experimental")) {
     return;
   }
 
   let parent = new FormAutofillParent();
+  let enumerator = Services.wm.getEnumerator("navigator:browser");
+  // Load stylesheet to already opened windows
+  while (enumerator.hasMoreElements()) {
+    let win = enumerator.getNext();
+    let domWindow = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+
+    insertStyleSheet(domWindow, STYLESHEET_URI);
+  }
+
+  Services.wm.addListener(windowListener);
+
   parent.init();
   Services.mm.loadFrameScript("chrome://formautofill/content/FormAutofillFrameScript.js", true);
 }
 
-function shutdown() {}
+function shutdown() {
+  Services.wm.removeListener(windowListener);
+
+  let enumerator = Services.wm.getEnumerator("navigator:browser");
+
+  while (enumerator.hasMoreElements()) {
+    let win = enumerator.getNext();
+    let domWindow = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
+    let cachedStyleSheets = CACHED_STYLESHEETS.get(domWindow);
+
+    if (!cachedStyleSheets) {
+      continue;
+    }
+
+    while (cachedStyleSheets.length !== 0) {
+      cachedStyleSheets.pop().remove();
+    }
+  }
+}
+
 function install() {}
 function uninstall() {}
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/content/formautofill.css
@@ -0,0 +1,7 @@
+/* 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/. */
+
+.autocomplete-richlistitem[originaltype="autofill-profile"] {
+  -moz-binding: url("chrome://formautofill/content/formautofill.xml#autocomplete-profile-listitem");
+}
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/content/formautofill.xml
@@ -0,0 +1,79 @@
+<?xml version="1.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/. -->
+
+<bindings id="formautofillBindings"
+          xmlns="http://www.mozilla.org/xbl"
+          xmlns:html="http://www.w3.org/1999/xhtml"
+          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+          xmlns:xbl="http://www.mozilla.org/xbl">
+
+  <binding id="autocomplete-profile-listitem" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
+    <xbl:content xmlns="http://www.w3.org/1999/xhtml">
+      <div anonid="profile-item-box" class="profile-item-box">
+        <div class="profile-label-col profile-item-col">
+          <span anonid="profile-label" class="profile-label"></span>
+        </div>
+        <div class="profile-comment-col profile-item-col">
+          <span anonid="profile-comment" class="profile-comment"></span>
+        </div>
+      </div>
+    </xbl:content>
+
+    <implementation implements="nsIDOMXULSelectControlItemElement">
+      <constructor>
+        <![CDATA[
+          this._itemBox = document.getAnonymousElementByAttribute(
+            this, "anonid", "profile-item-box"
+          );
+          this._label = document.getAnonymousElementByAttribute(
+            this, "anonid", "profile-label"
+          );
+          this._comment = document.getAnonymousElementByAttribute(
+            this, "anonid", "profile-comment"
+          );
+
+          this._adjustAcItem();
+        ]]>
+      </constructor>
+
+      <method name="_cleanup">
+        <body>
+        <![CDATA[
+            this._itemBox.removeAttribute("size");
+        ]]>
+        </body>
+      </method>
+
+      <method name="_onOverflow">
+        <body></body>
+      </method>
+
+      <method name="_onUnderflow">
+        <body></body>
+      </method>
+
+      <method name="_adjustAcItem">
+        <body>
+        <![CDATA[
+          let outerBoxRect = this.parentNode.getBoundingClientRect();
+          let value = this.getAttribute("ac-value");
+          let comment = this.getAttribute("ac-comment");
+
+          this._comment.textContent = comment;
+          this._label.textContent = value;
+
+          // Use two-lines layout when width is smaller than 150px
+          if (outerBoxRect.width <= 150) {
+            this._itemBox.setAttribute("size", "small");
+          } else {
+            this._itemBox.removeAttribute("size");
+          }
+        ]]>
+        </body>
+      </method>
+    </implementation>
+  </binding>
+
+</bindings>