Bug 1167246 - Fix SDK native-options module on Android. draft
authorLuca Greco <lgreco@mozilla.com>
Fri, 01 Apr 2016 13:56:37 +0200
changeset 347294 8da867d8011c563db8dd3520eafa7412b2be7ddd
parent 346007 e14db462d31d566570e3bece66d5380f7b1ad400
child 517593 8807bde3f4ab805dcb3a90e2ece10b4342be9ad4
push id14541
push userluca.greco@alcacoop.it
push dateMon, 04 Apr 2016 14:40:10 +0000
bugs1167246
milestone48.0a1
Bug 1167246 - Fix SDK native-options module on Android. MozReview-Commit-ID: CrIgkXlllWV
addon-sdk/source/lib/sdk/preferences/native-options.js
--- a/addon-sdk/source/lib/sdk/preferences/native-options.js
+++ b/addon-sdk/source/lib/sdk/preferences/native-options.js
@@ -6,48 +6,67 @@
 module.metadata = {
   "stability": "unstable"
 };
 
 const { Cc, Ci, Cu } = require('chrome');
 const { on } = require('../system/events');
 const { id, preferencesBranch } = require('../self');
 const { localizeInlineOptions } = require('../l10n/prefs');
+const { Services } = require("resource://gre/modules/Services.jsm");
 const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm");
 const { defer } = require("sdk/core/promise");
 
+const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";;
 const DEFAULT_OPTIONS_URL = 'data:text/xml,<placeholder/>';
 
 const VALID_PREF_TYPES = ['bool', 'boolint', 'integer', 'string', 'color',
                           'file', 'directory', 'control', 'menulist', 'radio'];
 
+const isFennec = require("sdk/system/xul-app").is("Fennec");
+
 function enable({ preferences, id }) {
   let enabled = defer();
 
   validate(preferences);
 
   setDefaults(preferences, preferencesBranch);
 
   // allow the use of custom options.xul
   AddonManager.getAddonByID(id, (addon) => {
     on('addon-options-displayed', onAddonOptionsDisplayed, true);
     enabled.resolve({ id: id });
   });
 
   function onAddonOptionsDisplayed({ subject: doc, data }) {
     if (data === id) {
-      let parent = doc.getElementById('detail-downloads').parentNode;
-      injectOptions({
-        preferences: preferences,
-        preferencesBranch: preferencesBranch,
-        document: doc,
-        parent: parent,
-        id: id
-      });
-      localizeInlineOptions(doc);
+      let parent;
+
+      if (isFennec) {
+        parent = doc.querySelector('.options-box');
+
+        // NOTE: This disable the CSS rule that makes the options invisible
+        let item = doc.querySelector('#addons-details .addon-item');
+        item.removeAttribute("optionsURL");
+      } else {
+        parent = doc.getElementById('detail-downloads').parentNode;
+      }
+
+      if (parent) {
+        injectOptions({
+          preferences: preferences,
+          preferencesBranch: preferencesBranch,
+          document: doc,
+          parent: parent,
+          id: id
+        });
+        localizeInlineOptions(doc);
+      } else {
+        throw Error("Preferences parent node not found in Addon Details. The configured custom preferences will not be visible.");
+      }
     }
   }
 
   return enabled.promise;
 }
 exports.enable = enable;
 
 // centralized sanity checks
@@ -105,64 +124,67 @@ function setDefaults(preferences, prefer
         branch.setComplexValue(name, Ci.nsISupportsString, str);
         break;
     }
   }
 }
 exports.setDefaults = setDefaults;
 
 // dynamically injects inline options into about:addons page at runtime
+// NOTE: on Firefox Desktop the about:addons page is a xul page document,
+// on Firefox for Android the about:addons page is an xhtml page, to support both
+// the XUL xml namespace have to be enforced.
 function injectOptions({ preferences, preferencesBranch, document, parent, id }) {
   for (let { name, type, hidden, title, description, label, options, on, off } of preferences) {
-
     if (hidden) {
       continue;
     }
 
-    let setting = document.createElement('setting');
+    let setting = document.createElementNS(XUL_NS, 'setting');
     setting.setAttribute('pref-name', name);
     setting.setAttribute('data-jetpack-id', id);
     setting.setAttribute('pref', 'extensions.' + preferencesBranch + '.' + name);
     setting.setAttribute('type', type);
     setting.setAttribute('title', title);
     if (description)
       setting.setAttribute('desc', description);
 
     if (type === 'file' || type === 'directory') {
       setting.setAttribute('fullpath', 'true');
     }
     else if (type === 'control') {
-      let button = document.createElement('button');
+      let button = document.createElementNS(XUL_NS, 'button');
       button.setAttribute('pref-name', name);
       button.setAttribute('data-jetpack-id', id);
       button.setAttribute('label', label);
-      button.setAttribute('oncommand', "Services.obs.notifyObservers(null, '" +
-                                        id + "-cmdPressed', '" + name + "');");
+      button.addEventListener('command', function() {
+        Services.obs.notifyObservers(null, `${id}-cmdPressed`, name);
+      }, true);
       setting.appendChild(button);
     }
     else if (type === 'boolint') {
       setting.setAttribute('on', on);
       setting.setAttribute('off', off);
     }
     else if (type === 'menulist') {
-      let menulist = document.createElement('menulist');
-      let menupopup = document.createElement('menupopup');
+      let menulist = document.createElementNS(XUL_NS, 'menulist');
+      let menupopup = document.createElementNS(XUL_NS, 'menupopup');
       for (let { value, label } of options) {
-        let menuitem = document.createElement('menuitem');
+        let menuitem = document.createElementNS(XUL_NS, 'menuitem');
         menuitem.setAttribute('value', value);
         menuitem.setAttribute('label', label);
         menupopup.appendChild(menuitem);
       }
       menulist.appendChild(menupopup);
       setting.appendChild(menulist);
     }
     else if (type === 'radio') {
-      let radiogroup = document.createElement('radiogroup');
+      let radiogroup = document.createElementNS(XUL_NS, 'radiogroup');
       for (let { value, label } of options) {
-        let radio = document.createElement('radio');
+        let radio = document.createElementNS(XUL_NS, 'radio');
         radio.setAttribute('value', value);
         radio.setAttribute('label', label);
         radiogroup.appendChild(radio);
       }
       setting.appendChild(radiogroup);
     }
 
     parent.appendChild(setting);