MOBILE-3592 profilefields: Implement user profile fields

main
Dani Palou 2020-12-02 11:05:57 +01:00
parent dbec10b9d6
commit fd0ea51096
28 changed files with 1189 additions and 15 deletions

View File

@ -16,11 +16,13 @@ import { NgModule } from '@angular/core';
import { AddonPrivateFilesModule } from './privatefiles/privatefiles.module'; import { AddonPrivateFilesModule } from './privatefiles/privatefiles.module';
import { AddonFilterModule } from './filter/filter.module'; import { AddonFilterModule } from './filter/filter.module';
import { AddonUserProfileFieldModule } from './userprofilefield/userprofilefield.module';
@NgModule({ @NgModule({
imports: [ imports: [
AddonPrivateFilesModule, AddonPrivateFilesModule,
AddonFilterModule, AddonFilterModule,
AddonUserProfileFieldModule,
], ],
}) })
export class AddonsModule {} export class AddonsModule {}

View File

@ -0,0 +1,56 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonUserProfileFieldCheckboxHandler } from './services/handlers/checkbox';
import { CoreUserProfileFieldDelegate } from '@features/user/services/user-profile-field-delegate';
import { AddonUserProfileFieldCheckboxComponent } from './component/checkbox';
import { CoreComponentsModule } from '@components/components.module';
@NgModule({
declarations: [
AddonUserProfileFieldCheckboxComponent,
],
imports: [
CommonModule,
IonicModule.forRoot(),
TranslateModule.forChild(),
FormsModule,
ReactiveFormsModule,
CoreComponentsModule,
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [CoreUserProfileFieldDelegate, AddonUserProfileFieldCheckboxHandler],
useFactory: (
userProfileFieldDelegate: CoreUserProfileFieldDelegate,
handler: AddonUserProfileFieldCheckboxHandler,
) => () => userProfileFieldDelegate.registerHandler(handler),
},
],
exports: [
AddonUserProfileFieldCheckboxComponent,
],
entryComponents: [
AddonUserProfileFieldCheckboxComponent,
],
})
export class AddonUserProfileFieldCheckboxModule {}

View File

@ -0,0 +1,22 @@
<!-- Render (no edit). -->
<ion-item *ngIf="!edit && field && field.name">
<ion-label>
<h2>{{ field.name }}</h2>
<p *ngIf="value != '0'">
{{ 'core.yes' | translate }}
</p>
<p *ngIf="value == '0'">
{{ 'core.no' | translate }}
</p>
</ion-label>
</ion-item>
<!-- Edit. -->
<ion-item *ngIf="edit && field && field.shortname && form" [formGroup]="form">
<ion-label>
<span [core-mark-required]="required">{{ field.name }}</span>
<core-input-errors [control]="form.controls[modelName]"></core-input-errors>
</ion-label>
<ion-checkbox item-end [formControlName]="modelName">
</ion-checkbox>
</ion-item>

View File

@ -0,0 +1,45 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component } from '@angular/core';
import { Validators, FormControl } from '@angular/forms';
import { AuthEmailSignupProfileField } from '@features/login/services/login-helper';
import { CoreUserProfileFieldBaseComponent } from '@features/user/classes/base-profilefield-component';
import { CoreUtils } from '@services/utils/utils';
/**
* Directive to render a checkbox user profile field.
*/
@Component({
selector: 'addon-user-profile-field-checkbox',
templateUrl: 'addon-user-profile-field-checkbox.html',
})
export class AddonUserProfileFieldCheckboxComponent extends CoreUserProfileFieldBaseComponent {
/**
* Create the Form control.
*
* @return Form control.
*/
protected createFormControl(field: AuthEmailSignupProfileField): FormControl {
const formData = {
value: CoreUtils.instance.isTrueOrOne(field.defaultdata),
disabled: this.disabled,
};
return new FormControl(formData, this.required && !field.locked ? Validators.requiredTrue : null);
}
}

View File

