Bug 602682 - Sync UI: Implement easy setup. r=mconnor a=blocking-beta8

This adds a wizard page to the Existing Account flow for receiving credentials from an already set up device.
This commit is contained in:
Philipp von Weitershausen 2010-12-09 18:28:25 -08:00
parent 50cdb1c571
commit c1d7e98ec5
6 changed files with 294 additions and 170 deletions

View File

@ -49,8 +49,8 @@ const INTRO_PAGE = 0;
const NEW_ACCOUNT_START_PAGE = 1;
const NEW_ACCOUNT_PP_PAGE = 2;
const NEW_ACCOUNT_CAPTCHA_PAGE = 3;
const EXISTING_ACCOUNT_LOGIN_PAGE = 4;
const EXISTING_ACCOUNT_PP_PAGE = 5;
const EXISTING_ACCOUNT_CONNECT_PAGE = 4;
const EXISTING_ACCOUNT_LOGIN_PAGE = 5;
const OPTIONS_PAGE = 6;
const OPTIONS_CONFIRM_PAGE = 7;
const SETUP_SUCCESS_PAGE = 8;
@ -78,9 +78,8 @@ var gSyncSetup = {
get _usingMainServers() {
if (this._settingUpNew)
return document.getElementById("serverType").selectedItem.value == "main";
return document.getElementById("existingServerType").selectedItem.value == "main";
return document.getElementById("server").selectedIndex == 0;
return document.getElementById("existingServer").selectedIndex == 0;
},
init: function () {
@ -138,7 +137,7 @@ var gSyncSetup = {
useExistingAccount: function () {
this._settingUpNew = false;
this.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE;
this.wizard.pageIndex = EXISTING_ACCOUNT_CONNECT_PAGE;
},
onResetPassphrase: function () {
@ -156,31 +155,30 @@ var gSyncSetup = {
},
toggleLoginFeedback: function (stop) {
switch (this.wizard.pageIndex) {
case EXISTING_ACCOUNT_LOGIN_PAGE:
document.getElementById("connect-throbber").hidden = stop;
let feedback = document.getElementById("existingPasswordFeedbackRow");
if (stop) {
let success = Weave.Status.login == Weave.LOGIN_SUCCEEDED ||
Weave.Status.login == Weave.LOGIN_FAILED_INVALID_PASSPHRASE;
this._setFeedbackMessage(feedback, success, Weave.Status.login);
}
else
this._setFeedbackMessage(feedback, true);
break;
case EXISTING_ACCOUNT_PP_PAGE:
document.getElementById("passphrase-throbber").hidden = stop;
feedback = document.getElementById("existingPassphraseFeedbackBox");
if (stop) {
let success = Weave.Status.login == Weave.LOGIN_SUCCEEDED;
this._setFeedbackMessage(feedback, success, Weave.Status.login);
document.getElementById("passphraseHelpBox").hidden = success;
}
else
this._setFeedbackMessage(feedback, true);
document.getElementById("login-throbber").hidden = stop;
let password = document.getElementById("existingPasswordFeedbackRow");
let server = document.getElementById("existingServerFeedbackRow");
let passphrase = document.getElementById("existingPassphraseFeedbackRow");
if (!stop || (Weave.Status.login == Weave.LOGIN_SUCCEEDED)) {
password.hidden = server.hidden = passphrase.hidden = true;
return;
}
let feedback;
switch (Weave.Status.login) {
case Weave.LOGIN_FAILED_NETWORK_ERROR:
case Weave.LOGIN_FAILED_SERVER_ERROR:
feedback = server;
break;
case Weave.LOGIN_FAILED_LOGIN_REJECTED:
feedback = password;
break;
case Weave.LOGIN_FAILED_INVALID_PASSPHRASE:
feedback = passphrase;
break;
}
this._setFeedbackMessage(feedback, false, Weave.Status.login);
},
setupInitialSync: function () {
@ -228,19 +226,19 @@ var gSyncSetup = {
case EXISTING_ACCOUNT_LOGIN_PAGE:
let hasUser = document.getElementById("existingAccountName").value != "";
let hasPass = document.getElementById("existingPassword").value != "";
if (hasUser && hasPass) {
let hasKey = Weave.Utils.isPassphrase(
document.getElementById("existingPassphrase").value);
if (hasUser && hasPass && hasKey) {
if (this._usingMainServers)
return true;
if (this._validateServer(document.getElementById("existingServerURL"), false))
if (this._validateServer(document.getElementById("existingServer"), false))
return true;
}
return false;
case EXISTING_ACCOUNT_PP_PAGE:
let el = document.getElementById("existingPassphrase");
return Weave.Utils.isPassphrase(el.value);
}
// we probably shouldn't get here
// Default, e.g. wizard's special page -1 etc.
return true;
},
@ -330,20 +328,26 @@ var gSyncSetup = {
break;
case NEW_ACCOUNT_START_PAGE:
this.wizard.getButton("extra1").hidden = false;
this.onServerChange();
// fall through
case EXISTING_ACCOUNT_LOGIN_PAGE:
this.wizard.getButton("next").hidden = false;
this.wizard.getButton("back").hidden = false;
this.onServerCommand();
this.wizard.canRewind = true;
this.checkFields();
break;
case EXISTING_ACCOUNT_CONNECT_PAGE:
this.wizard.getButton("next").hidden = false;
this.wizard.getButton("back").hidden = false;
this.wizard.getButton("extra1").hidden = false;
this.wizard.canRewind = true;
this.startEasySetup();
break;
case EXISTING_ACCOUNT_PP_PAGE:
case EXISTING_ACCOUNT_LOGIN_PAGE:
this.wizard.canRewind = true;
this.checkFields();
break;
case SETUP_SUCCESS_PAGE:
this.wizard.canRewind = false;
this.wizard.canAdvance = true;
this.wizard.getButton("back").hidden = true;
this.wizard.getButton("next").hidden = true;
this.wizard.getButton("cancel").hidden = true;
@ -435,21 +439,6 @@ var gSyncSetup = {
case EXISTING_ACCOUNT_LOGIN_PAGE:
Weave.Service.account = document.getElementById("existingAccountName").value;
Weave.Service.password = document.getElementById("existingPassword").value;
Weave.Service.passphrase = Weave.Utils.normalizePassphrase(
document.getElementById("existingPassphrase").value);
// verifyLogin() will likely return false because we probably don't
// have a passphrase yet (unless the user already entered it
// and hit the back button).
if (!Weave.Service.verifyLogin()
&& Weave.Status.login != Weave.LOGIN_FAILED_NO_PASSPHRASE
&& Weave.Status.login != Weave.LOGIN_FAILED_INVALID_PASSPHRASE) {
let feedback = document.getElementById("existingPasswordFeedbackRow");
this._setFeedbackMessage(feedback, false, Weave.Status.login);
return false;
}
break;
case EXISTING_ACCOUNT_PP_PAGE:
let pp = document.getElementById("existingPassphrase").value;
Weave.Service.passphrase = Weave.Utils.normalizePassphrase(pp);
if (Weave.Service.login())
@ -479,8 +468,9 @@ var gSyncSetup = {
case EXISTING_ACCOUNT_LOGIN_PAGE:
this.wizard.pageIndex = INTRO_PAGE;
return false;
case EXISTING_ACCOUNT_PP_PAGE: // no idea wtf is up here, but meh!
this.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE;
case EXISTING_ACCOUNT_CONNECT_PAGE:
this.abortEasySetup();
this.wizard.pageIndex = INTRO_PAGE;
return false;
case OPTIONS_CONFIRM_PAGE:
// Backing up from the confirmation page = resetting first sync to merge.
@ -528,6 +518,7 @@ var gSyncSetup = {
this.onWizardFinish();
return;
}
this.abortEasySetup();
this._handleNoScript(false);
Weave.Service.startOver();
},
@ -550,6 +541,64 @@ var gSyncSetup = {
return false;
},
startEasySetup: function () {
// Don't do anything if we have a client already (e.g. we went to
// Sync Options and just came back).
if (this._jpakeclient)
return;
let self = this;
this._jpakeclient = new Weave.JPAKEClient({
displayPIN: function displayPIN(pin) {
document.getElementById("easySetupPIN1").value = pin.slice(0, 4);
document.getElementById("easySetupPIN2").value = pin.slice(4, 8);
document.getElementById("easySetupPIN3").value = pin.slice(8);
},
onComplete: function onComplete(credentials) {
Weave.Service.account = credentials.account;
Weave.Service.password = credentials.password;
Weave.Service.passphrase = credentials.synckey;
Weave.Service.serverURL = credentials.serverURL;
self.wizard.pageIndex = SETUP_SUCCESS_PAGE;
},
onAbort: function onAbort(error) {
delete self._jpakeclient;
// No error means manual abort, e.g. wizard is aborted. Ignore.
if (!error)
return;
// Automatically go to manual setup if we couldn't acquire a channel.
if (error == Weave.JPAKE_ERROR_CHANNEL) {
self.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE;
return;
}
// Restart on all other errors.
self.startEasySetup();
}
});
this._jpakeclient.receiveNoPIN();
},
abortEasySetup: function () {
document.getElementById("easySetupPIN1").value = "";
document.getElementById("easySetupPIN2").value = "";
document.getElementById("easySetupPIN3").value = "";
if (!this._jpakeclient)
return;
this._jpakeclient.abort();
delete this._jpakeclient;
},
manualSetup: function () {
this.abortEasySetup();
this.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE;
},
// _handleNoScript is needed because it blocks the captcha. So we temporarily
// allow the necessary sites so that we can verify the user is in fact a human.
// This was done with the help of Giorgio (NoScript author). See bug 508112.
@ -577,23 +626,45 @@ var gSyncSetup = {
}
},
onServerChange: function () {
if (this.wizard.pageIndex == EXISTING_ACCOUNT_LOGIN_PAGE) {
if (this._usingMainServers)
Weave.Svc.Prefs.reset("serverURL");
document.getElementById("existingServerRow").hidden = this._usingMainServers;
this.checkFields();
return;
onExistingServerCommand: function () {
let control = document.getElementById("existingServer");
if (control.selectedIndex == 0) {
control.removeAttribute("editable");
Weave.Svc.Prefs.reset("serverURL");
} else {
control.setAttribute("editable", "true");
// Force a style flush to ensure that the binding is attached.
control.clientTop;
control.value = "";
control.inputField.focus();
}
document.getElementById("existingServerFeedbackRow").hidden = true;
this.checkFields();
},
document.getElementById("serverRow").hidden = this._usingMainServers;
onExistingServerInput: function () {
// Check custom server validity when the user stops typing for 1 second.
if (this._existingServerTimer)
window.clearTimeout(this._existingServerTimer);
this._existingServerTimer = window.setTimeout(function () {
gSyncSetup.checkFields();
}, 1000);
},
onServerCommand: function () {
document.getElementById("TOSRow").hidden = !this._usingMainServers;
let control = document.getElementById("server");
if (!this._usingMainServers) {
control.setAttribute("editable", "true");
// Force a style flush to ensure that the binding is attached.
control.clientTop;
control.value = "";
control.inputField.focus();
// checkServer() will call checkAccount() and checkFields().
this.checkServer();
return;
}
control.removeAttribute("editable");
Weave.Svc.Prefs.reset("serverURL");
this.checkAccount();
this.status.server = true;
@ -612,7 +683,7 @@ var gSyncSetup = {
checkServer: function () {
delete this._checkServerTimer;
let el = document.getElementById("weaveServerURL");
let el = document.getElementById("server");
let valid = false;
let feedback = document.getElementById("serverFeedbackRow");
let str = "";
@ -809,9 +880,9 @@ var gSyncSetup = {
_setFeedback: function (element, success, string) {
element.hidden = success || !string;
let class = success ? "success" : "error";
let image = element.firstChild.nextSibling.firstChild;
let image = element.getElementsByAttribute("class", "statusIcon")[0];
image.setAttribute("status", class);
let label = image.nextSibling;
let label = element.getElementsByAttribute("class", "status")[0];
label.value = string;
},

View File

@ -89,9 +89,11 @@
<separator class="groove"/>
<vbox align="center" flex="1">
<spacer flex="3"/>
<label value="&setup.haveAccount.label;" />
<spacer flex="1"/>
<button id="existingAccount"
class="accountChoiceButton"
label="&button.haveAccount.label;"
label="&button.connect.label;"
oncommand="gSyncSetup.useExistingAccount()"/>
<spacer flex="3"/>
</vbox>
@ -145,23 +147,19 @@
</hbox>
</row>
<row align="center">
<label control="serverType"
<label control="server"
value="&server.label;"/>
<menulist id="serverType" oncommand="gSyncSetup.onServerChange()">
<menulist id="server"
oncommand="gSyncSetup.onServerCommand()"
oninput="gSyncSetup.onServerInput()">
<menupopup>
<menuitem label="&serverType.main.label;"
value="main"/>
<menuitem label="&serverType.custom.label;"
<menuitem label="&serverType.custom2.label;"
value="custom"/>
</menupopup>
</menulist>
</row>
<row id="serverRow" hidden="true" align="center">
<label value="&signIn.serverURL.label;"
accesskey="&signIn.serverURL.accesskey;"
control="weaveServerURL"/>
<textbox id="weaveServerURL" oninput="gSyncSetup.onServerInput()"/>
</row>
<row id="serverFeedbackRow" align="center" hidden="true">
<spacer/>
<hbox>
@ -243,8 +241,43 @@
</vbox>
</wizardpage>
<wizardpage id="useExisting"
label="&setup.existingAccount.title.label;"
<wizardpage id="addDevice"
label="&addDevice.title.label;"
onextra1="gSyncSetup.onSyncOptions()"
onpageshow="gSyncSetup.onPageShow()">
<description>
&addDevice.setup.description.label;
<label class="text-link"
value="&addDevice.showMeHow.label;"
href="https://services.mozilla.com/sync/help/easy-setup"/>
</description>
<description>&addDevice.setup.enterCode.label;</description>
<spacer flex="1"/>
<vbox align="center" flex="1">
<textbox id="easySetupPIN1"
class="pin"
value=""
disabled="true"
/>
<textbox id="easySetupPIN2"
class="pin"
value=""
disabled="true"
/>
<textbox id="easySetupPIN3"
class="pin"
value=""
disabled="true"
/>
</vbox>
<spacer flex="3"/>
<label class="text-link"
value="&addDevice.dontHaveDevice.label;"
onclick="gSyncSetup.manualSetup();"/>
</wizardpage>
<wizardpage id="existingAccount"
label="&setup.signInPage.title.label;"
onextra1="gSyncSetup.onSyncOptions()"
onpageshow="gSyncSetup.onPageShow()">
<grid>
@ -253,42 +286,15 @@
<column class="inputColumn" flex="1"/>
</columns>
<rows>
<row align="center">
<label control="existingServerType"
value="&server.label;"/>
<menulist id="existingServerType" oncommand="gSyncSetup.onServerChange()">
<menupopup>
<menuitem label="&serverType.main.label;"
value="main"/>
<menuitem label="&serverType.custom.label;"
value="custom"/>
</menupopup>
</menulist>
</row>
<row id="existingServerRow" hidden="true" align="center">
<label id="existingServerURLLabel"
value="&signIn.serverURL.label;"
accesskey="&signIn.serverURL.accesskey;"
control="existingServerURL"/>
<textbox id="existingServerURL"
onchange="gSyncSetup.checkFields(event)"/>
</row>
<row id="existingAccountRow" align="center">
<label id="existingAccountLabel"
value="&signIn.account.label;"
accesskey="&signIn.account.accesskey;"
value="&signIn.account2.label;"
accesskey="&signIn.account2.accesskey;"
control="existingAccount"/>
<textbox id="existingAccountName"
oninput="gSyncSetup.checkFields(event)"
onchange="gSyncSetup.checkFields(event)"/>
</row>
<row id="existingAccountFeedbackRow" align="center" hidden="true">
<spacer/>
<hbox>
<image class="statusIcon"/>
<label class="status" value=" "/>
</hbox>
</row>
<row id="existingPasswordRow" align="center">
<label id="existingPasswordLabel"
value="&signIn.password.label;"
@ -299,48 +305,76 @@
onkeyup="gSyncSetup.checkFields(event)"
onchange="gSyncSetup.checkFields(event)"/>
</row>
<row id="existingPasswordFeedbackRow" align="center" hidden="true">
<label class="text-link small" value="&resetPassword.label;"
onclick="gSyncUtils.resetPassword(); return false;"/>
<row id="existingPasswordFeedbackRow" align="center" hidden="true">
<spacer/>
<hbox>
<image class="statusIcon"/>
<label class="status" value=" "/>
<vbox>
<label class="status" value=" "/>
<label class="text-link"
value="&resetPassword.label;"
onclick="gSyncUtils.resetPassword(); return false;"/>
</vbox>
</hbox>
</row>
<row id="existingLoginFeedbackRow">
<row align="center">
<label control="existingServer"
value="&server.label;"/>
<menulist id="existingServer"
oncommand="gSyncSetup.onExistingServerCommand()"
oninput="gSyncSetup.onExistingServerInput()">
<menupopup>
<menuitem label="&serverType.main.label;"
value="main"/>
<menuitem label="&serverType.custom2.label;"
value="custom"/>
</menupopup>
</menulist>
</row>
<row id="existingServerFeedbackRow" align="center" hidden="true">
<spacer/>
<hbox id="connect-throbber" hidden="true">
<image/>
<label value="&connecting.label;"/>
</hbox>
<hbox>
<image class="statusIcon"/>
<vbox>
<label class="status" value=" "/>
</vbox>
</hbox>
</row>
</rows>
</grid>
</wizardpage>
<wizardpage id="existingPassphraseEntry"
label="&setup.existingSyncKeyPage.title;"
onextra1="gSyncSetup.onSyncOptions()"
onpageshow="gSyncSetup.onPageShow()">
<description>&setup.existingSyncKeyPage.description;</description>
<textbox id="existingPassphrase"
onkeyup="gSyncSetup.onPassphraseKeyUp(event)"
onchange="gSyncSetup.checkFields()"/>
<hbox id="passphrase-throbber" hidden="true">
<image/>
<label value="&verifying.label;"/>
</hbox>
<hbox align="left" id="existingPassphraseFeedbackBox">
<spacer/>
<hbox>
<image class="statusIcon"/>
<label class="status" value=" "/>
<groupbox>
<label id="existingPassphraseLabel"
value="&signIn.syncKey.label;"
accesskey="&signIn.syncKey.accesskey;"
control="existingPassphrase"/>
<textbox id="existingPassphrase"
onkeyup="gSyncSetup.onPassphraseKeyUp(event)"
onchange="gSyncSetup.checkFields()"/>
<hbox id="login-throbber" hidden="true">
<image/>
<label value="&verifying.label;"/>
</hbox>
</hbox>
<vbox class="small" id="passphraseHelpBox" hidden="true">
<description class="small">&existingSyncKeyHelp.description;</description>
<label class="text-link small" value="&lostSyncKey.label;"
onclick="gSyncUtils.resetPassphrase(); return false;"/>
<vbox align="left" id="existingPassphraseFeedbackRow" hidden="true">
<hbox>
<image class="statusIcon"/>
<vbox>
<label class="status" value=" "/>
<label class="text-link"
value="&lostSyncKey.label;"
onclick="gSyncUtils.resetPassphrase(); return false;"/>
</vbox>
</hbox>
</vbox>
</groupbox>
<vbox id="passphraseHelpBox">
<description>
&existingSyncKey.description;
<label class="text-link"
value="&addDevice.showMeHow.label;"
href="https://services.mozilla.com/sync/help/manual-setup"/>
</description>
</vbox>
</wizardpage>

View File

@ -4,7 +4,8 @@
<!ENTITY setup.pickSetupType.description "Welcome, if you've never used &syncBrand.fullName.label; before, you will need to create a new account.">
<!ENTITY button.createNewAccount.label "Create a New Account">
<!ENTITY button.haveAccount.label "I Have a &syncBrand.fullName.label; Account">
<!ENTITY setup.haveAccount.label "I already have a &syncBrand.fullName.label; account.">
<!ENTITY button.connect.label "Connect">
<!ENTITY setup.choicePage.title.label "Have you used &syncBrand.fullName.label; before?">
<!ENTITY setup.choicePage.new.label "I've never used &syncBrand.shortName.label; before">
@ -13,13 +14,13 @@
<!-- New Account AND Existing Account -->
<!ENTITY server.label "Server">
<!ENTITY serverType.main.label "&syncBrand.fullName.label; Server">
<!ENTITY serverType.custom.label "Use a custom server">
<!ENTITY signIn.account.label "Email Address / User Name">
<!ENTITY signIn.account.accesskey "E">
<!ENTITY serverType.custom2.label "Use a custom server">
<!ENTITY signIn.account2.label "Account">
<!ENTITY signIn.account2.accesskey "A">
<!ENTITY signIn.password.label "Password">
<!ENTITY signIn.password.accesskey "P">
<!ENTITY signIn.serverURL.label "Server URL">
<!ENTITY signIn.serverURL.accesskey "L">
<!ENTITY signIn.syncKey.label "Sync Key">
<!ENTITY signIn.syncKey.accesskey "K">
<!-- New Account Page 1: Basic Account Info -->
<!ENTITY setup.newAccountDetailsPage.title.label "Account Details">
@ -52,18 +53,19 @@
<!-- New Account Page 3: Captcha -->
<!ENTITY setup.captchaPage2.title.label "Please Confirm You're Not a Robot">
<!-- Existing Account Page 1: Add Device (incl. Add a Device dialog strings) -->
<!ENTITY addDevice.title.label "Add a Device">
<!ENTITY addDevice.showMeHow.label "Show me how.">
<!ENTITY addDevice.dontHaveDevice.label "I don't have the device with me">
<!ENTITY addDevice.setup.description.label "To activate, go to &syncBrand.shortName.label; Options on your other device and select &#x0022;Add a Device&#x0022;.">
<!ENTITY addDevice.setup.enterCode.label "Then, enter this code:">
<!-- Existing Account Page 1: Login -->
<!ENTITY setup.existingAccount.title.label "Enter Account Information">
<!ENTITY resetPassword.label "Reset Password">
<!ENTITY connecting.label "Connecting…">
<!-- Existing Account Page 2: Sync Key -->
<!ENTITY setup.existingSyncKeyPage.title "Please Enter Your Sync Key">
<!ENTITY setup.existingSyncKeyPage.description "The Sync Key was generated for you, or you entered your own, when you first signed up for &syncBrand.fullName.label;. It is not the same as your password.">
<!ENTITY existingSyncKeyHelp.description "You can find your saved Sync Key by going to your other computer and checking the Saved Passwords under Security. If you still cannot get the correct Sync Key, you can choose to reset it, but you will lose any data stored on the server.">
<!ENTITY lostSyncKey.label "I have lost my Sync Key">
<!-- Existing Account Page 2: Manual Login -->
<!ENTITY setup.signInPage.title.label "Sign In">
<!ENTITY existingSyncKey.description "You can get a copy of your Sync Key by going to &syncBrand.shortName.label; Options on your other device, and selecting &#x0022;My Sync Key&#x0022; under &#x0022;Manage Account&#x0022;.">
<!ENTITY verifying.label "Verifying…">
<!ENTITY resetPassword.label "Reset Password">
<!ENTITY lostSyncKey.label "I have lost my Sync Key">
<!-- Sync Options -->
<!ENTITY setup.optionsPage.title "Sync Options">

View File

@ -57,8 +57,8 @@ wizardpage {
}
/* Override the text-link style from global.css */
.text-link,
.text-link:focus {
description > .text-link,
description > .text-link:focus {
margin: 0px;
padding: 0px;
border: 0px;
@ -99,8 +99,14 @@ wizardpage {
-moz-margin-end: 2px
}
#connect-throbber image,
#passphrase-throbber image {
.pin {
font-size: 18pt;
width: 4em;
text-align: center;
}
#add-device-throbber > image,
#login-throbber > image {
list-style-image: url("chrome://global/skin/icons/loading_16.png");
}

View File

@ -57,14 +57,13 @@ wizardpage {
}
/* Override the text-link style from global.css */
.text-link,
.text-link:focus {
description > .text-link,
description > .text-link:focus {
margin: 0px;
padding: 0px;
border: 0px;
}
.success,
.error {
padding: 2px;
@ -99,8 +98,14 @@ wizardpage {
-moz-margin-end: 2px
}
#connect-throbber image,
#passphrase-throbber image {
.pin {
font-size: 18pt;
width: 4em;
text-align: center;
}
#add-device-throbber > image,
#login-throbber > image {
list-style-image: url("chrome://global/skin/icons/loading_16.png");
}

View File

@ -57,8 +57,8 @@ wizardpage {
}
/* Override the text-link style from global.css */
.text-link,
.text-link:focus {
description > .text-link,
description > .text-link:focus {
margin: 0px;
padding: 0px;
border: 0px;
@ -99,8 +99,14 @@ wizardpage {
-moz-margin-end: 2px
}
#connect-throbber image,
#passphrase-throbber image {
.pin {
font-size: 18pt;
width: 4em;
text-align: center;
}
#add-device-throbber > image,
#login-throbber > image {
list-style-image: url("chrome://global/skin/icons/loading_16.png");
}