commit
						9a291e4fed
					
				@ -1608,6 +1608,7 @@
 | 
			
		||||
  "core.remove": "moodle",
 | 
			
		||||
  "core.required": "moodle",
 | 
			
		||||
  "core.requireduserdatamissing": "local_moodlemobileapp",
 | 
			
		||||
  "core.resourcedisplayopen": "moodle",
 | 
			
		||||
  "core.resources": "moodle",
 | 
			
		||||
  "core.restore": "moodle",
 | 
			
		||||
  "core.retry": "local_moodlemobileapp",
 | 
			
		||||
 | 
			
		||||
@ -36,6 +36,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
 | 
			
		||||
    @Input() tab = 'overview';
 | 
			
		||||
    @Input() group = 0;
 | 
			
		||||
 | 
			
		||||
    component = AddonModFeedbackProvider.COMPONENT;
 | 
			
		||||
    moduleName = 'feedback';
 | 
			
		||||
 | 
			
		||||
    access = {
 | 
			
		||||
@ -67,6 +68,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
 | 
			
		||||
    firstSelectedTab: number;
 | 
			
		||||
 | 
			
		||||
    protected submitObserver: any;
 | 
			
		||||
    protected syncEventName = AddonModFeedbackSyncProvider.AUTO_SYNCED;
 | 
			
		||||
 | 
			
		||||
    constructor(injector: Injector, private feedbackProvider: AddonModFeedbackProvider, @Optional() content: Content,
 | 
			
		||||
            private feedbackOffline: AddonModFeedbackOfflineProvider, private groupsProvider: CoreGroupsProvider,
 | 
			
		||||
 | 
			
		||||
@ -357,7 +357,7 @@ export class AddonModForumDiscussionPage implements OnDestroy {
 | 
			
		||||
    protected syncDiscussion(showErrors: boolean): Promise<any> {
 | 
			
		||||
        const promises = [];
 | 
			
		||||
 | 
			
		||||
        promises.push(this.forumSync.syncDiscussionReplies(this.forumId, this.discussionId).then((result) => {
 | 
			
		||||
        promises.push(this.forumSync.syncDiscussionReplies(this.discussionId).then((result) => {
 | 
			
		||||
            if (result.warnings && result.warnings.length) {
 | 
			
		||||
                this.domUtils.showErrorModal(result.warnings[0]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -51,53 +51,64 @@
 | 
			
		||||
                </ion-card>
 | 
			
		||||
 | 
			
		||||
                <core-loading [hideUntil]="!showSpinner">
 | 
			
		||||
                    <ion-list *ngIf="lesson && (!preventMessages || !preventMessages.length)">
 | 
			
		||||
 | 
			
		||||
                    <ion-list *ngIf="(lesson && (!preventMessages || !preventMessages.length)) || retakeToReview">
 | 
			
		||||
                        <ion-item text-wrap *ngIf="retakeToReview">
 | 
			
		||||
                            <!-- A retake was finished in a synchronization, allow reviewing it. -->
 | 
			
		||||
                            <p>{{ 'addon.mod_lesson.retakefinishedinsync' | translate }}</p>
 | 
			
		||||
                            <p padding-bottom>{{ 'addon.mod_lesson.retakefinishedinsync' | translate }}</p>
 | 
			
		||||
                            <a ion-button block (click)="review()">{{ 'addon.mod_lesson.review' | translate }}</a>
 | 
			
		||||
                        </ion-item>
 | 
			
		||||
 | 
			
		||||
                        <ion-item text-wrap *ngIf="leftDuringTimed && !lesson.timelimit">
 | 
			
		||||
                            <!-- User left during the session and there is no time limit, ask to continue. -->
 | 
			
		||||
                            <p [innerHTML]="'addon.mod_lesson.youhaveseen' | translate"></p>
 | 
			
		||||
                            <ion-grid>
 | 
			
		||||
                                <ion-row>
 | 
			
		||||
                                    <ion-col>
 | 
			
		||||
                                        <a ion-button block color="light" (click)="start(false)">{{ 'core.no' | translate }}</a>
 | 
			
		||||
                                    </ion-col>
 | 
			
		||||
                                    <ion-col>
 | 
			
		||||
                                        <a ion-button block (click)="start(true)">{{ 'core.yes' | translate }}</a>
 | 
			
		||||
                                    </ion-col>
 | 
			
		||||
                                </ion-row>
 | 
			
		||||
                            </ion-grid>
 | 
			
		||||
                        </ion-item>
 | 
			
		||||
                        <ng-container *ngIf="lesson && (!preventMessages || !preventMessages.length)">
 | 
			
		||||
                            <ion-item text-wrap *ngIf="leftDuringTimed && !lesson.timelimit && !finishedOffline">
 | 
			
		||||
                                <!-- User left during the session and there is no time limit, ask to continue. -->
 | 
			
		||||
                                <p [innerHTML]="'addon.mod_lesson.youhaveseen' | translate"></p>
 | 
			
		||||
                                <ion-grid>
 | 
			
		||||
                                    <ion-row>
 | 
			
		||||
                                        <ion-col>
 | 
			
		||||
                                            <a ion-button block color="light" (click)="start(false)">{{ 'core.no' | translate }}</a>
 | 
			
		||||
                                        </ion-col>
 | 
			
		||||
                                        <ion-col>
 | 
			
		||||
                                            <a ion-button block (click)="start(true)">{{ 'core.yes' | translate }}</a>
 | 
			
		||||
                                        </ion-col>
 | 
			
		||||
                                    </ion-row>
 | 
			
		||||
                                </ion-grid>
 | 
			
		||||
                            </ion-item>
 | 
			
		||||
 | 
			
		||||
                        <ion-item text-wrap *ngIf="leftDuringTimed && lesson.timelimit && lesson.retake">
 | 
			
		||||
                            <!-- User left during the session with time limit and retakes allowed, ask to continue. -->
 | 
			
		||||
                            <p [innerHTML]="'addon.mod_lesson.leftduringtimed' | translate"></p>
 | 
			
		||||
                            <a ion-button block icon-end (click)="start(false)">
 | 
			
		||||
                                {{ 'addon.mod_lesson.continue' | translate }}
 | 
			
		||||
                                <ion-icon name="arrow-forward" md="ios-arrow-forward"></ion-icon>
 | 
			
		||||
                            </a>
 | 
			
		||||
                        </ion-item>
 | 
			
		||||
                            <ion-item text-wrap *ngIf="leftDuringTimed && lesson.timelimit && lesson.retake && !finishedOffline">
 | 
			
		||||
                                <!-- User left during the session with time limit and retakes allowed, ask to continue. -->
 | 
			
		||||
                                <p [innerHTML]="'addon.mod_lesson.leftduringtimed' | translate"></p>
 | 
			
		||||
                                <a ion-button block icon-end (click)="start(false)">
 | 
			
		||||
                                    {{ 'addon.mod_lesson.continue' | translate }}
 | 
			
		||||
                                    <ion-icon name="arrow-forward" md="ios-arrow-forward"></ion-icon>
 | 
			
		||||
                                </a>
 | 
			
		||||
                            </ion-item>
 | 
			
		||||
 | 
			
		||||
                        <ion-item text-wrap *ngIf="leftDuringTimed && lesson.timelimit && !lesson.retake">
 | 
			
		||||
                            <!-- User left during the session with time limit and retakes not allowed. This should be handled by preventMessages -->
 | 
			
		||||
                            <p [innerHTML]="'addon.mod_lesson.leftduringtimednoretake' | translate"></p>
 | 
			
		||||
                        </ion-item>
 | 
			
		||||
                            <ion-item text-wrap *ngIf="leftDuringTimed && lesson.timelimit && !lesson.retake">
 | 
			
		||||
                                <!-- User left during the session with time limit and retakes not allowed. This should be handled by preventMessages -->
 | 
			
		||||
                                <p [innerHTML]="'addon.mod_lesson.leftduringtimednoretake' | translate"></p>
 | 
			
		||||
                            </ion-item>
 | 
			
		||||
 | 
			
		||||
                        <ion-item text-wrap *ngIf="!leftDuringTimed">
 | 
			
		||||
                            <!-- User hasn't left during the session, show a start button. -->
 | 
			
		||||
                            <a ion-button block *ngIf="!canManage" icon-end (click)="start(false)">
 | 
			
		||||
                                {{ 'core.start' | translate }}
 | 
			
		||||
                                <ion-icon name="arrow-forward" md="ios-arrow-forward"></ion-icon>
 | 
			
		||||
                            </a>
 | 
			
		||||
                            <a ion-button block *ngIf="canManage" icon-end (click)="start(false)">
 | 
			
		||||
                                {{ 'addon.mod_lesson.preview' | translate }}
 | 
			
		||||
                                <ion-icon name="search"></ion-icon>
 | 
			
		||||
                            </a>
 | 
			
		||||
                        </ion-item>
 | 
			
		||||
                            <ion-item text-wrap *ngIf="!leftDuringTimed && !finishedOffline">
 | 
			
		||||
                                <!-- User hasn't left during the session, show a start button. -->
 | 
			
		||||
                                <a ion-button block *ngIf="!canManage" icon-end (click)="start(false)">
 | 
			
		||||
                                    {{ 'core.start' | translate }}
 | 
			
		||||
                                    <ion-icon name="arrow-forward" md="ios-arrow-forward"></ion-icon>
 | 
			
		||||
                                </a>
 | 
			
		||||
                                <a ion-button block *ngIf="canManage" icon-end (click)="start(false)">
 | 
			
		||||
                                    {{ 'addon.mod_lesson.preview' | translate }}
 | 
			
		||||
                                    <ion-icon name="search"></ion-icon>
 | 
			
		||||
                                </a>
 | 
			
		||||
                            </ion-item>
 | 
			
		||||
 | 
			
		||||
                            <ion-item text-wrap *ngIf="finishedOffline">
 | 
			
		||||
                                <!-- There's an attempt finished in offline. Let the user continue, showing the end of lesson. -->
 | 
			
		||||
                                <a ion-button block icon-end (click)="start(true)">
 | 
			
		||||
                                    {{ 'addon.mod_lesson.continue' | translate }}
 | 
			
		||||
                                    <ion-icon name="arrow-forward" md="ios-arrow-forward"></ion-icon>
 | 
			
		||||
                                </a>
 | 
			
		||||
                            </ion-item>
 | 
			
		||||
                        </ng-container>
 | 
			
		||||
                    </ion-list>
 | 
			
		||||
                </core-loading>
 | 
			
		||||
            </ng-template>
 | 
			
		||||
 | 
			
		||||
@ -56,6 +56,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
 | 
			
		||||
    reportLoaded: boolean; // Whether the report data has been loaded.
 | 
			
		||||
    selectedGroupName: string; // The name of the selected group.
 | 
			
		||||
    overview: any; // Reports overview data.
 | 
			
		||||
    finishedOffline: boolean; // Whether a retake was finished in offline.
 | 
			
		||||
 | 
			
		||||
    protected syncEventName = AddonModLessonSyncProvider.AUTO_SYNCED;
 | 
			
		||||
    protected accessInfo: any; // Lesson access info.
 | 
			
		||||
@ -159,6 +160,11 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
 | 
			
		||||
                    }
 | 
			
		||||
                }));
 | 
			
		||||
 | 
			
		||||
                // Check if the ser has a finished retake in offline.
 | 
			
		||||
                promises.push(this.lessonOffline.hasFinishedRetake(this.lesson.id).then((finished) => {
 | 
			
		||||
                    this.finishedOffline = finished;
 | 
			
		||||
                }));
 | 
			
		||||
 | 
			
		||||
                // Update the list of content pages viewed and question attempts.
 | 
			
		||||
                promises.push(this.lessonProvider.getContentPagesViewedOnline(this.lesson.id, info.attemptscount));
 | 
			
		||||
                promises.push(this.lessonProvider.getQuestionsAttemptsOnline(this.lesson.id, info.attemptscount));
 | 
			
		||||
 | 
			
		||||
@ -32,14 +32,14 @@
 | 
			
		||||
            <!-- Page content. -->
 | 
			
		||||
            <ion-card *ngIf="!eolData && !processData">
 | 
			
		||||
                <!-- Content page. -->
 | 
			
		||||
                <ion-item text-wrap *ngIf="!question">
 | 
			
		||||
                <ion-item text-wrap *ngIf="!question && pageContent">
 | 
			
		||||
                    <core-format-text [component]="component" [componentId]="lesson.coursemodule" [text]="pageContent"></core-format-text>
 | 
			
		||||
                </ion-item>
 | 
			
		||||
 | 
			
		||||
                <!-- Question page. -->
 | 
			
		||||
                <!-- We need to set ngIf loaded to make formGroup directive restart every time a page changes, see MOBILE-2540. -->
 | 
			
		||||
                <form *ngIf="question && loaded" ion-list [formGroup]="questionForm">
 | 
			
		||||
                    <ion-item-divider text-wrap>
 | 
			
		||||
                    <ion-item-divider text-wrap *ngIf="pageContent">
 | 
			
		||||
                        <core-format-text [component]="component" [componentId]="lesson.coursemodule" [text]="pageContent"></core-format-text>
 | 
			
		||||
                    </ion-item-divider>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,8 @@ import { AddonModLessonProvider } from './lesson';
 | 
			
		||||
export class AddonModLessonHelperProvider {
 | 
			
		||||
 | 
			
		||||
    constructor(private domUtils: CoreDomUtilsProvider, private fb: FormBuilder, private translate: TranslateService,
 | 
			
		||||
            private textUtils: CoreTextUtilsProvider, private timeUtils: CoreTimeUtilsProvider) { }
 | 
			
		||||
            private textUtils: CoreTextUtilsProvider, private timeUtils: CoreTimeUtilsProvider,
 | 
			
		||||
            private lessonProvider: AddonModLessonProvider) { }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given the HTML of next activity link, format it to extract the href and the text.
 | 
			
		||||
@ -149,8 +150,15 @@ export class AddonModLessonHelperProvider {
 | 
			
		||||
            return contents.innerHTML.trim();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Cannot find contents element, return the page.contents (some elements like videos might not work).
 | 
			
		||||
        return data.page.contents;
 | 
			
		||||
        // Cannot find contents element.
 | 
			
		||||
        if (this.lessonProvider.isQuestionPage(data.page.type) ||
 | 
			
		||||
                data.page.qtype == AddonModLessonProvider.LESSON_PAGE_BRANCHTABLE) {
 | 
			
		||||
            // Return page.contents to prevent having duplicated elements (some elements like videos might not work).
 | 
			
		||||
            return data.page.contents;
 | 
			
		||||
        } else {
 | 
			
		||||
            // It's an end of cluster, end of branch, etc. Return the whole pagecontent to match what's displayed in web.
 | 
			
		||||
            return data.pagecontent;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,7 @@ import { AddonModWorkshopOfflineProvider } from '../../providers/offline';
 | 
			
		||||
export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivityComponent {
 | 
			
		||||
    @Input() group = 0;
 | 
			
		||||
 | 
			
		||||
    component = AddonModWorkshopProvider.COMPONENT;
 | 
			
		||||
    moduleName = 'workshop';
 | 
			
		||||
    workshop: any;
 | 
			
		||||
    page = 0;
 | 
			
		||||
@ -64,6 +65,7 @@ export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivity
 | 
			
		||||
    protected obsAssessmentSaved: any;
 | 
			
		||||
    protected appResumeSubscription: any;
 | 
			
		||||
    protected syncObserver: any;
 | 
			
		||||
    protected syncEventName = AddonModWorkshopSyncProvider.AUTO_SYNCED;
 | 
			
		||||
 | 
			
		||||
    constructor(injector: Injector, private workshopProvider: AddonModWorkshopProvider, @Optional() content: Content,
 | 
			
		||||
            private workshopOffline: AddonModWorkshopOfflineProvider, private groupsProvider: CoreGroupsProvider,
 | 
			
		||||
 | 
			
		||||
@ -1608,6 +1608,7 @@
 | 
			
		||||
    "core.remove": "Remove",
 | 
			
		||||
    "core.required": "Required",
 | 
			
		||||
    "core.requireduserdatamissing": "This user lacks some required profile data. Please enter the data in your site and try again.<br>{{$a}}",
 | 
			
		||||
    "core.resourcedisplayopen": "Open",
 | 
			
		||||
    "core.resources": "Resources",
 | 
			
		||||
    "core.restore": "Restore",
 | 
			
		||||
    "core.retry": "Retry",
 | 
			
		||||
 | 
			
		||||
@ -605,7 +605,7 @@ export class CoreSite {
 | 
			
		||||
 | 
			
		||||
                    // Session expired, trigger event.
 | 
			
		||||
                    this.eventsProvider.trigger(CoreEventsProvider.SESSION_EXPIRED, {}, this.id);
 | 
			
		||||
                    // Change error message. We'll try to get data from cache.
 | 
			
		||||
                    // Change error message. Try to get data from cache, the event will handle the error.
 | 
			
		||||
                    error.message = this.translate.instant('core.lostconnection');
 | 
			
		||||
                } else if (error.errorcode === 'userdeleted') {
 | 
			
		||||
                    // User deleted, trigger event.
 | 
			
		||||
@ -614,17 +614,15 @@ export class CoreSite {
 | 
			
		||||
 | 
			
		||||
                    return Promise.reject(error);
 | 
			
		||||
                } else if (error.errorcode === 'forcepasswordchangenotice') {
 | 
			
		||||
                    // Password Change Forced, trigger event.
 | 
			
		||||
                    // Password Change Forced, trigger event. Try to get data from cache, the event will handle the error.
 | 
			
		||||
                    this.eventsProvider.trigger(CoreEventsProvider.PASSWORD_CHANGE_FORCED, {}, this.id);
 | 
			
		||||
                    error.message = this.translate.instant('core.forcepasswordchangenotice');
 | 
			
		||||
 | 
			
		||||
                    return Promise.reject(error);
 | 
			
		||||
                } else if (error.errorcode === 'usernotfullysetup') {
 | 
			
		||||
                    // User not fully setup, trigger event.
 | 
			
		||||
                    // User not fully setup, trigger event. Try to get data from cache, the event will handle the error.
 | 
			
		||||
                    this.eventsProvider.trigger(CoreEventsProvider.USER_NOT_FULLY_SETUP, {}, this.id);
 | 
			
		||||
                    error.message = this.translate.instant('core.usernotfullysetup');
 | 
			
		||||
 | 
			
		||||
                    return Promise.reject(error);
 | 
			
		||||
                } else if (error.errorcode === 'sitepolicynotagreed') {
 | 
			
		||||
                    // Site policy not agreed, trigger event.
 | 
			
		||||
                    this.eventsProvider.trigger(CoreEventsProvider.SITE_POLICY_NOT_AGREED, {}, this.id);
 | 
			
		||||
 | 
			
		||||
@ -62,13 +62,6 @@ export class CoreLocalFileComponent implements OnInit {
 | 
			
		||||
    ngOnInit(): void {
 | 
			
		||||
        this.manage = this.utils.isTrueOrOne(this.manage);
 | 
			
		||||
 | 
			
		||||
        // Let's calculate the relative path for the file.
 | 
			
		||||
        this.relativePath = this.fileProvider.removeBasePath(this.file.toURL());
 | 
			
		||||
        if (!this.relativePath) {
 | 
			
		||||
            // Didn't find basePath, use fullPath but if the user tries to manage the file it'll probably fail.
 | 
			
		||||
            this.relativePath = this.file.fullPath;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.loadFileBasicData();
 | 
			
		||||
 | 
			
		||||
        // Get the size and timemodified.
 | 
			
		||||
@ -88,6 +81,13 @@ export class CoreLocalFileComponent implements OnInit {
 | 
			
		||||
        this.fileName = this.file.name;
 | 
			
		||||
        this.fileIcon = this.mimeUtils.getFileIcon(this.file.name);
 | 
			
		||||
        this.fileExtension = this.mimeUtils.getFileExtension(this.file.name);
 | 
			
		||||
 | 
			
		||||
        // Let's calculate the relative path for the file.
 | 
			
		||||
        this.relativePath = this.fileProvider.removeBasePath(this.file.toURL());
 | 
			
		||||
        if (!this.relativePath) {
 | 
			
		||||
            // Didn't find basePath, use fullPath but if the user tries to manage the file it'll probably fail.
 | 
			
		||||
            this.relativePath = this.file.fullPath;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
<div *ngIf="publicKey">
 | 
			
		||||
    <!-- A button to open the recaptcha modal. -->
 | 
			
		||||
    <!-- Use anchor instead of button to prevent marking form as submitted. -->
 | 
			
		||||
    <button ion-button block *ngIf="!model[modelValueName]" (click)="answerRecaptcha()" type="button">{{ 'core.answer' | translate }}</button>
 | 
			
		||||
    <button ion-button block *ngIf="!model[modelValueName]" (click)="answerRecaptcha()" type="button">{{ 'core.resourcedisplayopen' | translate }}</button>
 | 
			
		||||
    <p *ngIf="model[modelValueName]" class="text-success">{{ 'core.answered' | translate }}</p>
 | 
			
		||||
    <p *ngIf="expired" class="text-danger">{{ 'core.login.recaptchaexpired' | translate }}</p>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
@ -49,7 +49,7 @@ export class CoreSplitViewComponent implements OnInit, OnDestroy {
 | 
			
		||||
    @ViewChild('menu') menu: Menu;
 | 
			
		||||
    @Input() when?: string | boolean = 'md';
 | 
			
		||||
 | 
			
		||||
    protected isEnabled = false;
 | 
			
		||||
    protected isEnabled;
 | 
			
		||||
    protected masterPageName = '';
 | 
			
		||||
    protected masterPageIndex = 0;
 | 
			
		||||
    protected loadDetailPage: any = false;
 | 
			
		||||
@ -174,7 +174,7 @@ export class CoreSplitViewComponent implements OnInit, OnDestroy {
 | 
			
		||||
     * @return {boolean} If split view is enabled.
 | 
			
		||||
     */
 | 
			
		||||
    isOn(): boolean {
 | 
			
		||||
        return this.isEnabled;
 | 
			
		||||
        return !!this.isEnabled;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -182,16 +182,24 @@ export class CoreSplitViewComponent implements OnInit, OnDestroy {
 | 
			
		||||
     *
 | 
			
		||||
     * @param {any} page   The component class or deeplink name you want to push onto the navigation stack.
 | 
			
		||||
     * @param {any} params Any NavParams you want to pass along to the next view.
 | 
			
		||||
     * @param {boolean} [retrying] Whether it's retrying.
 | 
			
		||||
     */
 | 
			
		||||
    push(page: any, params?: any): void {
 | 
			
		||||
        if (this.isEnabled) {
 | 
			
		||||
            this.detailNav.setRoot(page, params);
 | 
			
		||||
    push(page: any, params?: any, retrying?: boolean): void {
 | 
			
		||||
        if (typeof this.isEnabled == 'undefined' && !retrying) {
 | 
			
		||||
            // Hasn't calculated if it's enabled yet. Wait a bit and try again.
 | 
			
		||||
            setTimeout(() => {
 | 
			
		||||
                this.push(page, params, true);
 | 
			
		||||
            }, 200);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.loadDetailPage = {
 | 
			
		||||
                component: page,
 | 
			
		||||
                data: params
 | 
			
		||||
            };
 | 
			
		||||
            this.masterNav.push(page, params);
 | 
			
		||||
            if (this.isEnabled) {
 | 
			
		||||
                this.detailNav.setRoot(page, params);
 | 
			
		||||
            } else {
 | 
			
		||||
                this.loadDetailPage = {
 | 
			
		||||
                    component: page,
 | 
			
		||||
                    data: params
 | 
			
		||||
                };
 | 
			
		||||
                this.masterNav.push(page, params);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -294,10 +294,6 @@ export class LocalNotificationsMock extends LocalNotifications {
 | 
			
		||||
            notification.timeoutAfter = this.parseToInt('timeoutAfter', notification);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (typeof notification.data == 'object') {
 | 
			
		||||
            notification.data = JSON.stringify(notification.data);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.convertPriority(notification);
 | 
			
		||||
        this.convertTrigger(notification);
 | 
			
		||||
        this.convertActions(notification);
 | 
			
		||||
 | 
			
		||||
@ -115,7 +115,7 @@
 | 
			
		||||
 | 
			
		||||
            <!-- ReCAPTCHA -->
 | 
			
		||||
            <ng-container *ngIf="settings.recaptchapublickey">
 | 
			
		||||
                <ion-item-divider text-wrap>{{ 'core.login.security_question' | translate }}</ion-item-divider>
 | 
			
		||||
                <ion-item-divider text-wrap><span [core-mark-required]="true">{{ 'core.login.security_question' | translate }}</span></ion-item-divider>
 | 
			
		||||
                <ion-item text-wrap>
 | 
			
		||||
                    <core-recaptcha [publicKey]="settings.recaptchapublickey" [model]="captcha" [siteUrl]="siteUrl"></core-recaptcha>
 | 
			
		||||
                </ion-item>
 | 
			
		||||
 | 
			
		||||
@ -261,25 +261,25 @@ export class CoreLoginEmailSignupPage {
 | 
			
		||||
                (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.
 | 
			
		||||
                            const 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) {
 | 
			
		||||
                                let error = result.warnings[0].message;
 | 
			
		||||
                                if (error == 'incorrect-captcha-sol') {
 | 
			
		||||
                                    error = this.translate.instant('core.login.recaptchaincorrect');
 | 
			
		||||
                                }
 | 
			
		||||
 | 
			
		||||
                                this.domUtils.showErrorModal(error);
 | 
			
		||||
                            } else {
 | 
			
		||||
                                this.domUtils.showErrorModal('core.login.usernotaddederror', true);
 | 
			
		||||
                    return this.wsProvider.callAjax('auth_email_signup_user', params, { siteUrl: this.siteUrl });
 | 
			
		||||
                }).then((result) => {
 | 
			
		||||
                    if (result.success) {
 | 
			
		||||
                        // Show alert and ho back.
 | 
			
		||||
                        const 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) {
 | 
			
		||||
                            let error = result.warnings[0].message;
 | 
			
		||||
                            if (error == 'incorrect-captcha-sol') {
 | 
			
		||||
                                error = this.translate.instant('core.login.recaptchaincorrect');
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            this.domUtils.showErrorModal(error);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            this.domUtils.showErrorModal('core.login.usernotaddederror', true);
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                    }
 | 
			
		||||
                }).catch((error) => {
 | 
			
		||||
                    this.domUtils.showErrorModalDefault(error, 'core.login.usernotaddederror', true);
 | 
			
		||||
                }).finally(() => {
 | 
			
		||||
 | 
			
		||||
@ -44,15 +44,27 @@ export class CoreSharedFilesModule {
 | 
			
		||||
        delegate.registerHandler(handler);
 | 
			
		||||
 | 
			
		||||
        if (platform.is('ios')) {
 | 
			
		||||
            let lastCheck = 0;
 | 
			
		||||
 | 
			
		||||
            // Check if there are new files at app start and when the app is resumed.
 | 
			
		||||
            helper.searchIOSNewSharedFiles();
 | 
			
		||||
            platform.resume.subscribe(() => {
 | 
			
		||||
                helper.searchIOSNewSharedFiles();
 | 
			
		||||
                // Wait a bit to make sure that APP_LAUNCHED_URL is treated before this callback.
 | 
			
		||||
                setTimeout(() => {
 | 
			
		||||
                    if (Date.now() - lastCheck < 1000) {
 | 
			
		||||
                        // Last check less than 1s ago, don't do anything.
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    lastCheck = Date.now();
 | 
			
		||||
                    helper.searchIOSNewSharedFiles();
 | 
			
		||||
                }, 200);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            eventsProvider.on(CoreEventsProvider.APP_LAUNCHED_URL, (url) => {
 | 
			
		||||
                if (url && url.indexOf('file://') === 0) {
 | 
			
		||||
                    // We received a file in iOS, it's probably a shared file. Treat it.
 | 
			
		||||
                    lastCheck = Date.now();
 | 
			
		||||
                    helper.searchIOSNewSharedFiles(url);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
@ -196,6 +196,7 @@
 | 
			
		||||
    "remove": "Remove",
 | 
			
		||||
    "required": "Required",
 | 
			
		||||
    "requireduserdatamissing": "This user lacks some required profile data. Please enter the data in your site and try again.<br>{{$a}}",
 | 
			
		||||
    "resourcedisplayopen": "Open",
 | 
			
		||||
    "resources": "Resources",
 | 
			
		||||
    "restore": "Restore",
 | 
			
		||||
    "retry": "Retry",
 | 
			
		||||
 | 
			
		||||
@ -324,7 +324,16 @@ export class CoreFileProvider {
 | 
			
		||||
            path = this.removeStartingSlash(path.replace(this.basePath, ''));
 | 
			
		||||
            this.logger.debug('Remove file: ' + path);
 | 
			
		||||
 | 
			
		||||
            return this.file.removeFile(this.basePath, path);
 | 
			
		||||
            return this.file.removeFile(this.basePath, path).catch((error) => {
 | 
			
		||||
                // The delete can fail if the path has encoded characters. Try again if that's the case.
 | 
			
		||||
                const decodedPath = decodeURI(path);
 | 
			
		||||
 | 
			
		||||
                if (decodedPath != path) {
 | 
			
		||||
                    return this.file.removeFile(this.basePath, decodedPath);
 | 
			
		||||
                } else {
 | 
			
		||||
                    return Promise.reject(error);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user