@ -0,0 +1,76 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Type } from '@angular/core';
import { AuthEmailSignupProfileField } from '@features/login/services/login-helper';
import { CoreUserProfileField } from '@features/user/services/user';
import { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from '@features/user/services/user-profile-field-delegate';
import { AddonUserProfileFieldCheckboxComponent } from '../../component/checkbox';
/**
* Checkbox user profile field handlers.
*/
@Injectable({ providedIn: 'root' })
export class AddonUserProfileFieldCheckboxHandler implements CoreUserProfileFieldHandler {
name = 'AddonUserProfileFieldCheckbox';
type = 'checkbox';
/**
* Whether or not the handler is enabled on a site level.
*
* @return Promise resolved with true if enabled.
*/
async isEnabled(): Promise<boolean> {
return true;
}
/**
* Get the data to send for the field based on the input data.
*
* @param field User field to get the data for.
* @param signup True if user is in signup page.
* @param registerAuth Register auth method. E.g. 'email'.
* @param formValues Form Values.
* @return Data to send for the field.
*/
async getData(
field: AuthEmailSignupProfileField | CoreUserProfileField,
signup: boolean,
registerAuth: string,
formValues: Record<string, unknown>,
): Promise<CoreUserProfileFieldHandlerData | undefined> {
const name = 'profile_field_' + field.shortname;
if (typeof formValues[name] != 'undefined') {
return {
type: 'checkbox',
name: name,
value: formValues[name] ? 1 : 0,
};
}
}
/**
* Return the Component to use to display the user profile field.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @return The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(): Type<unknown> | Promise<Type<unknown>> {
return AddonUserProfileFieldCheckboxComponent;
}
}

View File

@ -0,0 +1,18 @@
<!-- Render (no edit). -->
<ion-item *ngIf="!edit && field && field.name">
<ion-label>
<h2>{{ field.name }}</h2>
<p>{{ valueNumber * 1000 | coreFormatDate }}</p>
</ion-label>
</ion-item>
<!-- Edit. -->
<ion-item *ngIf="edit && field && field.shortname && form" text-wrap [formGroup]="form">
<ion-label position="stacked">
<span [core-mark-required]="required">{{ field.name }}</span>
</ion-label>
<ion-datetime [formControlName]="modelName" [placeholder]="'core.choosedots' | translate" [displayFormat]="format"
[max]="max" [min]="min">
</ion-datetime>
<core-input-errors [control]="form.controls[modelName]"></core-input-errors>
</ion-item>

View File

@ -0,0 +1,95 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { FormControl, Validators } from '@angular/forms';
import { Component } from '@angular/core';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreUtils } from '@services/utils/utils';
import { AuthEmailSignupProfileField } from '@features/login/services/login-helper';
import { CoreUserProfileField } from '@features/user/services/user';
import { Translate } from '@singletons';
import { CoreUserProfileFieldBaseComponent } from '@features/user/classes/base-profilefield-component';
/**
* Directive to render a datetime user profile field.
*/
@Component({
selector: 'addon-user-profile-field-datetime',
templateUrl: 'addon-user-profile-field-datetime.html',
})
export class AddonUserProfileFieldDatetimeComponent extends CoreUserProfileFieldBaseComponent {
format?: string;
min?: number;
max?: number;
valueNumber = 0;
/**
* Init the data when the field is meant to be displayed without editing.
*
* @param field Field to render.
*/
protected initForNonEdit(field: CoreUserProfileField): void {
this.valueNumber = Number(field.value);
}
/**
* Init the data when the field is meant to be displayed for editing.
*
* @param field Field to render.
*/
protected initForEdit(field: AuthEmailSignupProfileField): void {
super.initForEdit(field);
// Check if it's only date or it has time too.
const hasTime = CoreUtils.instance.isTrueOrOne(field.param3);
// Calculate format to use.
this.format = CoreTimeUtils.instance.fixFormatForDatetime(CoreTimeUtils.instance.convertPHPToMoment(
Translate.instance.instant('core.' + (hasTime ? 'strftimedatetime' : 'strftimedate')),
));
// Check min value.
if (field.param1) {
const year = parseInt(field.param1, 10);
if (year) {
this.min = year;
}
}
// Check max value.
if (field.param2) {
const year = parseInt(field.param2, 10);
if (year) {
this.max = year;
}
}
}
/**
* Create the Form control.
*
* @return Form control.
*/
protected createFormControl(field: AuthEmailSignupProfileField): FormControl {
const formData = {
value: field.defaultdata != '0' ? field.defaultdata : undefined,
disabled: this.disabled,
};
return new FormControl(formData, this.required && !field.locked ? Validators.required : null);
}
}

View File

@ -0,0 +1,58 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonUserProfileFieldDatetimeHandler } from './services/handlers/datetime';
import { CoreUserProfileFieldDelegate } from '@features/user/services/user-profile-field-delegate';
import { AddonUserProfileFieldDatetimeComponent } from './component/datetime';
import { CoreComponentsModule } from '@components/components.module';
import { CorePipesModule } from '@pipes/pipes.module';
@NgModule({
declarations: [
AddonUserProfileFieldDatetimeComponent,
],
imports: [
CommonModule,
IonicModule.forRoot(),
TranslateModule.forChild(),
FormsModule,
ReactiveFormsModule,
CoreComponentsModule,
CorePipesModule,
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [CoreUserProfileFieldDelegate, AddonUserProfileFieldDatetimeHandler],
useFactory: (
userProfileFieldDelegate: CoreUserProfileFieldDelegate,
handler: AddonUserProfileFieldDatetimeHandler,
) => () => userProfileFieldDelegate.registerHandler(handler),
},
],
exports: [
AddonUserProfileFieldDatetimeComponent,
],
entryComponents: [
AddonUserProfileFieldDatetimeComponent,
],
})
export class AddonUserProfileFieldDatetimeModule {}

