From d7c6c25292b8de809017d08c1206e22c1fb3a26f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Thu, 18 Jan 2018 16:38:41 +0100 Subject: [PATCH] MOBILE-2317 login: Add custom user profile field to sign-up --- .../checkbox/component/checkbox.html | 5 +- .../checkbox/component/checkbox.scss | 0 .../checkbox/component/checkbox.ts | 18 +++-- .../checkbox/providers/handler.ts | 13 ++-- .../datetime/component/datetime.html | 6 +- .../datetime/component/datetime.scss | 0 .../datetime/component/datetime.ts | 22 ++++-- .../datetime/providers/handler.ts | 30 ++------ .../userprofilefield/menu/component/menu.html | 6 +- .../userprofilefield/menu/component/menu.scss | 0 .../userprofilefield/menu/component/menu.ts | 18 +++-- .../menu/providers/handler.ts | 13 ++-- .../userprofilefield/text/component/text.html | 6 +- .../userprofilefield/text/component/text.scss | 0 .../userprofilefield/text/component/text.ts | 18 +++-- .../text/providers/handler.ts | 11 ++- .../textarea/component/textarea.html | 8 +-- .../textarea/component/textarea.scss | 0 .../textarea/component/textarea.ts | 26 ++++--- .../textarea/providers/handler.ts | 42 +++++------- src/classes/delegate.ts | 46 +++++++++++-- src/core/login/login.module.ts | 2 +- .../pages/email-signup/email-signup.html | 20 +++--- .../pages/email-signup/email-signup.module.ts | 2 + .../login/pages/email-signup/email-signup.ts | 33 ++++----- src/core/login/providers/helper.ts | 10 +-- .../user-profile-field/user-profile-field.ts | 17 +++-- src/core/user/lang/en.json | 3 + src/core/user/providers/helper.ts | 1 - .../providers/user-profile-field-delegate.ts | 68 +++++++------------ src/providers/utils/dom.ts | 14 ++++ src/providers/utils/time.ts | 8 +++ 32 files changed, 253 insertions(+), 213 deletions(-) delete mode 100644 src/addon/userprofilefield/checkbox/component/checkbox.scss delete mode 100644 src/addon/userprofilefield/datetime/component/datetime.scss delete mode 100644 src/addon/userprofilefield/menu/component/menu.scss delete mode 100644 src/addon/userprofilefield/text/component/text.scss delete mode 100644 src/addon/userprofilefield/textarea/component/textarea.scss diff --git a/src/addon/userprofilefield/checkbox/component/checkbox.html b/src/addon/userprofilefield/checkbox/component/checkbox.html index 8ab6fe45f..41170009e 100644 --- a/src/addon/userprofilefield/checkbox/component/checkbox.html +++ b/src/addon/userprofilefield/checkbox/component/checkbox.html @@ -9,8 +9,9 @@

- + {{ field.name }} - + + \ No newline at end of file diff --git a/src/addon/userprofilefield/checkbox/component/checkbox.scss b/src/addon/userprofilefield/checkbox/component/checkbox.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/addon/userprofilefield/checkbox/component/checkbox.ts b/src/addon/userprofilefield/checkbox/component/checkbox.ts index 28f11a4bf..b909bfac7 100644 --- a/src/addon/userprofilefield/checkbox/component/checkbox.ts +++ b/src/addon/userprofilefield/checkbox/component/checkbox.ts @@ -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)); } } diff --git a/src/addon/userprofilefield/checkbox/providers/handler.ts b/src/addon/userprofilefield/checkbox/providers/handler.ts index 69c7ac051..ee5147f99 100644 --- a/src/addon/userprofilefield/checkbox/providers/handler.ts +++ b/src/addon/userprofilefield/checkbox/providers/handler.ts @@ -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; } diff --git a/src/addon/userprofilefield/datetime/component/datetime.html b/src/addon/userprofilefield/datetime/component/datetime.html index cd19d4595..57b8e7ca2 100644 --- a/src/addon/userprofilefield/datetime/component/datetime.html +++ b/src/addon/userprofilefield/datetime/component/datetime.html @@ -4,7 +4,7 @@

{{ field.value * 1000 | coreFormatDate:"dfmediumdate"}}

