MOBILE-4009 core: Create a generic password modal
parent
c819f2eedd
commit
2804951810
|
@ -18,13 +18,11 @@ import { CoreSharedModule } from '@/core/shared.module';
|
|||
import { CoreCourseComponentsModule } from '@features/course/components/components.module';
|
||||
import { AddonModLessonIndexComponent } from './index/index';
|
||||
import { AddonModLessonMenuModalPage } from './menu-modal/menu-modal';
|
||||
import { AddonModLessonPasswordModalComponent } from './password-modal/password-modal';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModLessonIndexComponent,
|
||||
AddonModLessonMenuModalPage,
|
||||
AddonModLessonPasswordModalComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
|
@ -35,7 +33,6 @@ import { AddonModLessonPasswordModalComponent } from './password-modal/password-
|
|||
exports: [
|
||||
AddonModLessonIndexComponent,
|
||||
AddonModLessonMenuModalPage,
|
||||
AddonModLessonPasswordModalComponent,
|
||||
],
|
||||
})
|
||||
export class AddonModLessonComponentsModule {}
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreCanceledError } from '@classes/errors/cancelederror';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
|
||||
import { CoreCourseActivityPrefetchHandlerBase } from '@features/course/classes/activity-prefetch-handler';
|
||||
|
@ -26,7 +25,6 @@ import { CoreDomUtils } from '@services/utils/dom';
|
|||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreWSFile } from '@services/ws';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { AddonModLessonPasswordModalComponent } from '../../components/password-modal/password-modal';
|
||||
import {
|
||||
AddonModLesson,
|
||||
AddonModLessonGetAccessInformationWSResponse,
|
||||
|
@ -55,15 +53,11 @@ export class AddonModLessonPrefetchHandlerService extends CoreCourseActivityPref
|
|||
*/
|
||||
protected async askUserPassword(): Promise<string> {
|
||||
// Create and show the modal.
|
||||
const modalData = await CoreDomUtils.openModal<string>({
|
||||
component: AddonModLessonPasswordModalComponent,
|
||||
return CoreDomUtils.promptPassword({
|
||||
title: 'addon.mod_lesson.enterpassword',
|
||||
placeholder: 'core.login.password',
|
||||
submit: 'addon.mod_lesson.continue',
|
||||
});
|
||||
|
||||
if (typeof modalData != 'string') {
|
||||
throw new CoreCanceledError();
|
||||
}
|
||||
|
||||
return modalData;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>
|
||||
<h1>{{ 'core.login.password' | translate }}</h1>
|
||||
<h1>{{ title | translate }}</h1>
|
||||
</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
|
||||
|
@ -10,19 +10,18 @@
|
|||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-padding addon-mod_lesson-password-modal">
|
||||
<form (ngSubmit)="submitPassword($event, passwordinput)" #passwordForm>
|
||||
<ion-content class="ion-padding">
|
||||
<form (ngSubmit)="submitPassword($event)" #passwordForm class="ion-padding-vertical">
|
||||
<ion-item>
|
||||
<ion-label>{{ 'addon.mod_lesson.enterpassword' | translate }}</ion-label>
|
||||
<ion-label class="sr-only">{{ placeholder | translate }}</ion-label>
|
||||
<core-show-password name="password">
|
||||
<ion-input name="password" type="password" placeholder="{{ 'core.login.password' | translate }}" core-auto-focus
|
||||
#passwordinput [clearOnEdit]="false">
|
||||
<ion-input class="ion-text-wrap core-ioninput-password" name="password" type="password"
|
||||
placeholder="{{ placeholder | translate }}" [(ngModel)]="password" core-auto-focus [clearOnEdit]="false">
|
||||
</ion-input>
|
||||
</core-show-password>
|
||||
</ion-item>
|
||||
<ion-button expand="block" type="submit">
|
||||
{{ 'addon.mod_lesson.continue' | translate }}
|
||||
<ion-icon slot="end" name="fas-chevron-right" aria-hidden="true"></ion-icon>
|
||||
<ion-button expand="block" type="submit" [disabled]="!password">
|
||||
{{ submit | translate }}
|
||||
</ion-button>
|
||||
<!-- Remove this once Ionic fixes this bug: https://github.com/ionic-team/ionic-framework/issues/19368 -->
|
||||
<input type="submit" class="core-submit-hidden-enter" />
|
|
@ -0,0 +1,29 @@
|
|||
// (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 { CorePasswordModalComponent } from './password-modal';
|
||||
import { CoreSharedModule } from '@/core/shared.module';
|
||||
|
||||
export { CorePasswordModalComponent };
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CorePasswordModalComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
],
|
||||
})
|
||||
export class CorePasswordModalModule {}
|
|
@ -12,37 +12,42 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, ViewChild, ElementRef } from '@angular/core';
|
||||
import { IonInput } from '@ionic/angular';
|
||||
import { Component, ViewChild, ElementRef, Input } from '@angular/core';
|
||||
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreForms } from '@singletons/form';
|
||||
import { ModalController } from '@singletons';
|
||||
|
||||
/**
|
||||
* Modal that asks the password for a lesson.
|
||||
* Modal that asks the password.
|
||||
*
|
||||
* WARNING: This component is not loaded with components.module.ts.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'page-addon-mod-lesson-password-modal',
|
||||
selector: 'core-password-modal',
|
||||
templateUrl: 'password-modal.html',
|
||||
})
|
||||
export class AddonModLessonPasswordModalComponent {
|
||||
export class CorePasswordModalComponent {
|
||||
|
||||
@ViewChild('passwordForm') formElement?: ElementRef;
|
||||
|
||||
@Input() title? = 'core.login.password'; // Translatable string to be shown on modal title.
|
||||
@Input() placeholder? = 'core.login.password'; // Translatable string to be shown on password input as placeholder.
|
||||
@Input() submit? = 'core.submit'; // Translatable string to be shown on submit button.
|
||||
@Input() password? = ''; // Previous entered password.
|
||||
|
||||
/**
|
||||
* Send the password back.
|
||||
*
|
||||
* @param e Event.
|
||||
* @param password The input element.
|
||||
*/
|
||||
submitPassword(e: Event, password: IonInput): void {
|
||||
submitPassword(e: Event): void {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
CoreForms.triggerFormSubmittedEvent(this.formElement, false, CoreSites.getCurrentSiteId());
|
||||
|
||||
ModalController.dismiss(password.value);
|
||||
ModalController.dismiss(this.password);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,3 +60,5 @@ export class AddonModLessonPasswordModalComponent {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
export type CorePasswordModalParams = Pick<CorePasswordModalComponent, 'title' | 'placeholder' | 'submit' | 'password'>;
|
|
@ -31,7 +31,6 @@ import {
|
|||
} from '@features/course/services/course-options-delegate';
|
||||
import { CoreCourseHelper } from '@features/course/services/course-helper';
|
||||
import { ActionSheetController, ModalController, NgZone, Translate } from '@singletons';
|
||||
import { CoreCoursesSelfEnrolPasswordComponent } from '../../../courses/components/self-enrol-password/self-enrol-password';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreCoursesHelper, CoreCourseWithImageAndColor } from '@features/courses/services/courses-helper';
|
||||
|
@ -374,25 +373,23 @@ export class CoreCourseSummaryPage implements OnInit, OnDestroy {
|
|||
modal?.dismiss();
|
||||
|
||||
if (error && error.errorcode === CoreCoursesProvider.ENROL_INVALID_KEY) {
|
||||
// Initialize the self enrol modal.
|
||||
// Invalid password, show the modal to enter the password.
|
||||
const modalData = await CoreDomUtils.openModal<string>(
|
||||
{
|
||||
component: CoreCoursesSelfEnrolPasswordComponent,
|
||||
componentProps: { password },
|
||||
},
|
||||
);
|
||||
|
||||
if (modalData !== undefined) {
|
||||
try {
|
||||
// Initialize the self enrol modal.
|
||||
// Invalid password, show the modal to enter the password.
|
||||
const modalData = await CoreDomUtils.promptPassword({
|
||||
password,
|
||||
title: 'core.courses.selfenrolment',
|
||||
placeholder: 'core.courses.password',
|
||||
submit: 'core.courses.enrolme',
|
||||
});
|
||||
|
||||
this.selfEnrolInCourse(instanceId, modalData);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
} catch {
|
||||
// No password entered, don't show error.
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CoreDomUtils.showErrorModalDefault(error, 'core.courses.errorselfenrol', true);
|
||||
|
|
|
@ -18,14 +18,12 @@ import { CoreSharedModule } from '@/core/shared.module';
|
|||
import { CoreCoursesCourseListItemComponent } from './course-list-item/course-list-item';
|
||||
import { CoreCoursesCourseProgressComponent } from './course-progress/course-progress';
|
||||
import { CoreCoursesCourseOptionsMenuComponent } from './course-options-menu/course-options-menu';
|
||||
import { CoreCoursesSelfEnrolPasswordComponent } from './self-enrol-password/self-enrol-password';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreCoursesCourseListItemComponent,
|
||||
CoreCoursesCourseProgressComponent,
|
||||
CoreCoursesCourseOptionsMenuComponent,
|
||||
CoreCoursesSelfEnrolPasswordComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
|
@ -34,7 +32,6 @@ import { CoreCoursesSelfEnrolPasswordComponent } from './self-enrol-password/sel
|
|||
CoreCoursesCourseListItemComponent,
|
||||
CoreCoursesCourseProgressComponent,
|
||||
CoreCoursesCourseOptionsMenuComponent,
|
||||
CoreCoursesSelfEnrolPasswordComponent,
|
||||
],
|
||||
})
|
||||
export class CoreCoursesComponentsModule {}
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>
|
||||
<h1>{{ 'core.courses.selfenrolment' | translate }}</h1>
|
||||
</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button fill="clear" (click)="close()" [attr.aria-label]="'core.close' | translate">
|
||||
<ion-icon name="fas-xmark" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content class="ion-padding">
|
||||
<form (ngSubmit)="submitPassword($event)" #enrolPasswordForm>
|
||||
<ion-item>
|
||||
<ion-label class="sr-only">{{ 'core.courses.password' | translate }}</ion-label>
|
||||
<core-show-password name="password">
|
||||
<ion-input class="ion-text-wrap core-ioninput-password" name="password" type="password"
|
||||
placeholder="{{ 'core.courses.password' | translate }}" [(ngModel)]="password" core-auto-focus [clearOnEdit]="false">
|
||||
</ion-input>
|
||||
</core-show-password>
|
||||
</ion-item>
|
||||
<div class="ion-padding">
|
||||
<ion-button expand="block" [disabled]="!password" type="submit">{{ 'core.courses.enrolme' | translate }}</ion-button>
|
||||
</div>
|
||||
</form>
|
||||
</ion-content>
|
|
@ -1,62 +0,0 @@
|
|||
// (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, ViewChild, ElementRef } from '@angular/core';
|
||||
import { NavParams } from '@ionic/angular';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { ModalController } from '@singletons';
|
||||
import { CoreForms } from '@singletons/form';
|
||||
|
||||
/**
|
||||
* Modal that displays a form to enter a password to self enrol in a course.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'page-core-courses-self-enrol-password',
|
||||
templateUrl: 'self-enrol-password.html',
|
||||
})
|
||||
export class CoreCoursesSelfEnrolPasswordComponent {
|
||||
|
||||
@ViewChild('enrolPasswordForm') formElement!: ElementRef;
|
||||
password = '';
|
||||
|
||||
constructor(
|
||||
navParams: NavParams,
|
||||
) {
|
||||
this.password = navParams.get('password') || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Close help modal.
|
||||
*/
|
||||
close(): void {
|
||||
CoreForms.triggerFormCancelledEvent(this.formElement, CoreSites.getCurrentSiteId());
|
||||
|
||||
ModalController.dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit password.
|
||||
*
|
||||
* @param e Event.
|
||||
*/
|
||||
submitPassword(e: Event): void {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
CoreForms.triggerFormSubmittedEvent(this.formElement, false, CoreSites.getCurrentSiteId());
|
||||
|
||||
ModalController.dismiss(this.password);
|
||||
}
|
||||
|
||||
}
|
|
@ -59,6 +59,7 @@ import { CoreErrorInfoComponent } from '@components/error-info/error-info';
|
|||
import { CorePlatform } from '@services/platform';
|
||||
import { CoreCancellablePromise } from '@classes/cancellable-promise';
|
||||
import { CoreLang } from '@services/lang';
|
||||
import { CorePasswordModalParams } from '@components/password-modal/password-modal';
|
||||
|
||||
/*
|
||||
* "Utils" service with helper functions for UI, DOM elements and HTML code.
|
||||
|
@ -1880,6 +1881,33 @@ export class CoreDomUtilsProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts password to the user and returns the entered text.
|
||||
*
|
||||
* @param passwordParams Params to show the modal.
|
||||
* @returns Entered password.
|
||||
*/
|
||||
async promptPassword(passwordParams?: CorePasswordModalParams): Promise<CorePasswordModalResponse> {
|
||||
const { CorePasswordModalComponent } =
|
||||
await import('@/core/components/password-modal/password-modal.module');
|
||||
|
||||
const modalData = await CoreDomUtils.openModal<string>(
|
||||
{
|
||||
cssClass: 'core-password-modal',
|
||||
showBackdrop: true,
|
||||
backdropDismiss: true,
|
||||
component: CorePasswordModalComponent,
|
||||
componentProps: passwordParams,
|
||||
},
|
||||
);
|
||||
|
||||
if (typeof modalData !== 'string') {
|
||||
throw new CoreCanceledError();
|
||||
}
|
||||
|
||||
return modalData;
|
||||
}
|
||||
|
||||
/**
|
||||
* View an image in a modal.
|
||||
*
|
||||
|
|
|
@ -729,6 +729,21 @@ body.core-iframe-fullscreen ion-router-outlet {
|
|||
}
|
||||
}
|
||||
|
||||
.core-password-modal {
|
||||
--border-radius: var(--medium-radius);
|
||||
--min-width: auto;
|
||||
--min-height: 260px;
|
||||
--width: 320px;
|
||||
--height: auto;
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
// Hidden submit button.
|
||||
.core-submit-hidden-enter {
|
||||
position: absolute;
|
||||
|
@ -871,7 +886,7 @@ img.large-avatar,
|
|||
max-width: var(--core-large-avatar-size);
|
||||
max-height: var(--core-large-avatar-size);
|
||||
margin-bottom: 10px;
|
||||
border-radius : 50%;
|
||||
border-radius: 50%;
|
||||
padding: 4px;
|
||||
border: 1px solid var(--stroke);
|
||||
background-color: transparent;
|
||||
|
|
Loading…
Reference in New Issue