Bug 514196: implement nsIPromptService2 [r=mark.finkle]
authorFabrice Desré <fabrice.desre@gmail.com>
Fri, 04 Sep 2009 13:40:03 -0400
changeset 65519 68f0e8507762d61010099a897c3bfe3395824caf
parent 65518 7407f1120e3de7c76bafc685444c8d973026cd26
child 65520 6c5d2ddde7d69f35205d719663bb0ad9d00496d0
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmark
bugs514196
Bug 514196: implement nsIPromptService2 [r=mark.finkle]
mobile/chrome/content/prompt/promptPassword.xul
mobile/components/promptService.js
--- a/mobile/chrome/content/prompt/promptPassword.xul
+++ b/mobile/chrome/content/prompt/promptPassword.xul
@@ -28,17 +28,17 @@
         <label value="&editfield1.label;"/>
         <textbox type="password" id="prompt-password-password"/>
       </row>
     </rows>
   </grid>
   
   <hbox id="prompt-password-checkbox-box" collapsed="true" align="center">
     <checkbox class="toggle-dark" id="prompt-password-checkbox"/>
-    <label id="prompt-password-checkbox-msg"/>
+    <description id="prompt-password-checkbox-msg"/>
   </hbox>
   <hbox pack="center" id="prompt-password-button-box">
     <button class="button-dark" label="&ok.label;"
             oncommand="document.getElementById('prompt-password-dialog').PromptHelper.closePassword(true)"/>
     <button class="button-dark" label="&cancel.label;"
             oncommand="document.getElementById('prompt-password-dialog').PromptHelper.closePassword(false)"/>
   </hbox>
 </dialog>
--- a/mobile/components/promptService.js
+++ b/mobile/components/promptService.js
@@ -49,76 +49,95 @@ promptService.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPromptService, Ci.nsIPromptService2]),
  
   // helper function do get the current document
   getDocument: function() {
     let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
     return wm.getMostRecentWindow("navigator:browser").document;
   },
  
-  // add a max-width style to prevent a element to grow larger 
+  // add a width style to prevent a element to grow larger 
   // than the screen width
   sizeElement: function(id, percent) {
     let elem = this.getDocument().getElementById(id);
     let screenW = this.getDocument().getElementById("main-window").getBoundingClientRect().width;
-    elem.style.maxWidth = screenW * percent / 100 + "px"
+    elem.style.width = screenW * percent / 100 + "px"
+  },
+  
+  // size the height of the scrollable message. this assumes the given element
+  // is a child of a scrollbox
+  sizeScrollableMsg: function(id, percent) {
+    let screenH = this.getDocument().getElementById("main-window").getBoundingClientRect().height;
+    let maxHeight = screenH * percent / 100;
+    
+    let elem = this.getDocument().getElementById(id);
+    let height = elem.getBoundingClientRect().height;
+    if (height > maxHeight)
+      height = maxHeight;
+    elem.parentNode.style.height = height + "px";
   },
   
   openDialog: function(src, params) {
     let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
     let browser = wm.getMostRecentWindow("navigator:browser");
     return browser.importDialog(src, params);
   },
   
   alert: function(aParent, aTitle, aText) {
     let dialog = this.openDialog("chrome://browser/content/prompt/alert.xul", null);
     let doc = this.getDocument();
     doc.getElementById("prompt-alert-title").value = aTitle;
     doc.getElementById("prompt-alert-message").appendChild(doc.createTextNode(aText));
     this.sizeElement("prompt-alert-message", 80);
+    this.sizeScrollableMsg("prompt-alert-message", 25);
     
     dialog.waitForClose();
   },
   
   alertCheck: function(aParent, aTitle, aText, aCheckMsg, aCheckState) {
     let dialog = this.openDialog("chrome://browser/content/prompt/alert.xul", aCheckState);
     let doc = this.getDocument();
     doc.getElementById("prompt-alert-title").value = aTitle;
     doc.getElementById("prompt-alert-message").appendChild(doc.createTextNode(aText));
     this.sizeElement("prompt-alert-message", 80);
+    this.sizeScrollableMsg("prompt-alert-message", 25);
+    
     doc.getElementById("prompt-alert-checkbox").checked = aCheckState.value;
     doc.getElementById("prompt-alert-checkbox-msg").value = aCheckMsg;
     this.sizeElement("prompt-alert-checkbox-msg", 50);
     doc.getElementById("prompt-alert-checkbox-box").removeAttribute("collapsed");
     
     dialog.waitForClose();
   },
   
   confirm: function(aParent, aTitle, aText) {
     var params = new Object();
     params.result = false;
     let doc = this.getDocument();
     let dialog = this.openDialog("chrome://browser/content/prompt/confirm.xul", params);
     doc.getElementById("prompt-confirm-title").value = aTitle;
     doc.getElementById("prompt-confirm-message").appendChild(doc.createTextNode(aText));
     this.sizeElement("prompt-confirm-message", 80);
+    this.sizeScrollableMsg("prompt-confirm-message", 25);
     
     dialog.waitForClose();
     return params.result;
   },
   
   confirmCheck: function(aParent, aTitle, aText, aCheckMsg, aCheckState) {
     var params = new Object();
     params.result = false;
     params.checkbox = aCheckState;
     let doc = this.getDocument();
     let dialog = this.openDialog("chrome://browser/content/prompt/confirm.xul", params);
     doc.getElementById("prompt-confirm-title").value = aTitle;
     doc.getElementById("prompt-confirm-message").appendChild(doc.createTextNode(aText));
     this.sizeElement("prompt-confirm-message", 80);
+    this.sizeScrollableMsg("prompt-confirm-message", 25);
+
     doc.getElementById("prompt-confirm-checkbox").checked = aCheckState.value;
     doc.getElementById("prompt-confirm-checkbox-msg").value = aCheckMsg;
     this.sizeElement("prompt-confirm-checkbox-msg", 50);
     doc.getElementById("prompt-confirm-checkbox-box").removeAttribute("collapsed");
     
     dialog.waitForClose();
     return params.result;
   },