- - {{ field.name }} - + + {{ field.name }} + \ No newline at end of file diff --git a/src/addon/userprofilefield/datetime/component/datetime.scss b/src/addon/userprofilefield/datetime/component/datetime.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/addon/userprofilefield/datetime/component/datetime.ts b/src/addon/userprofilefield/datetime/component/datetime.ts index 4526abc5e..737b6bed7 100644 --- a/src/addon/userprofilefield/datetime/component/datetime.ts +++ b/src/addon/userprofilefield/datetime/component/datetime.ts @@ -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)); } } diff --git a/src/addon/userprofilefield/datetime/providers/handler.ts b/src/addon/userprofilefield/datetime/providers/handler.ts index ad3c95414..16e1f7048 100644 --- a/src/addon/userprofilefield/datetime/providers/handler.ts +++ b/src/addon/userprofilefield/datetime/providers/handler.ts @@ -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; } diff --git a/src/addon/userprofilefield/menu/component/menu.html b/src/addon/userprofilefield/menu/component/menu.html index 23ee49f9b..68198ddc9 100644 --- a/src/addon/userprofilefield/menu/component/menu.html +++ b/src/addon/userprofilefield/menu/component/menu.html @@ -4,9 +4,9 @@

- - {{ field.name }} - + + {{ field.name }} + {{ 'core.choosedots' | translate }} {{option}} diff --git a/src/addon/userprofilefield/menu/component/menu.scss b/src/addon/userprofilefield/menu/component/menu.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/addon/userprofilefield/menu/component/menu.ts b/src/addon/userprofilefield/menu/component/menu.ts index 98bf2f43b..a7048af52 100644 --- a/src/addon/userprofilefield/menu/component/menu.ts +++ b/src/addon/userprofilefield/menu/component/menu.ts @@ -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)); } } diff --git a/src/addon/userprofilefield/menu/providers/handler.ts b/src/addon/userprofilefield/menu/providers/handler.ts index 470fd1d3d..7a04a2b61 100644 --- a/src/addon/userprofilefield/menu/providers/handler.ts +++ b/src/addon/userprofilefield/menu/providers/handler.ts @@ -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; } diff --git a/src/addon/userprofilefield/text/component/text.html b/src/addon/userprofilefield/text/component/text.html index c27315320..aaa43b1ac 100644 --- a/src/addon/userprofilefield/text/component/text.html +++ b/src/addon/userprofilefield/text/component/text.html @@ -4,7 +4,7 @@

- - {{ field.name }} - + + {{ field.name }} + diff --git a/src/addon/userprofilefield/text/component/text.scss b/src/addon/userprofilefield/text/component/text.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/addon/userprofilefield/text/component/text.ts b/src/addon/userprofilefield/text/component/text.ts index f8fd5b72e..3efb230e5 100644 --- a/src/addon/userprofilefield/text/component/text.ts +++ b/src/addon/userprofilefield/text/component/text.ts @@ -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)); } } diff --git a/src/addon/userprofilefield/text/providers/handler.ts b/src/addon/userprofilefield/text/providers/handler.ts index 30949f452..cd6754e70 100644 --- a/src/addon/userprofilefield/text/providers/handler.ts +++ b/src/addon/userprofilefield/text/providers/handler.ts @@ -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; } diff --git a/src/addon/userprofilefield/textarea/component/textarea.html b/src/addon/userprofilefield/textarea/component/textarea.html index 003d70ef2..4921c3675 100644 --- a/src/addon/userprofilefield/textarea/component/textarea.html +++ b/src/addon/userprofilefield/textarea/component/textarea.html @@ -4,7 +4,7 @@

