diff --git a/.eslintignore b/.eslintignore
index 5a047f0bd273..f2808fd85fda 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -335,9 +335,6 @@ toolkit/components/reader/JSDOMParser.js
# Uses preprocessing
toolkit/components/reader/Readerable.jsm
-# Should be going away soon
-toolkit/content/widgets/wizard.xml
-
# Uses preprocessing
toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js
toolkit/modules/AppConstants.jsm
diff --git a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/wizard.py b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/wizard.py
index cc1215078a0b..afacc8e95dec 100644
--- a/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/wizard.py
+++ b/testing/marionette/puppeteer/firefox/firefox_puppeteer/ui/update_wizard/wizard.py
@@ -50,7 +50,7 @@ class Wizard(UIBaseLib):
@property
def _buttons(self):
- return self.element.find_element(By.ANON_ATTRIBUTE, {'anonid': 'Buttons'})
+ return self.element.get_property('_wizardButtons')
@property
def cancel_button(self):
diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn
index 7837239c4264..565572a85102 100644
--- a/toolkit/content/jar.mn
+++ b/toolkit/content/jar.mn
@@ -75,7 +75,6 @@ toolkit.jar:
* content/global/bindings/textbox.xml (widgets/textbox.xml)
content/global/bindings/timekeeper.js (widgets/timekeeper.js)
content/global/bindings/timepicker.js (widgets/timepicker.js)
- content/global/bindings/wizard.xml (widgets/wizard.xml)
content/global/elements/autocomplete-popup.js (widgets/autocomplete-popup.js)
content/global/elements/autocomplete-richlistitem.js (widgets/autocomplete-richlistitem.js)
content/global/elements/browser-custom-element.js (widgets/browser-custom-element.js)
diff --git a/toolkit/content/widgets/wizard.js b/toolkit/content/widgets/wizard.js
index bec7c7dfaa71..b8b1e3df63c4 100644
--- a/toolkit/content/widgets/wizard.js
+++ b/toolkit/content/widgets/wizard.js
@@ -8,14 +8,385 @@
// a block to prevent accidentally leaking globals onto `window`.
{
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
+const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
const kDTDs = [ "chrome://global/locale/wizard.dtd" ];
+class MozWizard extends MozXULElement {
+ constructor() {
+ super();
+
+ this._accessMethod = null;
+ this._currentPage = null;
+ this._canAdvance = true;
+ this._canRewind = false;
+ this._hasLoaded = false;
+ this._pageStack = [];
+
+ this._bundle =
+ Services.strings.createBundle("chrome://global/locale/wizard.properties");
+
+ this.addEventListener("keypress", (event) => {
+ if (event.keyCode == KeyEvent.DOM_VK_RETURN) {
+ this._hitEnter(event);
+ } else if (event.keyCode == KeyEvent.DOM_VK_ESCAPE && !event.defaultPrevented) {
+ this.cancel();
+ }
+ }, { mozSystemGroup: true });
+
+ this.attachShadow({ mode: "open" }).appendChild(
+ MozXULElement.parseXULToFragment(`
+
+
+
+
+
+
+
+ `));
+ this.initializeAttributeInheritance();
+
+ this._deck = this.shadowRoot.querySelector(".wizard-page-box");
+ this._wizardButtons = this.shadowRoot.querySelector(".wizard-buttons");
+
+ this._wizardHeader = this.shadowRoot.querySelector(".wizard-header");
+ this._wizardHeader.appendChild(
+ MozXULElement.parseXULToFragment(AppConstants.platform == "macosx" ?
+ `` :
+ ``
+ )
+ );
+ }
+
+ static get inheritedAttributes() {
+ return {
+ ".wizard-buttons": "pagestep,firstpage,lastpage",
+ };
+ }
+
+ connectedCallback() {
+ if (this.delayConnectedCallback()) {
+ return;
+ }
+
+ this.pageCount = this.wizardPages.length;
+
+ this._initPages();
+ this.advance(); // start off on the first page
+
+ window.addEventListener("close", (event) => {
+ if (document.documentElement.cancel()) {
+ event.preventDefault();
+ }
+ });
+
+ // Give focus to the first focusable element in the wizard, do it after
+ // onload completes, see bug 103197.
+ window.addEventListener("load", () => window.setTimeout(() => {
+ document.documentElement._hasLoaded = true;
+ if (!document.commandDispatcher.focusedElement) {
+ document.commandDispatcher.advanceFocusIntoSubtree(this);
+ }
+ try {
+ let button = document.documentElement._wizardButtons.defaultButton;
+ if (button) {
+ window.notifyDefaultButtonLoaded(button);
+ }
+ } catch (e) {}
+ }, 0));
+ }
+
+ set title(val) {
+ return document.title = val;
+ }
+
+ get title() {
+ return document.title;
+ }
+
+ set canAdvance(val) {
+ this.getButton("next").disabled = !val;
+ return this._canAdvance = val;
+ }
+
+ get canAdvance() {
+ return this._canAdvance;
+ }
+
+ set canRewind(val) {
+ this.getButton("back").disabled = !val;
+ return this._canRewind = val;
+ }
+
+ get canRewind() {
+ return this._canRewind;
+ }
+
+ get pageStep() {
+ return this._pageStack.length;
+ }
+
+ get wizardPages() {
+ const xulns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+ return this.getElementsByTagNameNS(xulns, "wizardpage");
+ }
+
+ set currentPage(val) {
+ if (!val)
+ return val;
+
+ this._currentPage = val;
+
+ // Setting this attribute allows wizard's clients to dynamically
+ // change the styles of each page based on purpose of the page.
+ this.setAttribute("currentpageid", val.pageid);
+ if (this.onFirstPage) {
+ this.canRewind = false;
+ this.setAttribute("firstpage", "true");
+ if (AppConstants.platform == "linux") {
+ this.getButton("back").setAttribute("hidden", "true");
+ }
+ } else {
+ this.canRewind = true;
+ this.setAttribute("firstpage", "false");
+ if (AppConstants.platform == "linux") {
+ this.getButton("back").setAttribute("hidden", "false");
+ }
+ }
+
+ if (this.onLastPage) {
+ this.canAdvance = true;
+ this.setAttribute("lastpage", "true");
+ } else {
+ this.setAttribute("lastpage", "false");
+ }
+
+ this._deck.setAttribute("selectedIndex", val.pageIndex);
+ this._advanceFocusToPage(val);
+
+ this._adjustWizardHeader();
+ this._wizardButtons.onPageChange();
+
+ this._fireEvent(val, "pageshow");
+
+ return val;
+ }
+
+ get currentPage() {
+ return this._currentPage;
+ }
+
+ set pageIndex(val) {
+ if (val < 0 || val >= this.pageCount)
+ return val;
+
+ var page = this.wizardPages[val];
+ this._pageStack[this._pageStack.length - 1] = page;
+ this.currentPage = page;
+
+ return val;
+ }
+
+ get pageIndex() {
+ return this._currentPage ? this._currentPage.pageIndex : -1;
+ }
+
+ get onFirstPage() {
+ return this._pageStack.length == 1;
+ }
+
+ get onLastPage() {
+ var cp = this.currentPage;
+ return cp && ((this._accessMethod == "sequential" && cp.pageIndex == this.pageCount - 1) ||
+ (this._accessMethod == "random" && cp.next == ""));
+ }
+
+ getButton(aDlgType) {
+ return this._wizardButtons.getButton(aDlgType);
+ }
+
+ getPageById(aPageId) {
+ var els = this.getElementsByAttribute("pageid", aPageId);
+ return els.item(0);
+ }
+
+ extra1() {
+ if (this.currentPage)
+ this._fireEvent(this.currentPage, "extra1");
+ }
+
+ extra2() {
+ if (this.currentPage)
+ this._fireEvent(this.currentPage, "extra2");
+ }
+
+ rewind() {
+ if (!this.canRewind)
+ return;
+
+ if (this.currentPage && !this._fireEvent(this.currentPage, "pagehide"))
+ return;
+
+ if (this.currentPage && !this._fireEvent(this.currentPage, "pagerewound"))
+ return;
+
+ if (!this._fireEvent(this, "wizardback"))
+ return;
+
+ this._pageStack.pop();
+ this.currentPage = this._pageStack[this._pageStack.length - 1];
+ this.setAttribute("pagestep", this._pageStack.length);
+ }
+
+ advance(aPageId) {
+ if (!this.canAdvance)
+ return;
+
+ if (this.currentPage && !this._fireEvent(this.currentPage, "pagehide"))
+ return;
+
+ if (this.currentPage && !this._fireEvent(this.currentPage, "pageadvanced"))
+ return;
+
+ if (this.onLastPage && !aPageId) {
+ if (this._fireEvent(this, "wizardfinish"))
+ window.setTimeout(function() { window.close(); }, 1);
+ } else {
+ if (!this._fireEvent(this, "wizardnext"))
+ return;
+
+ let page;
+ if (aPageId) {
+ page = this.getPageById(aPageId);
+ } else if (this.currentPage) {
+ if (this._accessMethod == "random") {
+ page = this.getPageById(this.currentPage.next);
+ } else {
+ page = this.wizardPages[this.currentPage.pageIndex + 1];
+ }
+ } else {
+ page = this.wizardPages[0];
+ }
+
+ if (page) {
+ this._pageStack.push(page);
+ this.setAttribute("pagestep", this._pageStack.length);
+
+ this.currentPage = page;
+ }
+ }
+ }
+
+ goTo(aPageId) {
+ var page = this.getPageById(aPageId);
+ if (page) {
+ this._pageStack[this._pageStack.length - 1] = page;
+ this.currentPage = page;
+ }
+ }
+
+ cancel() {
+ if (!this._fireEvent(this, "wizardcancel"))
+ return true;
+
+ window.close();
+ window.setTimeout(function() { window.close(); }, 1);
+ return false;
+ }
+
+ _advanceFocusToPage(aPage) {
+ if (!this._hasLoaded)
+ return;
+
+ // XXX: it'd be correct to advance focus into the panel, however we can't do
+ // it until bug 1558990 is fixed, so moving the focus into a wizard itsef
+ // as a workaround - it's same behavior but less optimal.
+ document.commandDispatcher.advanceFocusIntoSubtree(this);
+
+ // if advanceFocusIntoSubtree tries to focus one of our
+ // dialog buttons, then remove it and put it on the root
+ var focused = document.commandDispatcher.focusedElement;
+ if (focused && focused.hasAttribute("dlgtype"))
+ this.focus();
+ }
+
+ _initPages() {
+ var meth = "sequential";
+ var pages = this.wizardPages;
+ for (var i = 0; i < pages.length; ++i) {
+ var page = pages[i];
+ page.pageIndex = i;
+ if (page.next != "")
+ meth = "random";
+ }
+ this._accessMethod = meth;
+ }
+
+ _adjustWizardHeader() {
+ var label = this.currentPage.getAttribute("label");
+ if (!label && this.onFirstPage && this._bundle) {
+ if (AppConstants.platform == "macosx") {
+ label = this._bundle.GetStringFromName("default-first-title-mac");
+ } else {
+ label = this._bundle.formatStringFromName("default-first-title", [this.title]);
+ }
+ } else if (!label && this.onLastPage && this._bundle) {
+ if (AppConstants.platform == "macosx") {
+ label = this._bundle.GetStringFromName("default-last-title-mac");
+ } else {
+ label = this._bundle.formatStringFromName("default-last-title", [this.title]);
+ }
+ }
+ this._wizardHeader.
+ querySelector(".wizard-header-label").textContent = label;
+ let headerDescEl =
+ this._wizardHeader.querySelector(".wizard-header-description");
+ if (headerDescEl) {
+ headerDescEl.textContent =
+ this.currentPage.getAttribute("description");
+ }
+ }
+
+ _hitEnter(evt) {
+ if (!evt.defaultPrevented)
+ this.advance();
+ }
+
+ _fireEvent(aTarget, aType) {
+ var event = document.createEvent("Events");
+ event.initEvent(aType, true, true);
+
+ // handle dom event handlers
+ return aTarget.dispatchEvent(event);
+ }
+}
+
+customElements.define("wizard", MozWizard);
+
class MozWizardPage extends MozXULElement {
constructor() {
super();
this.pageIndex = -1;
}
+ connectedCallback() {
+ this.setAttribute("slot", "wizardpage");
+ }
get pageid() {
return this.getAttribute("pageid");
}
diff --git a/toolkit/content/widgets/wizard.xml b/toolkit/content/widgets/wizard.xml
deleted file mode 100644
index ad40e7445b6d..000000000000
--- a/toolkit/content/widgets/wizard.xml
+++ /dev/null
@@ -1,428 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
- null
- null
- null
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- = this.pageCount)
- return val;
-
- var page = this.wizardPages[val];
- this._pageStack[this._pageStack.length-1] = page;
- this.currentPage = page;
-
- return val;
- ]]>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- // see bug 63370 for details
- this._bundle = Cc["@mozilla.org/intl/stringbundle;1"]
- .getService(Ci.nsIStringBundleService)
- .createBundle("chrome://global/locale/wizard.properties");
- } catch (e) {
- // This fails in remote XUL, which has to provide titles for all pages
- // see bug 142502
- }
-
- // get anonymous content references
- this._wizardHeader = document.getAnonymousElementByAttribute(this, "anonid", "Header");
-
- this._wizardHeader.appendChild(
- MozXULElement.parseXULToFragment(/Mac/.test(navigator.platform) ?
- `` :
- ``
- )
- );
-
- this._wizardButtons = document.getAnonymousElementByAttribute(this, "anonid", "Buttons");
- customElements.upgrade(this._wizardButtons);
-
- this._deck = document.getAnonymousElementByAttribute(this, "anonid", "Deck");
-
- this._initPages();
-
- window.addEventListener("close", (event) => {
- if (document.documentElement.cancel()) {
- event.preventDefault();
- }
- });
-
- // start off on the first page
- this.pageCount = this.wizardPages.length;
- this.advance();
-
- // give focus to the first focusable element in the dialog
- window.addEventListener("load", this._setInitialFocus);
- ]]>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- if (!event.defaultPrevented)
- this.cancel();
-
-
-
-
diff --git a/toolkit/content/xul.css b/toolkit/content/xul.css
index f9b3b7f1b334..98cd83975d0a 100644
--- a/toolkit/content/xul.css
+++ b/toolkit/content/xul.css
@@ -588,7 +588,6 @@ page {
wizard,
wizard:root /* override :root from above */ {
- -moz-binding: url("chrome://global/content/bindings/wizard.xml#wizard");
-moz-box-orient: vertical;
width: 40em;
height: 30em;