@@ -173,16 +192,18 @@ promptService.prototype = {
     var params = new Object();
     params.result = false;
     params.checkbox = aCheckState;
     let doc = this.getDocument();
     let dialog = this.openDialog("chrome://browser/content/prompt/confirm.xul", params);
     doc.getElementById("prompt-confirm-title").value = aTitle;
     doc.getElementById("prompt-confirm-message").appendChild(doc.createTextNode(aText));
     this.sizeElement("prompt-confirm-message", 80);
+    this.sizeScrollableMsg("prompt-confirm-message", 25);
+
     doc.getElementById("prompt-confirm-checkbox").checked = aCheckState.value;
     doc.getElementById("prompt-confirm-checkbox-msg").value = aCheckMsg;
     this.sizeElement("prompt-confirm-checkbox-msg", 50);
     if (aCheckMsg) {
       doc.getElementById("prompt-confirm-checkbox-box").removeAttribute("collapsed");
     }
     
     let bbox = doc.getElementById("prompt-confirm-button-box");
@@ -240,16 +261,18 @@ promptService.prototype = {
     params.result = false;
     params.checkbox = aCheckState;
     params.value = aValue;
     let dialog = this.openDialog("chrome://browser/content/prompt/prompt.xul", params);
     let doc = this.getDocument();
     doc.getElementById("prompt-prompt-title").value = aTitle;
     doc.getElementById("prompt-prompt-message").appendChild(doc.createTextNode(aText));
     this.sizeElement("prompt-prompt-message", 80);
+    this.sizeScrollableMsg("prompt-prompt-message", 25);
+
     doc.getElementById("prompt-prompt-checkbox").checked = aCheckState.value;
     doc.getElementById("prompt-prompt-checkbox-msg").value = aCheckMsg;
     this.sizeElement("prompt-prompt-checkbox-msg", 50);
     doc.getElementById("prompt-prompt-textbox").value = aValue.value;
     if (aCheckMsg) {
       doc.getElementById("prompt-prompt-checkbox-box").removeAttribute("collapsed");
     }
     if (isPassword) {
@@ -274,47 +297,138 @@ promptService.prototype = {
     params.checkbox = aCheckState;
     params.user = aUsername;
     params.password = aPassword;
     let dialog = this.openDialog("chrome://browser/content/prompt/promptPassword.xul", params);
     let doc = this.getDocument();
     doc.getElementById("prompt-password-title").value = aTitle;
     doc.getElementById("prompt-password-message").appendChild(doc.createTextNode(aText));
     this.sizeElement("prompt-password-message", 80);
+    this.sizeScrollableMsg("prompt-password-message", 25);
     doc.getElementById("prompt-password-checkbox").checked = aCheckState.value;
-    doc.getElementById("prompt-password-checkbox-msg").value = aCheckMsg;
-    this.sizeElement("prompt-password-checkbox-msg", 50);
+    
     doc.getElementById("prompt-password-user").value = aUsername.value;
     doc.getElementById("prompt-password-password").value = aPassword.value;
     if (aCheckMsg) {
       doc.getElementById("prompt-password-checkbox-box").removeAttribute("collapsed");
+      doc.getElementById("prompt-password-checkbox-msg").appendChild(doc.createTextNode(aCheckMsg));
+      this.sizeElement("prompt-password-checkbox-msg", 50);
+      this.sizeElement("prompt-password-checkbox-box", 50);
     }
     
     dialog.waitForClose();
     return params.result;
   },
   
+  //
+  // JS port of http://mxr.mozilla.org/mozilla-central/source/embedding/components/windowwatcher/public/nsPromptUtils.h#89
+  //
+  getAuthHostPort: function(aChannel, aAuthInfo) {
+    let uri = aChannel.URI;
+    let res = { host: null, port: -1 };
+    if (aAuthInfo.flags & aAuthInfo.AUTH_PROXY) {
+      let proxy = aChannel.QueryInterface(Ci.nsIProxiedChannel);
+      res.host = proxy.proxyInfo.host;
+      res.port = proxy.proxyInfo.port;
+    } else {
+      res.host = uri.host;
+      res.port = uri.port;
+    }
+    return res;
+  },
+  
+  //
+  // JS port of http://mxr.mozilla.org/mozilla-central/source/embedding/components/windowwatcher/src/nsPrompt.cpp#388
+  //
+  makeDialogText: function(aChannel, aAuthInfo) {
+    let bundleService = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
+    let bundle = bundleService.createBundle("chrome://global/locale/prompts.properties");
+    
+    let HostPort = this.getAuthHostPort(aChannel, aAuthInfo);
+    let displayHost = HostPort.host;
+    let uri = aChannel.URI;
+    let scheme = uri.scheme;
+    let username = aAuthInfo.username;
+    let proxyAuth = (aAuthInfo.flags & aAuthInfo.AUTH_PROXY) != 0;
+    let realm = aAuthInfo.realm;
+    if (realm.length > 100) { // truncate and add ellipsis
+      let pref = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+      let ellipsis = pref.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
+      if (!ellipsis)
+        ellipsis = "...";
+      realm = realm.substring(0, 100) + ellipsis;
+    }
+    
+    if (HostPort.port != -1)
+      displayHost += ":" + HostPort.port;
+    
+    let text = null;
+    if (proxyAuth) {
+      text = "EnterLoginForProxy";
+    } else {
+      text = "EnterLoginForRealm";
+      displayHost = scheme + "://" + displayHost;
+    }
+    
+    let strings = [realm, displayHost];
+    let count = 2;
+    if (aAuthInfo.flags & aAuthInfo.ONLY_PASSWORD) {
+      text = "EnterPasswordFor";
+      strings[0] = username;
+    } else if (!proxyAuth && (realm.length == 0)) {
+      text = "EnterUserPasswordFor";
+      count = 1;
+      strings[0] = strings[1];
+    }
+    
+    return bundle.formatStringFromName(text, strings, count);
+  },
+  
   promptAuth: function(aParent, aChannel, aLevel, aAuthInfo, aCheckMsg, aCheckState) {
-    // TODO: implement this (bug 514196)
-    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+    let res = false;
+    
+    let defaultUser = aAuthInfo.username;
+    if ((aAuthInfo.flags & aAuthInfo.NEED_DOMAIN) && (aAuthInfo.domain.length > 0))
+      defaultUser = aAuthInfo.domain + "\\" + defaultUser;
+    
+    let username = { value: defaultUser };
+    let password = { value: aAuthInfo.password };
+    
+    let message = this.makeDialogText(aChannel, aAuthInfo);
+    let title = this.getLocaleString("PromptUsernameAndPassword2");
+    
+    if (aAuthInfo.flags & aAuthInfo.ONLY_PASSWORD) {
+      res = this.promptPassword(aParent, title, message, password, aCheckMsg, aCheckState);
+    } else {
+      res = this.promptUsernameAndPassword(aParent, title, message, username, password, aCheckMsg, aCheckState);
+    }
+    
+    if (res) {
+      aAuthInfo.username = username.value;
+      aAuthInfo.password = password.value;
+    }
+    
+    return res;
   },
   
   asyncPromptAuth: function(aParent, aChannel, aCallback, aContext, aLevel, aAuthInfo, aCheckMsg, aCheckState) {
+    // bug 514196
     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
   
   select: function(aParent, aTitle, aText, aCount, aSelectList, aOutSelection) {
     var params = new Object();
     params.result = false;
     params.selection = aOutSelection;
     let dialog = this.openDialog("chrome://browser/content/prompt/select.xul", params);
     let doc = this.getDocument();
     doc.getElementById("prompt-select-title").value = aTitle;
     doc.getElementById("prompt-select-message").appendChild(doc.createTextNode(aText));
     this.sizeElement("prompt-select-message", 80);
+    this.sizeScrollableMsg("prompt-select-message", 25);
     
     let list = doc.getElementById("prompt-select-list");
     for (let i = 0; i < aCount; i++) {
       let option = doc.createElementNS("http://www.w3.org/1999/xhtml", "option");
       option.appendChild(doc.createTextNode(aSelectList[i]));
       list.appendChild(option);
     }