View File

@ -0,0 +1,78 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Type } from '@angular/core';
import { AuthEmailSignupProfileField } from '@features/login/services/login-helper';
import { CoreUserProfileField } from '@features/user/services/user';
import { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from '@features/user/services/user-profile-field-delegate';
import { CoreTimeUtils } from '@services/utils/time';
import { AddonUserProfileFieldDatetimeComponent } from '../../component/datetime';
/**
* Datetime user profile field handlers.
*/
@Injectable({ providedIn: 'root' })
export class AddonUserProfileFieldDatetimeHandler implements CoreUserProfileFieldHandler {
name = 'AddonUserProfileFieldDatetime';
type = 'datetime';
/**
* Whether or not the handler is enabled on a site level.
*
* @return Promise resolved with true if enabled.
*/
async isEnabled(): Promise<boolean> {
return true;
}
/**
* Get the data to send for the field based on the input data.
*
* @param field User field to get the data for.
* @param signup True if user is in signup page.
* @param registerAuth Register auth method. E.g. 'email'.
* @param formValues Form Values.
* @return Data to send for the field.
*/
async getData(
field: AuthEmailSignupProfileField | CoreUserProfileField,
signup: boolean,
registerAuth: string,
formValues: Record<string, unknown>,
): Promise<CoreUserProfileFieldHandlerData | undefined> {
const name = 'profile_field_' + field.shortname;
if (formValues[name]) {
return {
type: 'datetime',
name: 'profile_field_' + field.shortname,
value: CoreTimeUtils.instance.convertToTimestamp(<string> formValues[name]),
};
}
}
/**
* Return the Component to use to display the user profile field.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param injector Injector.
* @return The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(): Type<unknown> | Promise<Type<unknown>> {
return AddonUserProfileFieldDatetimeComponent;
}
}

View File

@ -0,0 +1,21 @@
<!-- Render (no edit). -->
<ion-item *ngIf="!edit && field && field.name">
<ion-label>
<h2>{{ field.name }}</h2>
<p><core-format-text [text]="value" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId"
[courseId]="courseId">
</core-format-text></p>
</ion-label>
</ion-item>
<!-- Edit. -->
<ion-item *ngIf="edit && field && field.shortname && form" text-wrap [formGroup]="form">
<ion-label position="stacked">
<span [core-mark-required]="required">{{ field.name }}</span>
</ion-label>
<ion-select [formControlName]="modelName" [placeholder]="'core.choosedots' | translate" interface="action-sheet">
<ion-select-option value="">{{ 'core.choosedots' | translate }}</ion-select-option>
<ion-select-option *ngFor="let option of options" [value]="option">{{option}}</ion-select-option>
</ion-select>
<core-input-errors [control]="form.controls[modelName]"></core-input-errors>
</ion-item>

View File

@ -0,0 +1,47 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component } from '@angular/core';
import { AuthEmailSignupProfileField } from '@features/login/services/login-helper';
import { CoreUserProfileFieldBaseComponent } from '@features/user/classes/base-profilefield-component';
/**
* Directive to render a menu user profile field.
*/
@Component({
selector: 'addon-user-profile-field-menu',
templateUrl: 'addon-user-profile-field-menu.html',
})
export class AddonUserProfileFieldMenuComponent extends CoreUserProfileFieldBaseComponent {
options?: string[];
/**
* Init the data when the field is meant to be displayed for editing.
*
* @param field Field to render.
*/
protected initForEdit(field: AuthEmailSignupProfileField): void {
super.initForEdit(field);
// Parse options.
if (field.param1) {
this.options = field.param1.split(/\r\n|\r|\n/g);
} else {
this.options = [];
}
}
}

View File

@ -0,0 +1,58 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonUserProfileFieldMenuHandler } from './services/handlers/menu';
import { CoreUserProfileFieldDelegate } from '@features/user/services/user-profile-field-delegate';
import { AddonUserProfileFieldMenuComponent } from './component/menu';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [
AddonUserProfileFieldMenuComponent,
],
imports: [
CommonModule,
IonicModule.forRoot(),
TranslateModule.forChild(),
FormsModule,
ReactiveFormsModule,
CoreComponentsModule,
CoreDirectivesModule,
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [CoreUserProfileFieldDelegate, AddonUserProfileFieldMenuHandler],
useFactory: (
userProfileFieldDelegate: CoreUserProfileFieldDelegate,
handler: AddonUserProfileFieldMenuHandler,
) => () => userProfileFieldDelegate.registerHandler(handler),
},
],
exports: [
AddonUserProfileFieldMenuComponent,
],
entryComponents: [
AddonUserProfileFieldMenuComponent,
],
})
export class AddonUserProfileFieldMenuModule {}

