MOBILE-2317 login: Add custom user profile field to sign-up

main
Pau Ferrer Ocaña 2018-01-18 16:38:41 +01:00
parent 61a477afd5
commit d7c6c25292
32 changed files with 253 additions and 213 deletions

View File

@ -9,8 +9,9 @@
</p>
</ion-item>
<!-- Edit. -->
<ion-item *ngIf="edit && field && field.shortname">
<ion-item *ngIf="edit && field && field.shortname" [formGroup]="form">
<ion-label [core-mark-required]="field.required">{{ field.name }}</ion-label>
<ion-checkbox text-wrap [name]="field.modelName" [(ngModel)]="model[field.modelName]" [disabled]="!signup && field.locked" [required]="field.required" core-input-errors>
<ion-checkbox item-end [formControlName]="field.modelName">
</ion-checkbox>
<core-input-errors [control]="form.controls[field.modelName]" [errorMessages]="errors"></core-input-errors>
</ion-item>

View File

@ -13,20 +13,22 @@
// limitations under the License.
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
/**
* Directive to render a checkbox user profile field.
*/
@Component({
selector: 'core-user-profile-field-checkbox',
selector: 'addon-user-profile-field-checkbox',
templateUrl: 'checkbox.html'
})
export class AddonUserProfileFieldCheckboxComponent implements OnInit {
@Input() field: any; // The profile field to be rendered.
@Input() edit?: boolean = false; // True if editing the field. Defaults to false.
@Input() model?: any; // Model where to store the data. Required if edit=true or signup=true.
@Input() disabled?: boolean = false; // True if disabled. Defaults to false.
@Input() form?: FormGroup; // Form where to add the form control.
constructor() {}
constructor(private fb: FormBuilder) {}
/**
* Component being initialized.
@ -34,13 +36,15 @@ export class AddonUserProfileFieldCheckboxComponent implements OnInit {
ngOnInit() {
let field = this.field;
if (field && this.edit && this.model) {
if (field && this.edit && this.form) {
field.modelName = 'profile_field_' + field.shortname;
// Initialize the value.
if (typeof field.defaultdata != 'undefined' && typeof this.model[field.modelName] == 'undefined') {
this.model[field.modelName] = field.defaultdata && field.defaultdata !== '0' && field.defaultdata !== 'false';
}
let formData = {
value: field.defaultdata && field.defaultdata !== '0' && field.defaultdata !== 'false',
disabled: this.disabled
};
this.form.addControl(field.modelName, this.fb.control(formData, field.required && !field.locked ? Validators.requiredTrue : null));
}
}

View File

@ -40,17 +40,17 @@ export class AddonUserProfileFieldCheckboxHandler implements CoreUserProfileFiel
* @param {any} field User field to get the data for.
* @param {boolean} signup True if user is in signup page.
* @param {string} [registerAuth] Register auth method. E.g. 'email'.
* @param {any} model Model with the input data.
* @param {any} formValues Form Values.
* @return {CoreUserProfileFieldHandlerData} Data to send for the field.
*/
getData(field: any, signup: boolean, registerAuth: string, model: any): CoreUserProfileFieldHandlerData {
getData(field: any, signup: boolean, registerAuth: string, formValues: any): CoreUserProfileFieldHandlerData {
let name = 'profile_field_' + field.shortname;
if (typeof model[name] != 'undefined') {
if (typeof formValues[name] != 'undefined') {
return {
type: 'checkbox',
name: name,
value: model[name] ? 1 : 0
value: formValues[name] ? 1 : 0
};
}
}
@ -58,12 +58,9 @@ export class AddonUserProfileFieldCheckboxHandler implements CoreUserProfileFiel
/**
* Return the Component to use to display the user profile field.
*
* @param {any} field User field to get the data for.
* @param {boolean} signup True if user is in signup page.
* @param {string} [registerAuth] Register auth method. E.g. 'email'.
* @return {any} The component to use, undefined if not found.
*/
getComponent(field: any, signup: boolean, registerAuth: string) {
getComponent() {
return AddonUserProfileFieldCheckboxComponent;
}

View File

@ -4,7 +4,7 @@
<p>{{ field.value * 1000 | coreFormatDate:"dfmediumdate"}}</p>
</ion-item>
<!-- Edit. -->
<ion-item *ngIf="edit && field && field.shortname" text-wrap>
<ion-label [core-mark-required]="field.required">{{ field.name }}</ion-label>
<ion-datetime [name]="field.modelName" [displayFormat]="field.format | translate" [disabled]="!signup && field.locked" [(ngModel)]="model[field.modelName]" [required]="field.required" core-input-errors [max]="field.max" [min]="field.min"></ion-datetime>
<ion-item *ngIf="edit && field && field.shortname" text-wrap [formGroup]="form">
<ion-label stacked [core-mark-required]="field.required">{{ field.name }}</ion-label>
<ion-datetime [formControlName]="field.modelName" [placeholder]="'core.choosedots' | translate" [displayFormat]="field.format" core-input-errors [max]="field.max" [min]="field.min"></ion-datetime>
</ion-item>

View File

@ -13,21 +13,23 @@
// limitations under the License.
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { CoreTimeUtilsProvider } from '../../../../providers/utils/time';
/**
* Directive to render a datetime user profile field.
*/
@Component({
selector: 'core-user-profile-field-datetime',
selector: 'addon-user-profile-field-datetime',
templateUrl: 'datetime.html'
})
export class AddonUserProfileFieldDatetimeComponent implements OnInit {
@Input() field: any; // The profile field to be rendered.
@Input() edit?: boolean = false; // True if editing the field. Defaults to false.
@Input() model?: any; // Model where to store the data. Required if edit=true or signup=true.
@Input() disabled?: boolean = false; // True if disabled. Defaults to false.
@Input() form?: FormGroup; // Form where to add the form control.
constructor() {}
constructor(private fb: FormBuilder, private timeUtils: CoreTimeUtilsProvider) {}
/**
* Component being initialized.
@ -35,12 +37,12 @@ export class AddonUserProfileFieldDatetimeComponent implements OnInit {
ngOnInit() {
let field = this.field,
year;
if (field && this.edit && this.model) {
if (field && this.edit && this.form) {
field.modelName = 'profile_field_' + field.shortname;
// Check if it's only date or it has time too.
field.hasTime = field.param3 && field.param3 !== '0' && field.param3 !== 'false';
field.format = field.hasTime ? 'core.dffulldate' : 'core.dfdaymonthyear';
let hasTime = field.param3 && field.param3 !== '0' && field.param3 !== 'false';
field.format = hasTime ? this.timeUtils.getLocalizedDateFormat('LLL') : this.timeUtils.getLocalizedDateFormat('LL');
// Check min value.
if (field.param1) {
@ -57,6 +59,12 @@ export class AddonUserProfileFieldDatetimeComponent implements OnInit {
field.max = year;
}
}
let formData = {
value: field.defaultdata,
disabled: this.disabled
};
this.form.addControl(field.modelName, this.fb.control(formData, field.required && !field.locked ? Validators.required : null));
}
}

View File

@ -41,31 +41,18 @@ export class AddonUserProfileFieldDatetimeHandler implements CoreUserProfileFiel
* @param {any} field User field to get the data for.
* @param {boolean} signup True if user is in signup page.
* @param {string} [registerAuth] Register auth method. E.g. 'email'.
* @param {any} model Model with the input data.
* @param {any} formValues Form Values.
* @return {CoreUserProfileFieldHandlerData} Data to send for the field.
*/
getData(field: any, signup: boolean, registerAuth: string, model: any): CoreUserProfileFieldHandlerData {
let hasTime = field.param3 && field.param3 !== '0' && field.param3 !== 'false',
modelName = 'profile_field_' + field.shortname,
date = JSON.parse(JSON.stringify(model[modelName + '_date'])),
time;
if (date) {
if (hasTime && this.platform.is('ios')) {
// In iOS the time is in a different input. Add it to the date.
time = model[modelName + '_time'];
if (!time) {
return;
}
date.setHours(time.getHours());
date.setMinutes(time.getMinutes());
}
getData(field: any, signup: boolean, registerAuth: string, formValues: any): CoreUserProfileFieldHandlerData {
let name = 'profile_field_' + field.shortname;
if (formValues[name]) {
let milliseconds = new Date(formValues[name]).getTime();
return {
type: 'datetime',
name: 'profile_field_' + field.shortname,
value: Math.round(date.getTime() / 1000)
value: Math.round(milliseconds / 1000)
};
}
}
@ -73,12 +60,9 @@ export class AddonUserProfileFieldDatetimeHandler implements CoreUserProfileFiel
/**
* Return the Component to use to display the user profile field.
*
* @param {any} field User field to get the data for.
* @param {boolean} signup True if user is in signup page.
* @param {string} [registerAuth] Register auth method. E.g. 'email'.
* @return {any} The component to use, undefined if not found.
*/
getComponent(field: any, signup: boolean, registerAuth: string) {
getComponent() {
return AddonUserProfileFieldDatetimeComponent;
}

View File

@ -4,9 +4,9 @@
<p><core-format-text [text]="field.value"></core-format-text></p>
</ion-item>
<!-- Edit. -->
<ion-item *ngIf="edit && field && field.shortname" text-wrap>
<ion-label [core-mark-required]="field.required">{{ field.name }}</ion-label>
<ion-select [name]="field.modelName" [(ngModel)]="model[field.modelName]" [disabled]="!signup && field.locked" [required]="field.required" core-input-errors>
<ion-item *ngIf="edit && field && field.shortname" text-wrap [formGroup]="form">
<ion-label stacked [core-mark-required]="field.required">{{ field.name }}</ion-label>
<ion-select [formControlName]="field.modelName" [placeholder]="'core.choosedots' | translate" core-input-errors>
<ion-option value="">{{ 'core.choosedots' | translate }}</ion-option>
<ion-option *ngFor="let option of field.options" [value]="option">{{option}}</ion-option>
</ion-select>

View File

@ -13,20 +13,22 @@
// limitations under the License.
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
/**
* Directive to render a menu user profile field.
*/
@Component({
selector: 'core-user-profile-field-menu',
selector: 'addon-user-profile-field-menu',
templateUrl: 'menu.html'
})
export class AddonUserProfileFieldMenuComponent implements OnInit {
@Input() field: any; // The profile field to be rendered.
@Input() edit?: boolean = false; // True if editing the field. Defaults to false.
@Input() model?: any; // Model where to store the data. Required if edit=true or signup=true.
@Input() disabled?: boolean = false; // True if disabled. Defaults to false.
@Input() form?: FormGroup; // Form where to add the form control.
constructor() {}
constructor(private fb: FormBuilder) {}
/**
* Component being initialized.
@ -34,7 +36,7 @@ export class AddonUserProfileFieldMenuComponent implements OnInit {
ngOnInit() {
let field = this.field;
if (field && this.edit && this.model) {
if (field && this.edit && this.form) {
field.modelName = 'profile_field_' + field.shortname;
// Parse options.
@ -44,10 +46,12 @@ export class AddonUserProfileFieldMenuComponent implements OnInit {
field.options = [];
}
let formData = {
value: field.defaultdata,
disabled: this.disabled
};
// Initialize the value using default data.
if (typeof field.defaultdata != 'undefined' && typeof this.model[field.modelName] == 'undefined') {
this.model[field.modelName] = field.defaultdata;
}
this.form.addControl(field.modelName, this.fb.control(formData, field.required && !field.locked ? Validators.required : null));
}
}

View File

@ -40,17 +40,17 @@ export class AddonUserProfileFieldMenuHandler implements CoreUserProfileFieldHan
* @param {any} field User field to get the data for.
* @param {boolean} signup True if user is in signup page.
* @param {string} [registerAuth] Register auth method. E.g. 'email'.
* @param {any} model Model with the input data.
* @param {any} formValues Form Values.
* @return {CoreUserProfileFieldHandlerData} Data to send for the field.
*/
getData(field: any, signup: boolean, registerAuth: string, model: any): CoreUserProfileFieldHandlerData {
getData(field: any, signup: boolean, registerAuth: string, formValues: any): CoreUserProfileFieldHandlerData {
let name = 'profile_field_' + field.shortname;
if (model[name]) {
if (formValues[name]) {
return {
type: 'menu',
name: name,
value: model[name]
value: formValues[name]
};
}
}
@ -58,12 +58,9 @@ export class AddonUserProfileFieldMenuHandler implements CoreUserProfileFieldHan
/**
* Return the Component to use to display the user profile field.
*
* @param {any} field User field to get the data for.
* @param {boolean} signup True if user is in signup page.
* @param {string} [registerAuth] Register auth method. E.g. 'email'.
* @return {any} The component to use, undefined if not found.
*/
getComponent(field: any, signup: boolean, registerAuth: string) {
getComponent() {
return AddonUserProfileFieldMenuComponent;
}

View File

@ -4,7 +4,7 @@
<p><core-format-text [text]="field.value"></core-format-text></p>
</ion-item>
<!-- Edit. -->
<ion-item *ngIf="edit && field && field.shortname" text-wrap>
<ion-label [core-mark-required]="field.required">{{ field.name }}</ion-label>
<ion-input [type]="field.inputType" [name]="field.modelName" [placeholder]="field.name" [(ngModel)]="model[field.modelName]" [disabled]="!signup && field.locked" maxlength="{{field.maxlength}}" [required]="field.required" core-input-errors></ion-input>
<ion-item *ngIf="edit && field && field.shortname" text-wrap [formGroup]="form">
<ion-label stacked [core-mark-required]="field.required">{{ field.name }}</ion-label>
<ion-input [type]="field.inputType" [formControlName]="field.modelName" [placeholder]="field.name" maxlength="{{field.maxlength}}" core-input-errors></ion-input>
</ion-item>

View File

@ -13,20 +13,22 @@
// limitations under the License.
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
/**
* Directive to render a text user profile field.
*/
@Component({
selector: 'core-user-profile-field-text',
selector: 'addon-user-profile-field-text',
templateUrl: 'text.html'
})
export class AddonUserProfileFieldTextComponent implements OnInit {
@Input() field: any; // The profile field to be rendered.
@Input() edit?: boolean = false; // True if editing the field. Defaults to false.
@Input() model?: any; // Model where to store the data. Required if edit=true or signup=true.
@Input() disabled?: boolean = false; // True if disabled. Defaults to false.
@Input() form?: FormGroup; // Form where to add the form control.
constructor() {}
constructor(private fb: FormBuilder) {}
/**
* Component being initialized.
@ -34,7 +36,7 @@ export class AddonUserProfileFieldTextComponent implements OnInit {
ngOnInit() {
let field = this.field;
if (field && this.edit && this.model) {
if (field && this.edit && this.form) {
field.modelName = 'profile_field_' + field.shortname;
// Check max length.
@ -45,10 +47,12 @@ export class AddonUserProfileFieldTextComponent implements OnInit {
// Check if it's a password or text.
field.inputType = field.param3 && field.param3 !== '0' && field.param3 !== 'false' ? 'password' : 'text';
let formData = {
value: field.defaultdata,
disabled: this.disabled
};
// Initialize the value using default data.
if (typeof field.defaultdata != 'undefined' && typeof this.model[field.modelName] == 'undefined') {
this.model[field.modelName] = field.defaultdata;
}
this.form.addControl(field.modelName, this.fb.control(formData, field.required && !field.locked ? Validators.required : null));
}
}

View File

@ -41,28 +41,25 @@ export class AddonUserProfileFieldTextHandler implements CoreUserProfileFieldHan
* @param {any} field User field to get the data for.
* @param {boolean} signup True if user is in signup page.
* @param {string} [registerAuth] Register auth method. E.g. 'email'.
* @param {any} model Model with the input data.
* @param {any} formValues Form Values.
* @return {CoreUserProfileFieldHandlerData} Data to send for the field.
*/
getData(field: any, signup: boolean, registerAuth: string, model: any): CoreUserProfileFieldHandlerData {
getData(field: any, signup: boolean, registerAuth: string, formValues: any): CoreUserProfileFieldHandlerData {
let name = 'profile_field_' + field.shortname;
return {
type: 'text',
name: name,
value: this.textUtils.cleanTags(model[name])
value: this.textUtils.cleanTags(formValues[name])
};
}
/**
* Return the Component to use to display the user profile field.
*
* @param {any} field User field to get the data for.
* @param {boolean} signup True if user is in signup page.
* @param {string} [registerAuth] Register auth method. E.g. 'email'.
* @return {any} The component to use, undefined if not found.
*/
getComponent(field: any, signup: boolean, registerAuth: string) {
getComponent() {
return AddonUserProfileFieldTextComponent;
}

View File

@ -4,7 +4,7 @@
<p><core-format-text [text]="field.value"></core-format-text></p>
</ion-item>
<!-- Edit. -->
<ion-item *ngIf="edit && field && field.shortname" text-wrap>
<ion-label [core-mark-required]="field.required">{{ field.name }}</ion-label>
<ion-textarea [name]="field.modelName" [(ngModel)]="model[field.modelName]" [placeholder]="field.name" [disabled]="!signup && field.locked" [required]="field.required"></ion-textarea>
<ion-item *ngIf="edit && field && field.shortname" text-wrap [formGroup]="form">
<ion-label stacked [core-mark-required]="field.required">{{ field.name }}</ion-label>
<core-rich-text-editor item-content [control]="control" [placeholder]="field.name"></core-rich-text-editor>
</ion-item>

View File

@ -13,18 +13,22 @@
// limitations under the License.
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup, Validators, FormControl} from '@angular/forms';
/**
* Directive to render a textarea user profile field.
*/
@Component({
selector: 'core-user-profile-field-textarea',
selector: 'addon-user-profile-field-textarea',
templateUrl: 'textarea.html'
})
export class AddonUserProfileFieldTextareaComponent implements OnInit {
@Input() field: any; // The profile field to be rendered.
@Input() edit?: boolean = false; // True if editing the field. Defaults to false.
@Input() model?: any; // Model where to store the data. Required if edit=true or signup=true.
@Input() disabled?: boolean = false; // True if disabled. Defaults to false.
@Input() form?: FormGroup; // Form where to add the form control.
control: FormControl
constructor() {}
@ -34,17 +38,17 @@ export class AddonUserProfileFieldTextareaComponent implements OnInit {
ngOnInit() {
let field = this.field;
if (field && this.edit && this.model) {
if (field && this.edit && this.form) {
field.modelName = 'profile_field_' + field.shortname;
this.model[field.modelName] = {
format: 1
};
// Initialize the value using default data.
if (typeof field.defaultdata != 'undefined' && typeof this.model[field.modelName].text == 'undefined') {
this.model[field.modelName].text = field.defaultdata;
}
}
let formData = {
value: field.defaultdata,
disabled: this.disabled
};
this.control = new FormControl(formData, field.required && !field.locked ? Validators.required : null);
this.form.addControl(field.modelName, this.control);
}
}

View File

@ -16,7 +16,6 @@ import { Injectable } from '@angular/core';
import { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from '../../../../core/user/providers/user-profile-field-delegate';
import { AddonUserProfileFieldTextareaComponent } from '../component/textarea';
import { CoreTextUtilsProvider } from '../../../../providers/utils/text';
import { CoreDomUtilsProvider } from '../../../../providers/utils/dom';
/**
* Textarea user profile field handlers.
@ -25,7 +24,7 @@ import { CoreDomUtilsProvider } from '../../../../providers/utils/dom';
export class AddonUserProfileFieldTextareaHandler implements CoreUserProfileFieldHandler {
name = 'textarea';
constructor(private textUtils: CoreTextUtilsProvider, private domUtils: CoreDomUtilsProvider) {}
constructor(private textUtils: CoreTextUtilsProvider) {}
/**
* Whether or not the handler is enabled on a site level.
@ -42,41 +41,34 @@ export class AddonUserProfileFieldTextareaHandler implements CoreUserProfileFiel
* @param {any} field User field to get the data for.
* @param {boolean} signup True if user is in signup page.
* @param {string} [registerAuth] Register auth method. E.g. 'email'.
* @param {any} model Model with the input data.
* @return {Promise<CoreUserProfileFieldHandlerData>} Data to send for the field.
* @param {any} formValues Form Values.
* @return {CoreUserProfileFieldHandlerData} Data to send for the field.
*/
getData(field: any, signup: boolean, registerAuth: string, model: any): Promise<CoreUserProfileFieldHandlerData> {
getData(field: any, signup: boolean, registerAuth: string, formValues: any): CoreUserProfileFieldHandlerData {
let name = 'profile_field_' + field.shortname;
if (model[name]) {
return this.domUtils.isRichTextEditorEnabled().then((enabled) => {
let text = model[name].text || '';
if (!enabled) {
// Rich text editor not enabled, add some HTML to the message if needed.
text = this.textUtils.formatHtmlLines(text);
}
if (formValues[name]) {
let text = formValues[name] || '';
// Add some HTML to the message in case the user edited with textarea.
text = this.textUtils.formatHtmlLines(text);
return {
type: 'textarea',
name: name,
value: JSON.stringify({
text: text,
format: model[name].format || 1
})
};
});
return {
type: 'textarea',
name: name,
value: JSON.stringify({
text: text,
format: 1 // Always send this format.
})
};
}
}
/**
* Return the Component to use to display the user profile field.
*
* @param {any} field User field to get the data for.
* @param {boolean} signup True if user is in signup page.
* @param {string} [registerAuth] Register auth method. E.g. 'email'.
* @return {any} The component to use, undefined if not found.
*/
getComponent(field: any, signup: boolean, registerAuth: string) {
getComponent() {
return AddonUserProfileFieldTextareaComponent;
}

View File

@ -92,6 +92,19 @@ export class CoreDelegate {
eventsProvider.on(CoreEventsProvider.REMOTE_ADDONS_LOADED, this.updateHandlers.bind(this));
}
/**
* Execute a certain function in a enabled handler.
* If the handler isn't found or function isn't defined, call the same function in the default handler.
*
* @param {string} handlerName The handler name.
* @param {string} fnName Name of the function to execute.
* @param {any[]} params Parameters to pass to the function.
* @return {any} Function returned value or default value.
*/
protected executeFunctionOnEnabled(handlerName: string, fnName: string, params?: any[]) : any {
return this.execute(this.enabledHandlers[handlerName], fnName, params);
}
/**
* Execute a certain function in a handler.
* If the handler isn't found or function isn't defined, call the same function in the default handler.
@ -102,7 +115,19 @@ export class CoreDelegate {
* @return {any} Function returned value or default value.
*/
protected executeFunction(handlerName: string, fnName: string, params?: any[]) : any {
let handler = this.enabledHandlers[handlerName];
return this.execute(this.handlers[handlerName], fnName, params);
}
/**
* Execute a certain function in a handler.
* If the handler isn't found or function isn't defined, call the same function in the default handler.
*
* @param {any} handler The handler.
* @param {string} fnName Name of the function to execute.
* @param {any[]} params Parameters to pass to the function.
* @return {any} Function returned value or default value.
*/
private execute(handler: any, fnName: string, params?: any[]) : any {
if (handler && handler[fnName]) {
return handler[fnName].apply(handler, params);
} else if (this.defaultHandler && this.defaultHandler[fnName]) {
@ -110,14 +135,26 @@ export class CoreDelegate {
}
}
/**
* Get a handler.
*
* @param {string} handlerName The handler name.
* @param {boolean} [enabled] Only enabled, or any.
* @return {any} Handler.
*/
protected getHandler(handlerName: string, enabled = false): any {
return enabled ? this.enabledHandlers[handlerName] : this.handlers[handlerName];
}
/**
* Check if a handler name has a registered handler (not necessarily enabled).
*
* @param {string} name The name of the handler.
* @param {string} name The handler name.
* @param {boolean} [enabled] Only enabled, or any.
* @return {boolean} If the controller is installed or not.
*/
hasHandler(name: string) : boolean {
return typeof this.handlers[name] !== 'undefined';
hasHandler(name: string, enabled = false) : boolean {
return enabled ? typeof this.enabledHandlers[name] !== 'undefined' : typeof this.handlers[name] !== 'undefined';
}
/**
@ -234,5 +271,4 @@ export class CoreDelegate {
updateData() {
}
}

View File

@ -21,7 +21,7 @@ import { CoreLoginHelperProvider } from './providers/helper';
imports: [
],
providers: [
CoreLoginHelperProvider,
CoreLoginHelperProvider
]
})
export class CoreLoginModule {}

View File

@ -75,14 +75,14 @@
</ion-select>
</ion-item>
<!-- Other categories. @todo: Implement once user profile fields are implemented. -->
<!-- <div *ngFor="let category in categories">
<ion-item-divider text-wrap color="light">{{ category.name }}</div>
<core-user-profile-field *ngFor="let field in category.fields" field="field" edit="true" signup="true" register-auth="email" model="data" scroll-handle="mmLoginEmailSignupScroll"></core-user-profile-field>
</div> -->
<!-- Other categories. -->
<ng-container *ngFor="let category of categories">
<ion-item-divider text-wrap color="light">{{ category.name }}</ion-item-divider>
<core-user-profile-field *ngFor="let field of category.fields" [field]="field" edit="true" signup="true" registerAuth="email" [form]="signupForm"></core-user-profile-field>
</ng-container>
<!-- ReCAPTCHA -->
<div *ngIf="settings.recaptchachallengehash && settings.recaptchachallengeimage">
<ng-container *ngIf="settings.recaptchachallengehash && settings.recaptchachallengeimage">
<ion-item-divider text-wrap color="light">{{ 'core.login.security_question' | translate }}</ion-item-divider>
<ion-item>
<img [src]="settings.recaptchachallengeimage" alt="{{ 'core.login.recaptchachallengeimage' | translate }}">
@ -96,20 +96,20 @@
<!-- Use anchor instead of button to prevent marking form as submitted. -->
<a ion-button block (click)="requestCaptcha()">{{ 'core.login.getanothercaptcha' | translate }}</a>
</ion-item>
</div>
</ng-container>
<!-- Site policy (if any). -->
<div *ngIf="settings.sitepolicy">
<ng-container *ngIf="settings.sitepolicy">
<ion-item-divider text-wrap color="light">{{ 'core.login.policyagreement' | translate }}</ion-item-divider>
<ion-item text-wrap>
<p><a [href]="settings.sitepolicy" core-link capture="false">{{ 'core.login.policyagreementclick' | translate }}</a></p>
</ion-item>
<ion-item text-wrap>
<ion-label core-mark-required="true">{{ 'core.login.policyaccept' | translate }}</ion-label>
<ion-checkbox item-right name="policyagreed" formControlName="policyagreed"></ion-checkbox>
<ion-checkbox item-end name="policyagreed" formControlName="policyagreed"></ion-checkbox>
<core-input-errors [control]="signupForm.controls.policyagreed" [errorMessages]="policyErrors"></core-input-errors>
</ion-item>
</div>
</ng-container>
<!-- Submit button. -->
<ion-item padding>

View File

@ -18,6 +18,7 @@ import { CoreLoginEmailSignupPage } from './email-signup';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '../../../../components/components.module';
import { CoreDirectivesModule } from '../../../../directives/directives.module';
import { CoreUserComponentsModule } from '../../../user/components/components.module';
@NgModule({
declarations: [
@ -26,6 +27,7 @@ import { CoreDirectivesModule } from '../../../../directives/directives.module';
imports: [
CoreComponentsModule,
CoreDirectivesModule,
CoreUserComponentsModule,
IonicPageModule.forChild(CoreLoginEmailSignupPage),
TranslateModule.forChild()
]

View File

@ -22,6 +22,7 @@ import { CoreUtilsProvider } from '../../../../providers/utils/utils';
import { CoreWSProvider } from '../../../../providers/ws';
import { CoreLoginHelperProvider } from '../../providers/helper';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { CoreUserProfileFieldDelegate } from '../../../user/providers/user-profile-field-delegate';
/**
* Page to signup using email.
@ -55,7 +56,7 @@ export class CoreLoginEmailSignupPage {
constructor(private navCtrl: NavController, navParams: NavParams, private fb: FormBuilder, private wsProvider: CoreWSProvider,
private sitesProvider: CoreSitesProvider, private loginHelper: CoreLoginHelperProvider,
private domUtils: CoreDomUtilsProvider, private translate: TranslateService, private utils: CoreUtilsProvider,
private textUtils: CoreTextUtilsProvider) {
private textUtils: CoreTextUtilsProvider, private userProfileFieldDelegate :CoreUserProfileFieldDelegate) {
this.siteUrl = navParams.get('siteUrl');
@ -228,26 +229,22 @@ export class CoreLoginEmailSignupPage {
}
// Get the data for the custom profile fields.
// @todo: Implement it once profile fields are implemented.
// $mmUserProfileFieldsDelegate.getDataForFields(fields, true, 'email', $scope.data).then(function(fieldsData) {
// params.customprofilefields = fieldsData;
this.userProfileFieldDelegate.getDataForFields(this.settings.profilefields, true, 'email', this.signupForm.value).then((fieldsData) => {
params.customprofilefields = fieldsData;
this.wsProvider.callAjax('auth_email_signup_user', params, {siteUrl: this.siteUrl}).then((result) => {
if (result.success) {
// Show alert and ho back.
let message = this.translate.instant('core.login.emailconfirmsent', {$a: params.email});
this.domUtils.showAlert(this.translate.instant('core.success'), message);
this.navCtrl.pop();
} else {
if (result.warnings && result.warnings.length) {
this.domUtils.showErrorModal(result.warnings[0].message);
this.wsProvider.callAjax('auth_email_signup_user', params, {siteUrl: this.siteUrl}).then((result) => {
if (result.success) {
// Show alert and ho back.
let message = this.translate.instant('core.login.emailconfirmsent', {$a: params.email});
this.domUtils.showAlert(this.translate.instant('core.success'), message);
this.navCtrl.pop();
} else {
this.domUtils.showErrorModal('core.login.usernotaddederror', true);
}
this.domUtils.showErrorModalFirstWarning(result.warnings, 'core.login.usernotaddederror', true);
// Error sending, request another capctha since the current one is probably invalid now.
this.requestCaptcha(true);
}
// Error sending, request another capctha since the current one is probably invalid now.
this.requestCaptcha(true);
}
});
}).catch((error) => {
this.domUtils.showErrorModalDefault(error && error.error, 'core.login.usernotaddederror', true);

View File

@ -244,12 +244,12 @@ export class CoreLoginHelperProvider {
* @return {any} Categories with the fields to show in each one.
*/
formatProfileFieldsForSignup(profileFields: any[]) : any {
let categories = {};
if (!profileFields) {
return categories;
return [];
}
let categories = {};
profileFields.forEach((field) => {
if (!field.signup) {
// Not a signup field, ignore it.
@ -267,7 +267,9 @@ export class CoreLoginHelperProvider {
categories[field.categoryid].fields.push(field);
});
return categories;
return Object.keys(categories).map((index) => {
return categories[index];
});
}
/**

View File

@ -15,6 +15,7 @@
import { Component, Input, ViewChild, ViewContainerRef, ComponentFactoryResolver, ComponentRef, OnInit } from '@angular/core';
import { CoreLoggerProvider } from '../../../../providers/logger';
import { CoreUserProfileFieldDelegate } from '../../providers/user-profile-field-delegate';
import { CoreUtilsProvider } from '../../../../providers/utils/utils';
/**
* Directive to render user profile field.
@ -27,13 +28,13 @@ export class CoreUserProfileFieldComponent implements OnInit {
@Input() field: any; // The profile field to be rendered.
@Input() signup?: boolean = false; // True if editing the field in signup. Defaults to false.
@Input() edit?: boolean = false; // True if editing the field. Defaults to false.
@Input() model?: any; // Model where to store the data. Required if edit=true or signup=true.
@Input() form?: any; // Form where to add the form control. Required if edit=true or signup=true.
@Input() registerAuth?: string; // Register auth method. E.g. 'email'.
// Get the containers where to inject dynamic components. We use a setter because they might be inside a *ngIf.
@ViewChild('userProfileField', { read: ViewContainerRef }) set userProfileField (el: ViewContainerRef) {
if (this.field) {
this.createComponent(this.ufDelegate.getComponent(this.field, this.signup, this.registerAuth), el);
this.createComponent(this.ufDelegate.getComponent(this.field, this.signup), el);
} else {
// The component hasn't been initialized yet. Store the container.
this.fieldContainer = el;
@ -47,7 +48,7 @@ export class CoreUserProfileFieldComponent implements OnInit {
protected fieldInstance: any;
constructor(logger: CoreLoggerProvider, private factoryResolver: ComponentFactoryResolver,
private ufDelegate: CoreUserProfileFieldDelegate) {
private ufDelegate: CoreUserProfileFieldDelegate, private utilsProvider: CoreUtilsProvider) {
this.logger = logger.getInstance('CoreUserProfileFieldComponent');
}
@ -55,7 +56,7 @@ export class CoreUserProfileFieldComponent implements OnInit {
* Component being initialized.
*/
ngOnInit() {
this.createComponent(this.ufDelegate.getComponent(this.field, this.signup, this.registerAuth), this.fieldContainer);
this.createComponent(this.ufDelegate.getComponent(this.field, this.signup), this.fieldContainer);
}
/**
@ -86,8 +87,12 @@ export class CoreUserProfileFieldComponent implements OnInit {
// Set the Input data.
this.fieldInstance.field = this.field;
this.fieldInstance.edit = this.edit;
this.fieldInstance.model = this.model;
this.fieldInstance.edit = this.utilsProvider.isTrueOrOne(this.edit);
if (this.edit) {
this.fieldInstance.signup = this.utilsProvider.isTrueOrOne(this.signup);
this.fieldInstance.disabled = this.utilsProvider.isTrueOrOne(this.field.locked);
this.fieldInstance.form = this.form;
}
return true;
} catch(ex) {

View File

@ -8,8 +8,11 @@
"detailsnotavailable": "The details of this user are not available to you.",
"editingteacher": "Teacher",
"email": "Email address",
"emailagain": "Email (again)",
"errorloaduser": "Error loading user.",
"firstname": "First name",
"interests": "Interests",
"lastname": "Surname",
"manager": "Manager",
"newpicture": "New picture",
"phone1": "Phone",

View File

@ -60,7 +60,6 @@ export class CoreUserHelperProvider {
let separator = this.translate.instant('core.listsep');
roles.map((value) => {
console.error(value);
let translation = this.translate.instant('core.user.' + value.shortname);
return translation.indexOf('core.user.') < 0 ? translation : value.shortname;
});

View File

@ -23,22 +23,19 @@ export interface CoreUserProfileFieldHandler extends CoreDelegateHandler {
/**
* Return the Component to use to display the user profile field.
*
* @param {any} field User field to get the data for.
* @param {boolean} [signup] True if user is in signup page.
* @param {string} [registerAuth] Register auth method. E.g. 'email'.
* @return {any} The component to use, undefined if not found.
*/
getComponent(field: any, signup: boolean, registerAuth: string): any;
getComponent(): any;
/**
* Get the data to send for the field based on the input data.
* @param {any} field User field to get the data for.
* @param {boolean} signup True if user is in signup page.
* @param {string} [registerAuth] Register auth method. E.g. 'email'.
* @param {any} model Model with the input data.
* @param {any} formValues Form Values.
* @return {Promise<CoreUserProfileFieldHandlerData>|CoreUserProfileFieldHandlerData} Data to send for the field.
*/
getData?(field: any, signup: boolean, registerAuth: string, model: any):
getData?(field: any, signup: boolean, registerAuth: string, formValues: any):
Promise<CoreUserProfileFieldHandlerData> | CoreUserProfileFieldHandlerData;
};
@ -80,12 +77,15 @@ export class CoreUserProfileFieldDelegate extends CoreDelegate {
*
* @param {any} field User field to get the directive for.
* @param {boolean} signup True if user is in signup page.
* @param {string} registerAuth Register auth method. E.g. 'email'
* @return {any} The component to use, undefined if not found.
*/
getComponent(field: any, signup: boolean, registerAuth: string) : any {
getComponent(field: any, signup: boolean) : any {
let type = field.type || field.datatype;
return this.executeFunction(type, 'getComponent', [field, signup, registerAuth]);
if (signup) {
return this.executeFunction(type, 'getComponent');
} else {
return this.executeFunctionOnEnabled(type, 'getComponent');
}
}
/**
@ -94,22 +94,22 @@ export class CoreUserProfileFieldDelegate extends CoreDelegate {
* @param {any} field User field to get the data for.
* @param {boolean} signup True if user is in signup page.
* @param {string} registerAuth Register auth method. E.g. 'email'.
* @param {any} model Model with the input data.
* @param {any} formValues Form values.
* @return {Promise<any>} Data to send for the field.
*/
getDataForField(field: any, signup: boolean, registerAuth: string, model: any): Promise<any> {
let handler = this.getHandler(field, signup);
getDataForField(field: any, signup: boolean, registerAuth: string, formValues: any): Promise<any> {
let type = field.type || field.datatype,
handler = this.getHandler(type, !signup);
if (handler) {
let name = 'profile_field_' + field.shortname;
if (handler.getData) {
return Promise.resolve(handler.getData(field, signup, registerAuth, model));
} else if (field.shortname && typeof model[name] != 'undefined') {
// Handler doesn't implement the function, but the model has data for the field.
return Promise.resolve(handler.getData(field, signup, registerAuth, formValues));
} else if (field.shortname && typeof formValues[name] != 'undefined') {
// Handler doesn't implement the function, but the form has data for the field.
return Promise.resolve({
type: field.type || field.datatype,
type: type,
name: name,
value: model[name]
value: formValues[name]
});
}
}
@ -122,43 +122,25 @@ export class CoreUserProfileFieldDelegate extends CoreDelegate {
* @param {any[]} fields User fields to get the data for.
* @param {boolean} [signup] True if user is in signup page.
* @param {string} [registerAuth] Register auth method. E.g. 'email'.
* @param {any} model Model with the input data.
* @param {any} formValues Form values.
* @return {Promise<any>} Data to send.
*/
getDataForFields(fields: any[], signup = false, registerAuth = "", model: any): Promise<any> {
getDataForFields(fields: any[], signup = false, registerAuth = "", formValues: any): Promise<any> {
let result = [],
promises = [];
fields.forEach((field) => {
this.getDataForField(field, signup, registerAuth, model).then((data) => {
result.push(data);
promises.push(this.getDataForField(field, signup, registerAuth, formValues).then((data) => {
if (data) {
result.push(data);
}
}).catch(() => {
// Ignore errors.
});
}));
});
return Promise.all(promises).then(() => {
return result;
});
}
/**
* Get a handler.
*
* @param {any} field User field to get the directive for.
* @param {boolean} signup True if user is in signup page.
* @return {any} Handler.
*/
protected getHandler(field: any, signup: boolean): any {
let type = field.type || field.datatype;
if (signup) {
if (this.handlers[type]) {
return this.handlers[type];
}
return false;
}
return this.enabledHandlers[type];
}
}

View File

@ -743,6 +743,20 @@ export class CoreDomUtilsProvider {
}
}
/**
* Show an alert modal with the first warning error message. It uses a default message if error is not a string.
*
* @param {any} warnings Warnings returned.
* @param {any} [defaultError] Message to show if the error is not a string.
* @param {boolean} [needsTranslate] Whether the error needs to be translated.
* @param {number} [autocloseTime] Number of milliseconds to wait to close the modal. If not defined, modal won't be closed.
* @return {Alert} The alert modal.
*/
showErrorModalFirstWarning(warnings: any, defaultError: any, needsTranslate?: boolean, autocloseTime?: number) : Alert {
let error = warnings && warnings.length && warnings[0].message;
return this.showErrorModalDefault(error, defaultError, needsTranslate, autocloseTime);
}
/**
* Displays a loading modal window.
*

View File

@ -145,4 +145,12 @@ export class CoreTimeUtilsProvider {
return Math.round(Date.now() / 1000);
}
/**
* Return the localized ISO format (i.e DDMMYY) from the localized moment format. Useful for translations.
*
* @return {string} Localized ISO format
*/
getLocalizedDateFormat(lozalizedFormat) : string {
return moment.localeData().longDateFormat(lozalizedFormat);
}
}