Bug 1457252 - Ensure l10n and initialization are done before sizing the subdialog. r?gijs
MozReview-Commit-ID: 8YMpRuzz04A
--- a/browser/components/preferences/applicationManager.js
+++ b/browser/components/preferences/applicationManager.js
@@ -2,17 +2,21 @@
// 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/.
/* import-globals-from in-content/main.js */
var gAppManagerDialog = {
_removed: [],
- init: function appManager_init() {
+ onLoad() {
+ document.mozSubdialogReady = this.init();
+ },
+
+ async init() {
this.handlerInfo = window.arguments[0];
Services.scriptloader.loadSubScript("chrome://browser/content/preferences/in-content/main.js",
window);
var pane = gMainPane;
const appDescElem = document.getElementById("appDescription");
if (this.handlerInfo.type == TYPE_MAYBE_FEED) {
document.l10n.setAttributes(appDescElem, "app-manager-handle-webfeeds");
@@ -35,17 +39,25 @@ var gAppManagerDialog = {
app.QueryInterface(Ci.nsIHandlerApp);
var item = list.appendItem(app.name);
item.setAttribute("image", pane._getIconURLForHandlerApp(app));
item.className = "listitem-iconic";
item.app = app;
}
+ // Triggers onSelect which populates label
list.selectedIndex = 0;
+
+ // We want to block on those elements being localized because the
+ // result will impact the size of the subdialog.
+ await document.l10n.translateElements([
+ appDescElem,
+ document.getElementById("appType")
+ ]);
},
onOK: function appManager_onOK() {
if (!this._removed.length) {
// return early to avoid calling the |store| method.
return;
}
--- a/browser/components/preferences/applicationManager.xul
+++ b/browser/components/preferences/applicationManager.xul
@@ -3,17 +3,17 @@
- 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/. -->
<?xml-stylesheet href="chrome://global/skin/"?>
<dialog id="appManager"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
buttons="accept,cancel"
- onload="gAppManagerDialog.init();"
+ onload="gAppManagerDialog.onLoad();"
ondialogaccept="gAppManagerDialog.onOK();"
ondialogcancel="gAppManagerDialog.onCancel();"
data-l10n-id="app-manager-window"
data-l10n-attrs="title, style"
persist="screenX screenY">
<link rel="localization" href="browser/preferences/applicationManager.ftl"/>
<script type="application/javascript" src="chrome://global/content/l10n.js"></script>
@@ -30,27 +30,25 @@
oncommand="gAppManagerDialog.remove();"
disabled="true"/>
</commandset>
<keyset id="appManagerKeyset">
<key id="delete" keycode="VK_DELETE" command="cmd_remove"/>
</keyset>
- <!-- The   character is required here to calculate the dialog height -->
- <description id="appDescription"> </description>
+ <description id="appDescription"/>
<separator class="thin"/>
<hbox flex="1">
<listbox id="appList" onselect="gAppManagerDialog.onSelect();" flex="1"/>
<vbox>
<button id="remove"
data-l10n-id="app-manager-remove"
command="cmd_remove"/>
<spacer flex="1"/>
</vbox>
</hbox>
<vbox id="appDetails">
<separator class="thin"/>
- <!-- The   character is required here to calculate the dialog height -->
- <label id="appType"> </label>
+ <label id="appType"/>
<textbox id="appLocation" readonly="true" class="plain"/>
</vbox>
</dialog>
--- a/browser/components/preferences/blocklists.js
+++ b/browser/components/preferences/blocklists.js
@@ -164,12 +164,8 @@ var gBlocklistManager = {
this._tree.view = this._view;
},
_getActiveList() {
let trackingTable = Services.prefs.getCharPref(TRACKING_TABLE_PREF);
return trackingTable.includes(CONTENT_LIST_ID) ? CONTENT_LIST_ID : BASE_LIST_ID;
}
};
-
-function initWithParams(params) {
- gBlocklistManager.init(params);
-}
--- a/browser/components/preferences/clearSiteData.js
+++ b/browser/components/preferences/clearSiteData.js
@@ -7,32 +7,44 @@ ChromeUtils.import("resource://gre/modul
ChromeUtils.import("resource://gre/modules/DownloadUtils.jsm");
ChromeUtils.import("resource:///modules/SiteDataManager.jsm");
var gClearSiteDataDialog = {
_clearSiteDataCheckbox: null,
_clearCacheCheckbox: null,
_clearButton: null,
- init() {
+ onLoad() {
+ document.mozSubdialogReady = this.init();
+ },
+
+ async init() {
this._clearButton = document.getElementById("clearButton");
this._cancelButton = document.getElementById("cancelButton");
this._clearSiteDataCheckbox = document.getElementById("clearSiteData");
this._clearCacheCheckbox = document.getElementById("clearCache");
- SiteDataManager.getTotalUsage().then(bytes => {
- let [amount, unit] = DownloadUtils.convertByteUnits(bytes);
- document.l10n.setAttributes(this._clearSiteDataCheckbox,
- "clear-site-data-cookies-with-data", { amount, unit });
- });
- SiteDataManager.getCacheSize().then(bytes => {
- let [amount, unit] = DownloadUtils.convertByteUnits(bytes);
- document.l10n.setAttributes(this._clearCacheCheckbox,
- "clear-site-data-cache-with-data", { amount, unit });
- });
+ // We'll block init() on this because the result values may impact
+ // subdialog sizing.
+ await Promise.all([
+ SiteDataManager.getTotalUsage().then(bytes => {
+ let [amount, unit] = DownloadUtils.convertByteUnits(bytes);
+ document.l10n.setAttributes(this._clearSiteDataCheckbox,
+ "clear-site-data-cookies-with-data", { amount, unit });
+ }),
+ SiteDataManager.getCacheSize().then(bytes => {
+ let [amount, unit] = DownloadUtils.convertByteUnits(bytes);
+ document.l10n.setAttributes(this._clearCacheCheckbox,
+ "clear-site-data-cache-with-data", { amount, unit });
+ }),
+ ]);
+ await document.l10n.translateElements([
+ this._clearCacheCheckbox,
+ this._clearSiteDataCheckbox
+ ]);
window.addEventListener("keypress", this.onWindowKeyPress);
this._cancelButton.addEventListener("command", window.close);
this._clearButton.addEventListener("command", () => this.onClear());
this._clearSiteDataCheckbox.addEventListener("command", e => this.onCheckboxCommand(e));
this._clearCacheCheckbox.addEventListener("command", e => this.onCheckboxCommand(e));
@@ -68,9 +80,9 @@ var gClearSiteDataDialog = {
}
if (allowed) {
window.close();
}
},
};
-window.addEventListener("load", () => gClearSiteDataDialog.init());
+window.addEventListener("load", () => gClearSiteDataDialog.onLoad());
--- a/browser/components/preferences/in-content/subdialogs.js
+++ b/browser/components/preferences/in-content/subdialogs.js
@@ -252,21 +252,35 @@ SubDialog.prototype = {
// XXX: Hack to make focus during the dialog's load functions work. Make the element visible
// sooner in DOMContentLoaded but mostly invisible instead of changing visibility just before
// the dialog's load event.
this._overlay.style.visibility = "visible";
this._overlay.style.opacity = "0.01";
},
- _onLoad(aEvent) {
+ async _onLoad(aEvent) {
if (aEvent.target.contentWindow.location == "about:blank") {
return;
}
+ // In order to properly calculate the sizing of the subdialog, we need to
+ // ensure that all of the l10n is done.
+ if (aEvent.target.contentDocument.l10n) {
+ await aEvent.target.contentDocument.l10n.ready;
+ }
+
+ // Some subdialogs may want to perform additional, asynchronous steps during initializations.
+ //
+ // In that case, we expect them to define a Promise which will delay measuring
+ // until the promise is fulfilled.
+ if (aEvent.target.contentDocument.mozSubdialogReady) {
+ await aEvent.target.contentDocument.mozSubdialogReady;
+ }
+
// Do this on load to wait for the CSS to load and apply before calculating the size.
let docEl = this._frame.contentDocument.documentElement;
let groupBoxTitle = document.getAnonymousElementByAttribute(this._box, "class", "groupbox-title");
let groupBoxTitleHeight = groupBoxTitle.clientHeight +
parseFloat(getComputedStyle(groupBoxTitle).borderBottomWidth);
let groupBoxBody = document.getAnonymousElementByAttribute(this._box, "class", "groupbox-body");