View File

@ -0,0 +1,76 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Type } from '@angular/core';
import { AuthEmailSignupProfileField } from '@features/login/services/login-helper';
import { CoreUserProfileField } from '@features/user/services/user';
import { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from '@features/user/services/user-profile-field-delegate';
import { AddonUserProfileFieldMenuComponent } from '../../component/menu';
/**
* Menu user profile field handlers.
*/
@Injectable({ providedIn: 'root' })
export class AddonUserProfileFieldMenuHandler implements CoreUserProfileFieldHandler {
name = 'AddonUserProfileFieldMenu';
type = 'menu';
/**
* Whether or not the handler is enabled on a site level.
*
* @return Promise resolved with true if enabled.
*/
async isEnabled(): Promise<boolean> {
return true;
}
/**
* Get the data to send for the field based on the input data.
*
* @param field User field to get the data for.
* @param signup True if user is in signup page.
* @param registerAuth Register auth method. E.g. 'email'.
* @param formValues Form Values.
* @return Data to send for the field.
*/
async getData(
field: AuthEmailSignupProfileField | CoreUserProfileField,
signup: boolean,
registerAuth: string,
formValues: Record<string, unknown>,
): Promise<CoreUserProfileFieldHandlerData | undefined> {
const name = 'profile_field_' + field.shortname;
if (formValues[name]) {
return {
type: 'menu',
name: name,
value: formValues[name],
};
}
}
/**
* Return the Component to use to display the user profile field.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @return The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(): Type<unknown> | Promise<Type<unknown>> {
return AddonUserProfileFieldMenuComponent;
}
}

View File

@ -0,0 +1,18 @@
<!-- Render (no edit). -->
<ion-item *ngIf="!edit && field && field.name">
<ion-label>
<h2>{{ field.name }}</h2>
<p><core-format-text [text]="value" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId"
[courseId]="courseId">
</core-format-text></p>
</ion-label>
</ion-item>
<!-- Edit. -->
<ion-item *ngIf="edit && field && field.shortname && form" text-wrap [formGroup]="form">
<ion-label position="stacked">
<span [core-mark-required]="required">{{ field.name }}</span>
</ion-label>
<ion-input [type]="inputType" [formControlName]="modelName" [placeholder]="field.name" maxlength="{{maxLength}}"></ion-input>
<core-input-errors [control]="form.controls[modelName]"></core-input-errors>
</ion-item>

View File

@ -0,0 +1,50 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component } from '@angular/core';
import { AuthEmailSignupProfileField } from '@features/login/services/login-helper';
import { CoreUserProfileFieldBaseComponent } from '@features/user/classes/base-profilefield-component';
import { CoreUtils } from '@services/utils/utils';
/**
* Directive to render a text user profile field.
*/
@Component({
selector: 'addon-user-profile-field-text',
templateUrl: 'addon-user-profile-field-text.html',
})
export class AddonUserProfileFieldTextComponent extends CoreUserProfileFieldBaseComponent {
inputType?: string;
maxLength?: number;
/**
* Init the data when the field is meant to be displayed for editing.
*
* @param field Field to render.
*/
protected initForEdit(field: AuthEmailSignupProfileField): void {
super.initForEdit(field);
// Check max length.
if (field.param2) {
this.maxLength = parseInt(field.param2, 10) || Number.MAX_VALUE;
}
// Check if it's a password or text.
this.inputType = CoreUtils.instance.isTrueOrOne(field.param3) ? 'password' : 'text';
}
}

View File

@ -0,0 +1,75 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Type } from '@angular/core';
import { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from '@features/user/services/user-profile-field-delegate';
import { AddonUserProfileFieldTextComponent } from '../../component/text';
import { CoreTextUtils } from '@services/utils/text';
import { AuthEmailSignupProfileField } from '@features/login/services/login-helper';
import { CoreUserProfileField } from '@features/user/services/user';
/**
* Text user profile field handlers.
*/
@Injectable({ providedIn: 'root' })
export class AddonUserProfileFieldTextHandler implements CoreUserProfileFieldHandler {
name = 'AddonUserProfileFieldText';
type = 'text';
/**
* Whether or not the handler is enabled on a site level.
*
* @return True or promise resolved with true if enabled.
*/
async isEnabled(): Promise<boolean> {
return true;
}
/**
* Get the data to send for the field based on the input data.
*
* @param field User field to get the data for.
* @param signup True if user is in signup page.
* @param registerAuth Register auth method. E.g. 'email'.
* @param formValues Form Values.
* @return Data to send for the field.
*/
async getData(
field: AuthEmailSignupProfileField | CoreUserProfileField,
signup: boolean,
registerAuth: string,
formValues: Record<string, unknown>,
): Promise<CoreUserProfileFieldHandlerData | undefined> {
const name = 'profile_field_' + field.shortname;
return {
type: 'text',
name: name,
value: CoreTextUtils.instance.cleanTags(<string> formValues[name]),
};
}
/**
* Return the Component to use to display the user profile field.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @return The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(): Type<unknown> | Promise<Type<unknown>> {
return AddonUserProfileFieldTextComponent;
}
}

View File

@ -0,0 +1,58 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonUserProfileFieldTextHandler } from './services/handlers/text';
import { CoreUserProfileFieldDelegate } from '@features/user/services/user-profile-field-delegate';
import { AddonUserProfileFieldTextComponent } from './component/text';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [
AddonUserProfileFieldTextComponent,
],
imports: [
CommonModule,
IonicModule.forRoot(),
TranslateModule.forChild(),
FormsModule,
ReactiveFormsModule,
CoreComponentsModule,
CoreDirectivesModule,
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [CoreUserProfileFieldDelegate, AddonUserProfileFieldTextHandler],
useFactory: (
userProfileFieldDelegate: CoreUserProfileFieldDelegate,
handler: AddonUserProfileFieldTextHandler,
) => () => userProfileFieldDelegate.registerHandler(handler),
},
],
exports: [
AddonUserProfileFieldTextComponent,
],
entryComponents: [
AddonUserProfileFieldTextComponent,
],
})
export class AddonUserProfileFieldTextModule {}

View File

@ -0,0 +1,20 @@
<!-- Render (no edit). -->
<ion-item *ngIf="!edit && field && field.name">
<ion-label>
<h2>{{ field.name }}</h2>
<p><core-format-text [text]="value" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId"
[courseId]="courseId">
</core-format-text></p>
</ion-label>
</ion-item>
<!-- Edit. -->
<ion-item *ngIf="edit && field && field.shortname" text-wrap [formGroup]="form">
<ion-label position="stacked">
<span [core-mark-required]="required">{{ field.name }}</span>
<core-input-errors [control]="control"></core-input-errors>
</ion-label>
<!-- @todo <core-rich-text-editor item-content [control]="control" [placeholder]="field.name" [autoSave]="true"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [elementId]="modelName">
</core-rich-text-editor> -->
</ion-item>

View File

@ -0,0 +1,26 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component } from '@angular/core';
import { CoreUserProfileFieldBaseComponent } from '@features/user/classes/base-profilefield-component';
/**
* Directive to render a textarea user profile field.
*/
@Component({
selector: 'addon-user-profile-field-textarea',
templateUrl: 'addon-user-profile-field-textarea.html',
})
export class AddonUserProfileFieldTextareaComponent extends CoreUserProfileFieldBaseComponent {}

View File

@ -0,0 +1,85 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Type } from '@angular/core';
import { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from '@features/user/services/user-profile-field-delegate';
import { AddonUserProfileFieldTextareaComponent } from '../../component/textarea';
import { CoreTextUtils } from '@services/utils/text';
import { AuthEmailSignupProfileField } from '@features/login/services/login-helper';
import { CoreUserProfileField } from '@features/user/services/user';
/**
* Textarea user profile field handlers.
*/
@Injectable({ providedIn: 'root' })
export class AddonUserProfileFieldTextareaHandler implements CoreUserProfileFieldHandler {
name = 'AddonUserProfileFieldTextarea';
type = 'textarea';
/**
* Whether or not the handler is enabled on a site level.
*
* @return True or promise resolved with true if enabled.
*/
async isEnabled(): Promise<boolean> {
return true;
}
/**
* Get the data to send for the field based on the input data.
*
* @param field User field to get the data for.
* @param signup True if user is in signup page.
* @param registerAuth Register auth method. E.g. 'email'.
* @param formValues Form Values.
* @return Data to send for the field.
*/
async getData(
field: AuthEmailSignupProfileField | CoreUserProfileField,
signup: boolean,
registerAuth: string,
formValues: Record<string, unknown>,
): Promise<CoreUserProfileFieldHandlerData | undefined> {
const name = 'profile_field_' + field.shortname;
if (formValues[name]) {
let text = <string> formValues[name] || '';
// Add some HTML to the message in case the user edited with textarea.
text = CoreTextUtils.instance.formatHtmlLines(text);
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.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param injector Injector.
* @return The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(): Type<unknown> | Promise<Type<unknown>> {
return AddonUserProfileFieldTextareaComponent;
}
}

View File

@ -0,0 +1,60 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonUserProfileFieldTextareaHandler } from './services/handlers/textarea';
import { CoreUserProfileFieldDelegate } from '@features/user/services/user-profile-field-delegate';
import { AddonUserProfileFieldTextareaComponent } from './component/textarea';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
// @todo import { CoreEditorComponentsModule } from '@core/editor/components/components.module';
@NgModule({
declarations: [
AddonUserProfileFieldTextareaComponent,
],
imports: [
CommonModule,
IonicModule.forRoot(),
TranslateModule.forChild(),
FormsModule,
ReactiveFormsModule,
CoreComponentsModule,
CoreDirectivesModule,
// CoreEditorComponentsModule,
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [CoreUserProfileFieldDelegate, AddonUserProfileFieldTextareaHandler],
useFactory: (
userProfileFieldDelegate: CoreUserProfileFieldDelegate,
handler: AddonUserProfileFieldTextareaHandler,
) => () => userProfileFieldDelegate.registerHandler(handler),
},
],
exports: [
AddonUserProfileFieldTextareaComponent,
],
entryComponents: [
AddonUserProfileFieldTextareaComponent,
],
})
export class AddonUserProfileFieldTextareaModule {}

View File

@ -0,0 +1,33 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { NgModule } from '@angular/core';
import { AddonUserProfileFieldCheckboxModule } from './checkbox/checkbox.module';
import { AddonUserProfileFieldDatetimeModule } from './datetime/datetime.module';
import { AddonUserProfileFieldMenuModule } from './menu/menu.module';
import { AddonUserProfileFieldTextModule } from './text/text.module';
import { AddonUserProfileFieldTextareaModule } from './textarea/textarea.module';
@NgModule({
declarations: [],
imports: [
AddonUserProfileFieldCheckboxModule,
AddonUserProfileFieldDatetimeModule,
AddonUserProfileFieldMenuModule,
AddonUserProfileFieldTextModule,
AddonUserProfileFieldTextareaModule,
],
exports: [],
})
export class AddonUserProfileFieldModule { }

View File

@ -9,7 +9,7 @@
</ion-header> </ion-header>
<ion-content> <ion-content>
<ion-list> <ion-list>
<ion-item *ngIf="siteInfo" class="ion-text-wrap" core-user-link [userId]="siteInfo.userid"> <ion-item button *ngIf="siteInfo" class="ion-text-wrap" core-user-link [userId]="siteInfo.userid">
<ion-avatar slot="start"></ion-avatar> <!-- @todo core-user-avatar [user]="siteInfo" --> <ion-avatar slot="start"></ion-avatar> <!-- @todo core-user-avatar [user]="siteInfo" -->
<ion-label> <ion-label>
<h2>{{siteInfo.fullname}}</h2> <h2>{{siteInfo.fullname}}</h2>

View File

@ -0,0 +1,100 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, OnInit } from '@angular/core';
import { FormGroup, Validators, FormControl } from '@angular/forms';
import { AuthEmailSignupProfileField } from '@features/login/services/login-helper';
import { CoreUserProfileField } from '@features/user/services/user';
/**
* Base class for components to render a user profile field.
*/
@Component({
template: '',
})
export class CoreUserProfileFieldBaseComponent implements OnInit {
@Input() field?: AuthEmailSignupProfileField | CoreUserProfileField; // The profile field to be rendered.
@Input() edit = false; // True if editing the field. Defaults to false.
@Input() disabled = false; // True if disabled. Defaults to false.
@Input() form?: FormGroup; // Form where to add the form control.
@Input() contextLevel?: string; // The context level.
@Input() contextInstanceId?: number; // The instance ID related to the context.
@Input() courseId?: number; // The course the field belongs to (if any).
control?: FormControl;
modelName = '';
value?: string;
required?: boolean;
/**
* Component being initialized.
*/
ngOnInit(): void {
if (!this.field) {
return;
}
if (!this.edit && 'value' in this.field) {
this.initForNonEdit(this.field);
return;
}
if (this.edit && 'required' in this.field) {
this.initForEdit(this.field);
return;
}
}
/**
* Init the data when the field is meant to be displayed without editing.
*
* @param field Field to render.
*/
protected initForNonEdit(field: CoreUserProfileField): void {
this.value = field.value;
}
/**
* Init the data when the field is meant to be displayed for editing.
*
* @param field Field to render.
*/
protected initForEdit(field: AuthEmailSignupProfileField): void {
this.modelName = 'profile_field_' + field.shortname;
this.required = !!field.required;
this.control = this.createFormControl(field);
this.form?.addControl(this.modelName, this.control);
}
/**
* Create the Form control.
*
* @return Form control.
*/
protected createFormControl(field: AuthEmailSignupProfileField): FormControl {
const formData = {
value: field.defaultdata,
disabled: this.disabled,
};
return new FormControl(formData, this.required && !field.locked ? Validators.required : null);
}
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Component, Input, OnInit, Injector, Type } from '@angular/core'; import { Component, Input, OnInit, Type } from '@angular/core';
import { FormGroup } from '@angular/forms'; import { FormGroup } from '@angular/forms';
import { AuthEmailSignupProfileField } from '@features/login/services/login-helper'; import { AuthEmailSignupProfileField } from '@features/login/services/login-helper';
@ -42,7 +42,6 @@ export class CoreUserProfileFieldComponent implements OnInit {
constructor( constructor(
protected userProfileFieldsDelegate: CoreUserProfileFieldDelegate, protected userProfileFieldsDelegate: CoreUserProfileFieldDelegate,
protected injector: Injector,
) { } ) { }
/** /**
@ -53,7 +52,7 @@ export class CoreUserProfileFieldComponent implements OnInit {
return; return;
} }
this.componentClass = await this.userProfileFieldsDelegate.getComponent(this.injector, this.field, this.signup); this.componentClass = await this.userProfileFieldsDelegate.getComponent(this.field, this.signup);
this.data.field = this.field; this.data.field = this.field;
this.data.edit = CoreUtils.instance.isTrueOrOne(this.edit); this.data.edit = CoreUtils.instance.isTrueOrOne(this.edit);

View File

@ -75,9 +75,9 @@
<p>{{ user.interests }}</p> <p>{{ user.interests }}</p>
</ion-label> </ion-label>
</ion-item> </ion-item>
<!-- @todo <core-user-profile-field *ngFor="let field of user.customfields" [field]="field" contextLevel="course" <core-user-profile-field *ngFor="let field of user.customfields" [field]="field" contextLevel="course"
[contextInstanceId]="courseId" [courseId]="courseId"> [contextInstanceId]="courseId" [courseId]="courseId">
</core-user-profile-field> --> </core-user-profile-field>
</ion-item-group> </ion-item-group>
<ion-item-group *ngIf="user.description"> <ion-item-group *ngIf="user.description">
<ion-item-divider>{{ 'core.user.description' | translate}}</ion-item-divider> <ion-item-divider>{{ 'core.user.description' | translate}}</ion-item-divider>

View File

@ -34,10 +34,10 @@ import { CoreUserHelper } from '@features/user/services/user-helper';
}) })
export class CoreUserAboutPage implements OnInit { export class CoreUserAboutPage implements OnInit {
protected courseId!: number;
protected userId!: number; protected userId!: number;
protected siteId: string; protected siteId: string;
courseId!: number;
userLoaded = false; userLoaded = false;
hasContact = false; hasContact = false;
hasDetails = false; hasDetails = false;

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Injectable, Injector, Type } from '@angular/core'; import { Injectable, Type } from '@angular/core';
import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate';
import { CoreError } from '@classes/errors/error'; import { CoreError } from '@classes/errors/error';
@ -32,10 +32,9 @@ export interface CoreUserProfileFieldHandler extends CoreDelegateHandler {
* Return the Component to use to display the user profile field. * Return the Component to use to display the user profile field.
* It's recommended to return the class of the component, but you can also return an instance of the component. * It's recommended to return the class of the component, but you can also return an instance of the component.
* *
* @param injector Injector.
* @return The component (or promise resolved with component) to use, undefined if not found. * @return The component (or promise resolved with component) to use, undefined if not found.
*/ */
getComponent(injector: Injector): Type<unknown> | Promise<Type<unknown>>; getComponent(): Type<unknown> | Promise<Type<unknown>>;
/** /**
* Get the data to send for the field based on the input data. * Get the data to send for the field based on the input data.
@ -51,7 +50,7 @@ export interface CoreUserProfileFieldHandler extends CoreDelegateHandler {
signup: boolean, signup: boolean,
registerAuth: string, registerAuth: string,
formValues: Record<string, unknown>, formValues: Record<string, unknown>,
): Promise<CoreUserProfileFieldHandlerData>; ): Promise<CoreUserProfileFieldHandlerData | undefined>;
} }
export interface CoreUserProfileFieldHandlerData { export interface CoreUserProfileFieldHandlerData {
@ -104,7 +103,6 @@ export class CoreUserProfileFieldDelegate extends CoreDelegate<CoreUserProfileFi
* @return Promise resolved with component to use, undefined if not found. * @return Promise resolved with component to use, undefined if not found.
*/ */
async getComponent( async getComponent(
injector: Injector,
field: AuthEmailSignupProfileField | CoreUserProfileField, field: AuthEmailSignupProfileField | CoreUserProfileField,
signup: boolean, signup: boolean,
): Promise<Type<unknown> | undefined> { ): Promise<Type<unknown> | undefined> {
@ -112,9 +110,9 @@ export class CoreUserProfileFieldDelegate extends CoreDelegate<CoreUserProfileFi
try { try {
if (signup) { if (signup) {
return await this.executeFunction(type, 'getComponent', [injector]); return await this.executeFunction(type, 'getComponent', []);
} else { } else {
return await this.executeFunctionOnEnabled(type, 'getComponent', [injector]); return await this.executeFunctionOnEnabled(type, 'getComponent', []);
} }
} catch (error) { } catch (error) {
this.logger.error('Error getting component for field', type, error); this.logger.error('Error getting component for field', type, error);
@ -135,7 +133,7 @@ export class CoreUserProfileFieldDelegate extends CoreDelegate<CoreUserProfileFi
signup: boolean, signup: boolean,
registerAuth: string, registerAuth: string,
formValues: Record<string, unknown>, formValues: Record<string, unknown>,
): Promise<CoreUserProfileFieldHandlerData> { ): Promise<CoreUserProfileFieldHandlerData | undefined> {
const type = this.getType(field); const type = this.getType(field);
const handler = this.getHandler(type, !signup); const handler = this.getHandler(type, !signup);