converse-register: Consolidate validation and error reporting
This commit is contained in:
parent
7cfe81ea1f
commit
4063bbfc1c
@ -7,6 +7,8 @@
|
||||
- Remove `Login` and `Registration` tabs and consolidate into one panel.
|
||||
- Add validation message for an invalid JID in the login form.
|
||||
- Don't require `auto_login` to be `true` when using the API to log in.
|
||||
- Use CSS3 fade transitions to render various elements.
|
||||
- Consolidate error and validation reporting on the registration form.
|
||||
- #828 Add routing for the `#converse-login` and `#converse-register` URL
|
||||
fragments, which will render the registration and login forms respectively.
|
||||
|
||||
|
@ -1281,6 +1281,9 @@
|
||||
#converse-embedded-chat .error,
|
||||
#conversejs .error {
|
||||
color: #A53214; }
|
||||
#converse-embedded-chat .info,
|
||||
#conversejs .info {
|
||||
color: #1E9652; }
|
||||
#converse-embedded-chat .reg-feedback,
|
||||
#conversejs .reg-feedback {
|
||||
font-size: 85%;
|
||||
@ -1945,8 +1948,8 @@
|
||||
font-size: 90%;
|
||||
margin: 1.5em 0; }
|
||||
#conversejs #controlbox #converse-register .form-errors {
|
||||
color: red;
|
||||
display: none; }
|
||||
color: #A53214;
|
||||
margin: 1em 0; }
|
||||
#conversejs #controlbox #converse-register .provider-title {
|
||||
font-size: 20px;
|
||||
margin: 0; }
|
||||
|
@ -1281,6 +1281,9 @@
|
||||
#converse-embedded-chat .error,
|
||||
#conversejs .error {
|
||||
color: #A53214; }
|
||||
#converse-embedded-chat .info,
|
||||
#conversejs .info {
|
||||
color: #1E9652; }
|
||||
#converse-embedded-chat .reg-feedback,
|
||||
#conversejs .reg-feedback {
|
||||
font-size: 85%;
|
||||
@ -2033,8 +2036,8 @@ body {
|
||||
font-size: 90%;
|
||||
margin: 1.5em 0; }
|
||||
#conversejs #controlbox #converse-register .form-errors {
|
||||
color: red;
|
||||
display: none; }
|
||||
color: #A53214;
|
||||
margin: 1em 0; }
|
||||
#conversejs #controlbox #converse-register .provider-title {
|
||||
font-size: 26px;
|
||||
margin: 0; }
|
||||
@ -2401,6 +2404,11 @@ body {
|
||||
@media screen and (max-width: 480px) {
|
||||
#conversejs #controlbox .brand-heading-container .brand-heading {
|
||||
font-size: 400%; } }
|
||||
#conversejs #controlbox .controlbox-panes {
|
||||
background-color: white; }
|
||||
#conversejs #controlbox .controlbox-pane {
|
||||
height: -webkit-calc(100% - 63px);
|
||||
height: calc(100% - 63px); }
|
||||
#conversejs #controlbox.logged-out {
|
||||
opacity: 0;
|
||||
/* make things invisible upon start */
|
||||
@ -2422,6 +2430,8 @@ body {
|
||||
#conversejs #controlbox.logged-out .box-flyout .controlbox-head {
|
||||
background-color: white;
|
||||
height: 0; }
|
||||
#conversejs #controlbox.logged-out .box-flyout .controlbox-pane {
|
||||
height: auto; }
|
||||
#conversejs #controlbox .box-flyout {
|
||||
border: 0;
|
||||
min-width: 250px;
|
||||
@ -2459,10 +2469,6 @@ body {
|
||||
font-size: 18px; }
|
||||
#conversejs #controlbox #controlbox-tabs li a.current, #conversejs #controlbox #controlbox-tabs li a.current:hover {
|
||||
height: 63px; }
|
||||
#conversejs #controlbox .controlbox-panes {
|
||||
background-color: white; }
|
||||
#conversejs #controlbox .controlbox-pane {
|
||||
height: auto; }
|
||||
|
||||
#conversejs #converse-roster {
|
||||
text-align: left;
|
||||
|
@ -73,8 +73,8 @@
|
||||
margin: 1.5em 0;
|
||||
}
|
||||
.form-errors {
|
||||
color: red;
|
||||
display: none;
|
||||
color: $error-color;
|
||||
margin: 1em 0;
|
||||
}
|
||||
.provider-title {
|
||||
font-size: $font-size-huge;
|
||||
|
@ -152,6 +152,9 @@
|
||||
.error {
|
||||
color: $error-color;
|
||||
}
|
||||
.info {
|
||||
color: $info-color;
|
||||
}
|
||||
.reg-feedback {
|
||||
font-size: 85%;
|
||||
margin-bottom: 1em;
|
||||
|
@ -81,6 +81,7 @@ $light-background-color: #FCFDFD !default;
|
||||
$moderator-color: $dark-red !default;
|
||||
$online-color: $green !default;
|
||||
$error-color: $darkest-red !default;
|
||||
$info-color: $dark-green !default;
|
||||
|
||||
$button-border-radius: 5px !default;
|
||||
$chatbox-border-radius: 4px !default;
|
||||
|
@ -32,6 +32,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.controlbox-panes {
|
||||
background-color: white;
|
||||
}
|
||||
.controlbox-pane {
|
||||
@include calc(height, '100% - #{$controlbox-head-height}');
|
||||
}
|
||||
&.logged-out {
|
||||
@include fade-in;
|
||||
width: 100%;
|
||||
@ -41,6 +47,9 @@
|
||||
background-color: white;
|
||||
height: 0;
|
||||
}
|
||||
.controlbox-pane {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
.box-flyout {
|
||||
@ -93,11 +102,5 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.controlbox-panes {
|
||||
background-color: white;
|
||||
}
|
||||
.controlbox-pane {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -85,6 +85,7 @@ $light-background-color: #FCFDFD !default;
|
||||
$moderator-color: $red !default;
|
||||
$online-color: $green !default;
|
||||
$error-color: $darkest-red !default;
|
||||
$info-color: $dark-green !default;
|
||||
|
||||
$button-border-radius: 5px !default;
|
||||
$chatbox-border-radius: 0 !default;
|
||||
|
@ -100,7 +100,7 @@
|
||||
_converse.OPENED = 'opened';
|
||||
_converse.PREBIND = "prebind";
|
||||
|
||||
const PRETTY_CONNECTION_STATUS = {
|
||||
_converse.PRETTY_CONNECTION_STATUS = {
|
||||
0: 'ERROR',
|
||||
1: 'CONNECTING',
|
||||
2: 'CONNFAIL',
|
||||
@ -495,7 +495,7 @@
|
||||
* through various states while establishing or tearing down a
|
||||
* connection.
|
||||
*/
|
||||
_converse.log(`Status changed to: ${PRETTY_CONNECTION_STATUS[status]}`);
|
||||
_converse.log(`Status changed to: ${_converse.PRETTY_CONNECTION_STATUS[status]}`);
|
||||
if (status === Strophe.Status.CONNECTED || status === Strophe.Status.ATTACHED) {
|
||||
_converse.giveFeedback();
|
||||
// By default we always want to send out an initial presence stanza.
|
||||
|
@ -145,6 +145,11 @@
|
||||
const { _converse } = this,
|
||||
{ __ } = _converse;
|
||||
|
||||
_converse.PRETTY_CONNECTION_STATUS[Strophe.Status.REGIFAIL] = 'REGIFAIL';
|
||||
_converse.PRETTY_CONNECTION_STATUS[Strophe.Status.REGISTERED] = 'REGISTERED';
|
||||
_converse.PRETTY_CONNECTION_STATUS[Strophe.Status.CONFLICT] = 'CONFLICT';
|
||||
_converse.PRETTY_CONNECTION_STATUS[Strophe.Status.NOTACCEPTABLE] = 'NOTACCEPTABLE';
|
||||
|
||||
_converse.api.settings.update({
|
||||
allow_registration: true,
|
||||
domain_placeholder: __(" e.g. conversejs.org"), // Placeholder text shown in the domain input on the registration form
|
||||
@ -174,7 +179,7 @@
|
||||
className: 'controlbox-pane fade-in',
|
||||
events: {
|
||||
'submit form#converse-register': 'onProviderChosen',
|
||||
'click .button-cancel': 'cancelRegistration',
|
||||
'click .button-cancel': 'renderProviderChoiceForm',
|
||||
},
|
||||
|
||||
initialize (cfg) {
|
||||
@ -231,6 +236,9 @@
|
||||
const body = conn._proto._reqToData(req);
|
||||
if (!body) { return; }
|
||||
if (conn._proto._connect_cb(body) === Strophe.Status.CONNFAIL) {
|
||||
this.showValidationError(
|
||||
__("Sorry, we're unable to connect to your chosen provider.")
|
||||
);
|
||||
return false;
|
||||
}
|
||||
const register = body.getElementsByTagName("register");
|
||||
@ -240,12 +248,11 @@
|
||||
return false;
|
||||
}
|
||||
if (register.length === 0) {
|
||||
conn._changeConnectStatus(
|
||||
Strophe.Status.REGIFAIL,
|
||||
conn._changeConnectStatus(Strophe.Status.REGIFAIL);
|
||||
this.showValidationError(
|
||||
__("Sorry, the given provider does not support in "+
|
||||
"band account registration. Please try with a "+
|
||||
"different provider.")
|
||||
);
|
||||
"different provider."))
|
||||
return true;
|
||||
}
|
||||
// Send an IQ stanza to get all required data fields
|
||||
@ -266,12 +273,16 @@
|
||||
if (stanza.getAttribute("type") === "error") {
|
||||
_converse.connection._changeConnectStatus(
|
||||
Strophe.Status.REGIFAIL,
|
||||
__('Something went wrong while establishing a connection with "%1$s". Are you sure it exists?', this.domain)
|
||||
__('Something went wrong while establishing a connection with "%1$s".'+
|
||||
'Are you sure it exists?', this.domain)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (stanza.getElementsByTagName("query").length !== 1) {
|
||||
_converse.connection._changeConnectStatus(Strophe.Status.REGIFAIL, "unknown");
|
||||
_converse.connection._changeConnectStatus(
|
||||
Strophe.Status.REGIFAIL,
|
||||
"unknown"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
this.setFields(stanza);
|
||||
@ -331,7 +342,9 @@
|
||||
domain: Strophe.getDomainFromJid(domain_name),
|
||||
_registering: true
|
||||
});
|
||||
_converse.connection.connect(this.domain, "", this.onRegistering.bind(this));
|
||||
_converse.connection.connect(
|
||||
this.domain, "", this.onConnectStatusChanged.bind(this)
|
||||
);
|
||||
return false;
|
||||
},
|
||||
|
||||
@ -350,18 +363,18 @@
|
||||
|
||||
giveFeedback (message, klass) {
|
||||
let feedback = this.el.querySelector('.reg-feedback');
|
||||
if (_.isNull(feedback)) {
|
||||
if (!_.isNull(feedback)) {
|
||||
feedback.parentNode.removeChild(feedback);
|
||||
}
|
||||
const form = this.el.querySelector('form');
|
||||
form.insertAdjacentHTML(
|
||||
'afterbegin',
|
||||
'<span class="reg-feedback"></span>'
|
||||
);
|
||||
feedback = form.querySelector('.reg-feedback');
|
||||
}
|
||||
feedback.setAttribute('class', 'reg-feedback');
|
||||
feedback.textContent = message;
|
||||
if (klass) {
|
||||
$('.reg-feedback').addClass(klass);
|
||||
feedback.classList.add(klass);
|
||||
}
|
||||
},
|
||||
|
||||
@ -377,34 +390,31 @@
|
||||
return form;
|
||||
},
|
||||
|
||||
onRegistering (status, error) {
|
||||
/* Callback function called by Strophe */
|
||||
_converse.log('onRegistering');
|
||||
onConnectStatusChanged(status_code) {
|
||||
/* Callback function called by Strophe whenever the
|
||||
* connection status changes.
|
||||
*
|
||||
* Passed to Strophe specifically during a registration
|
||||
* attempt.
|
||||
*
|
||||
* Parameters:
|
||||
* (Integer) status_code - The Stroph.Status status code
|
||||
*/
|
||||
_converse.log('converse-register: onConnectStatusChanged');
|
||||
if (_.includes([
|
||||
Strophe.Status.DISCONNECTED,
|
||||
Strophe.Status.CONNFAIL,
|
||||
Strophe.Status.REGIFAIL,
|
||||
Strophe.Status.NOTACCEPTABLE,
|
||||
Strophe.Status.CONFLICT
|
||||
], status)) {
|
||||
], status_code)) {
|
||||
|
||||
_converse.log(
|
||||
`Problem during registration: Strophe.Status is: ${status}`,
|
||||
`Problem during registration: Strophe.Status is ${_converse.PRETTY_CONNECTION_STATUS[status_code]}`,
|
||||
Strophe.LogLevel.ERROR
|
||||
);
|
||||
this.cancelRegistration(error);
|
||||
if (error) {
|
||||
this.giveFeedback(__(
|
||||
'Something went wrong while establishing a connection with "%1$s". The returned error message is "%2$s"',
|
||||
this.domain, error
|
||||
), 'error');
|
||||
} else {
|
||||
this.giveFeedback(__(
|
||||
'Something went wrong while establishing a connection with "%1$s". Are you sure it exists?',
|
||||
this.domain
|
||||
), 'error');
|
||||
}
|
||||
} else if (status === Strophe.Status.REGISTERED) {
|
||||
this.abortRegistration();
|
||||
} else if (status_code === Strophe.Status.REGISTERED) {
|
||||
router.navigate(); // Strip the URL fragment
|
||||
_converse.log("Registered successfully.");
|
||||
this.model.set('registration_form_rendered', false);
|
||||
@ -419,7 +429,7 @@
|
||||
this.fields.password,
|
||||
_converse.onConnectStatusChanged
|
||||
);
|
||||
this.giveFeedback(__('Now logging you in'));
|
||||
this.giveFeedback(__('Now logging you in'), 'info');
|
||||
} else {
|
||||
_converse.chatboxviews.get('controlbox').renderLoginPanel();
|
||||
_converse.giveFeedback(__('Registered successfully'));
|
||||
@ -504,12 +514,34 @@
|
||||
`<input type="button" class="submit" value="${__('Return')}"/>`
|
||||
);
|
||||
form.querySelector('input[type=button]').addEventListener(
|
||||
'click', this.cancelRegistration.bind(this));
|
||||
'click', this.renderProviderChoiceForm.bind(this));
|
||||
}
|
||||
this.model.set('registration_form_rendered', true);
|
||||
this.showRegistrationForm();
|
||||
},
|
||||
|
||||
showValidationError (message) {
|
||||
const form = this.el.querySelector('form');
|
||||
let flash = form.querySelector('.form-errors');
|
||||
if (_.isNull(flash)) {
|
||||
flash = '<div class="form-errors hidden"></div>';
|
||||
const instructions = form.querySelector('p.instructions');
|
||||
if (_.isNull(instructions)) {
|
||||
form.insertAdjacentHTML('afterbegin', flash);
|
||||
} else {
|
||||
instructions.insertAdjacentHTML('afterend', flash);
|
||||
}
|
||||
flash = form.querySelector('.form-errors');
|
||||
} else {
|
||||
flash.innerHTML = '';
|
||||
}
|
||||
flash.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
'<p class="form-help error">'+message+'</p>'
|
||||
);
|
||||
flash.classList.remove('hidden');
|
||||
},
|
||||
|
||||
reportErrors (stanza) {
|
||||
/* Report back to the user any error messages received from the
|
||||
* XMPP server after attempted registration.
|
||||
@ -518,42 +550,33 @@
|
||||
* (XMLElement) stanza - The IQ stanza received from the
|
||||
* XMPP server.
|
||||
*/
|
||||
const $form= this.$('form'),
|
||||
$errmsgs = $(stanza).find('error text');
|
||||
|
||||
let $flash = $form.find('.form-errors');
|
||||
if (!$flash.length) {
|
||||
const flash = '<legend class="form-errors"></legend>';
|
||||
if ($form.find('p.instructions').length) {
|
||||
$form.find('p.instructions').append(flash);
|
||||
} else {
|
||||
$form.prepend(flash);
|
||||
}
|
||||
$flash = $form.find('.form-errors');
|
||||
} else {
|
||||
$flash.empty();
|
||||
}
|
||||
$errmsgs.each(function (idx, txt) {
|
||||
$flash.append($('<p class="form-help error">').text($(txt).text()));
|
||||
const errors = stanza.querySelectorAll('error');
|
||||
_.each(errors, (error) => {
|
||||
this.showValidationError(error.textContent);
|
||||
});
|
||||
if (!$errmsgs.length) {
|
||||
$flash.append($('<p class="form-help error">').text(
|
||||
__('The provider rejected your registration attempt. '+
|
||||
'Please check the values you entered for correctness.')));
|
||||
if (!errors.length) {
|
||||
const message = __('The provider rejected your registration attempt. '+
|
||||
'Please check the values you entered for correctness.');
|
||||
this.showValidationError(message);
|
||||
}
|
||||
$flash.show();
|
||||
},
|
||||
|
||||
cancelRegistration (ev) {
|
||||
/* Handler, when the user cancels the registration form.
|
||||
*/
|
||||
renderProviderChoiceForm (ev) {
|
||||
if (ev && ev.preventDefault) { ev.preventDefault(); }
|
||||
_converse.connection._proto._abortAllRequests();
|
||||
_converse.connection.reset();
|
||||
this.render();
|
||||
},
|
||||
|
||||
abortRegistration () {
|
||||
_converse.connection._proto._abortAllRequests();
|
||||
_converse.connection.reset();
|
||||
if (this.model.get('registration_form_rendered')) {
|
||||
if (_converse.registration_domain && this.model.get('registration_form_rendered')) {
|
||||
this.fetchRegistrationForm(
|
||||
_converse.registration_domain
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.render();
|
||||
}
|
||||
@ -657,14 +680,11 @@
|
||||
* Parameters:
|
||||
* (XMLElement) stanza - The IQ stanza.
|
||||
*/
|
||||
let error = null,
|
||||
query = stanza.getElementsByTagName("query");
|
||||
if (query.length > 0) {
|
||||
query = query[0];
|
||||
}
|
||||
if (stanza.getAttribute("type") === "error") {
|
||||
_converse.log("Registration failed.", Strophe.LogLevel.ERROR);
|
||||
error = stanza.getElementsByTagName("error");
|
||||
this.reportErrors(stanza);
|
||||
|
||||
let error = stanza.getElementsByTagName("error");
|
||||
if (error.length !== 1) {
|
||||
_converse.connection._changeConnectStatus(Strophe.Status.REGIFAIL, "unknown");
|
||||
return false;
|
||||
@ -677,16 +697,10 @@
|
||||
} else {
|
||||
_converse.connection._changeConnectStatus(Strophe.Status.REGIFAIL, error);
|
||||
}
|
||||
this.reportErrors(stanza);
|
||||
} else {
|
||||
_converse.connection._changeConnectStatus(Strophe.Status.REGISTERED, null);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
remove () {
|
||||
this.$tabs.empty();
|
||||
this.$el.parent().empty();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
<form id="converse-register" class="pure-form converse-form">
|
||||
<legend>{{{__("Account Registration")}}}</legend>
|
||||
<span class="reg-feedback"></span>
|
||||
|
||||
<label>{{{__("Please enter the XMPP provider to register with:")}}}</label>
|
||||
<p class="form-help">{{{help_providers}}} <a href="{{{href_providers}}}" class="url" target="_blank" rel="noopener">{{{help_providers_link}}}</a>.</p>
|
||||
<div class="form-errors hidden"></div>
|
||||
|
||||
{[ if (default_domain) { ]}
|
||||
{{{default_domain}}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<legend>{{{__("Account Registration:")}}} {{{domain}}}</legend>
|
||||
<span class="reg-feedback"></span>
|
||||
<p class="title">{{{title}}}</p>
|
||||
<p class="instructions">{{{instructions}}}</p>
|
||||
<div class="form-errors hidden"></div>
|
||||
|
Loading…
Reference in New Issue
Block a user