- - {{ field.name }} - - + + {{ field.name }} + + \ No newline at end of file diff --git a/src/addon/userprofilefield/textarea/component/textarea.scss b/src/addon/userprofilefield/textarea/component/textarea.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/addon/userprofilefield/textarea/component/textarea.ts b/src/addon/userprofilefield/textarea/component/textarea.ts index 967c4081c..dbcf50dfc 100644 --- a/src/addon/userprofilefield/textarea/component/textarea.ts +++ b/src/addon/userprofilefield/textarea/component/textarea.ts @@ -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); } } \ No newline at end of file diff --git a/src/addon/userprofilefield/textarea/providers/handler.ts b/src/addon/userprofilefield/textarea/providers/handler.ts index 544c2ad3e..9604e9a6e 100644 --- a/src/addon/userprofilefield/textarea/providers/handler.ts +++ b/src/addon/userprofilefield/textarea/providers/handler.ts @@ -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} 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 { + 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; } diff --git a/src/classes/delegate.ts b/src/classes/delegate.ts index 3185bf435..d9d472fd2 100644 --- a/src/classes/delegate.ts +++ b/src/classes/delegate.ts @@ -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() { } - } \ No newline at end of file diff --git a/src/core/login/login.module.ts b/src/core/login/login.module.ts index e13f72e96..8e4f9a3d8 100644 --- a/src/core/login/login.module.ts +++ b/src/core/login/login.module.ts @@ -21,7 +21,7 @@ import { CoreLoginHelperProvider } from './providers/helper'; imports: [ ], providers: [ - CoreLoginHelperProvider, + CoreLoginHelperProvider ] }) export class CoreLoginModule {} diff --git a/src/core/login/pages/email-signup/email-signup.html b/src/core/login/pages/email-signup/email-signup.html index e90bddbb5..c3fd44236 100644 --- a/src/core/login/pages/email-signup/email-signup.html +++ b/src/core/login/pages/email-signup/email-signup.html @@ -75,14 +75,14 @@
- - + + + {{ category.name }} + + -
+ {{ 'core.login.security_question' | translate }} {{ 'core.login.recaptchachallengeimage' | translate }} @@ -96,20 +96,20 @@ {{ 'core.login.getanothercaptcha' | translate }} -
+ -
+ {{ 'core.login.policyagreement' | translate }}

{{ 'core.login.policyagreementclick' | translate }}

{{ 'core.login.policyaccept' | translate }} - + -
+ diff --git a/src/core/login/pages/email-signup/email-signup.module.ts b/src/core/login/pages/email-signup/email-signup.module.ts index 451715de6..422f4271f 100644 --- a/src/core/login/pages/email-signup/email-signup.module.ts +++ b/src/core/login/pages/email-signup/email-signup.module.ts @@ -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() ] diff --git a/src/core/login/pages/email-signup/email-signup.ts b/src/core/login/pages/email-signup/email-signup.ts index 86bca81d8..c351f4aab 100644 --- a/src/core/login/pages/email-signup/email-signup.ts +++ b/src/core/login/pages/email-signup/email-signup.ts @@ -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); diff --git a/src/core/login/providers/helper.ts b/src/core/login/providers/helper.ts index 28db16e29..1706f28cc 100644 --- a/src/core/login/providers/helper.ts +++ b/src/core/login/providers/helper.ts @@ -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]; + }); } /** diff --git a/src/core/user/components/user-profile-field/user-profile-field.ts b/src/core/user/components/user-profile-field/user-profile-field.ts index 1b3dcfee0..b79bdfd0f 100644 --- a/src/core/user/components/user-profile-field/user-profile-field.ts +++ b/src/core/user/components/user-profile-field/user-profile-field.ts @@ -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) { diff --git a/src/core/user/lang/en.json b/src/core/user/lang/en.json index 6ea4eb277..d5390b8ac 100644 --- a/src/core/user/lang/en.json +++ b/src/core/user/lang/en.json @@ -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", diff --git a/src/core/user/providers/helper.ts b/src/core/user/providers/helper.ts index e09c223d5..e4d6eeb05 100644 --- a/src/core/user/providers/helper.ts +++ b/src/core/user/providers/helper.ts @@ -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; }); diff --git a/src/core/user/providers/user-profile-field-delegate.ts b/src/core/user/providers/user-profile-field-delegate.ts index b3b8784dd..72cbc2b5a 100644 --- a/src/core/user/providers/user-profile-field-delegate.ts +++ b/src/core/user/providers/user-profile-field-delegate.ts @@ -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} 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; }; @@ -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} Data to send for the field. */ - getDataForField(field: any, signup: boolean, registerAuth: string, model: any): Promise { - let handler = this.getHandler(field, signup); - + getDataForField(field: any, signup: boolean, registerAuth: string, formValues: any): Promise { + 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} Data to send. */ - getDataForFields(fields: any[], signup = false, registerAuth = "", model: any): Promise { + getDataForFields(fields: any[], signup = false, registerAuth = "", formValues: any): Promise { 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]; - } } diff --git a/src/providers/utils/dom.ts b/src/providers/utils/dom.ts index 5e4df4f10..ae8918b95 100644 --- a/src/providers/utils/dom.ts +++ b/src/providers/utils/dom.ts @@ -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. * diff --git a/src/providers/utils/time.ts b/src/providers/utils/time.ts index 3382e77eb..69d62f5f0 100644 --- a/src/providers/utils/time.ts +++ b/src/providers/utils/time.ts @@ -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); + } }