commit
9a291e4fed
|
@ -1608,6 +1608,7 @@
|
||||||
"core.remove": "moodle",
|
"core.remove": "moodle",
|
||||||
"core.required": "moodle",
|
"core.required": "moodle",
|
||||||
"core.requireduserdatamissing": "local_moodlemobileapp",
|
"core.requireduserdatamissing": "local_moodlemobileapp",
|
||||||
|
"core.resourcedisplayopen": "moodle",
|
||||||
"core.resources": "moodle",
|
"core.resources": "moodle",
|
||||||
"core.restore": "moodle",
|
"core.restore": "moodle",
|
||||||
"core.retry": "local_moodlemobileapp",
|
"core.retry": "local_moodlemobileapp",
|
||||||
|
|
|
@ -36,6 +36,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
@Input() tab = 'overview';
|
@Input() tab = 'overview';
|
||||||
@Input() group = 0;
|
@Input() group = 0;
|
||||||
|
|
||||||
|
component = AddonModFeedbackProvider.COMPONENT;
|
||||||
moduleName = 'feedback';
|
moduleName = 'feedback';
|
||||||
|
|
||||||
access = {
|
access = {
|
||||||
|
@ -67,6 +68,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
firstSelectedTab: number;
|
firstSelectedTab: number;
|
||||||
|
|
||||||
protected submitObserver: any;
|
protected submitObserver: any;
|
||||||
|
protected syncEventName = AddonModFeedbackSyncProvider.AUTO_SYNCED;
|
||||||
|
|
||||||
constructor(injector: Injector, private feedbackProvider: AddonModFeedbackProvider, @Optional() content: Content,
|
constructor(injector: Injector, private feedbackProvider: AddonModFeedbackProvider, @Optional() content: Content,
|
||||||
private feedbackOffline: AddonModFeedbackOfflineProvider, private groupsProvider: CoreGroupsProvider,
|
private feedbackOffline: AddonModFeedbackOfflineProvider, private groupsProvider: CoreGroupsProvider,
|
||||||
|
|
|
@ -357,7 +357,7 @@ export class AddonModForumDiscussionPage implements OnDestroy {
|
||||||
protected syncDiscussion(showErrors: boolean): Promise<any> {
|
protected syncDiscussion(showErrors: boolean): Promise<any> {
|
||||||
const promises = [];
|
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) {
|
if (result.warnings && result.warnings.length) {
|
||||||
this.domUtils.showErrorModal(result.warnings[0]);
|
this.domUtils.showErrorModal(result.warnings[0]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,14 +51,16 @@
|
||||||
</ion-card>
|
</ion-card>
|
||||||
|
|
||||||
<core-loading [hideUntil]="!showSpinner">
|
<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">
|
<ion-item text-wrap *ngIf="retakeToReview">
|
||||||
<!-- A retake was finished in a synchronization, allow reviewing it. -->
|
<!-- 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>
|
<a ion-button block (click)="review()">{{ 'addon.mod_lesson.review' | translate }}</a>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
<ion-item text-wrap *ngIf="leftDuringTimed && !lesson.timelimit">
|
<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. -->
|
<!-- User left during the session and there is no time limit, ask to continue. -->
|
||||||
<p [innerHTML]="'addon.mod_lesson.youhaveseen' | translate"></p>
|
<p [innerHTML]="'addon.mod_lesson.youhaveseen' | translate"></p>
|
||||||
<ion-grid>
|
<ion-grid>
|
||||||
|
@ -73,7 +75,7 @@
|
||||||
</ion-grid>
|
</ion-grid>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
<ion-item text-wrap *ngIf="leftDuringTimed && lesson.timelimit && lesson.retake">
|
<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. -->
|
<!-- User left during the session with time limit and retakes allowed, ask to continue. -->
|
||||||
<p [innerHTML]="'addon.mod_lesson.leftduringtimed' | translate"></p>
|
<p [innerHTML]="'addon.mod_lesson.leftduringtimed' | translate"></p>
|
||||||
<a ion-button block icon-end (click)="start(false)">
|
<a ion-button block icon-end (click)="start(false)">
|
||||||
|
@ -87,7 +89,7 @@
|
||||||
<p [innerHTML]="'addon.mod_lesson.leftduringtimednoretake' | translate"></p>
|
<p [innerHTML]="'addon.mod_lesson.leftduringtimednoretake' | translate"></p>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
<ion-item text-wrap *ngIf="!leftDuringTimed">
|
<ion-item text-wrap *ngIf="!leftDuringTimed && !finishedOffline">
|
||||||
<!-- User hasn't left during the session, show a start button. -->
|
<!-- User hasn't left during the session, show a start button. -->
|
||||||
<a ion-button block *ngIf="!canManage" icon-end (click)="start(false)">
|
<a ion-button block *ngIf="!canManage" icon-end (click)="start(false)">
|
||||||
{{ 'core.start' | translate }}
|
{{ 'core.start' | translate }}
|
||||||
|
@ -98,6 +100,15 @@
|
||||||
<ion-icon name="search"></ion-icon>
|
<ion-icon name="search"></ion-icon>
|
||||||
</a>
|
</a>
|
||||||
</ion-item>
|
</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>
|
</ion-list>
|
||||||
</core-loading>
|
</core-loading>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
|
@ -56,6 +56,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
|
||||||
reportLoaded: boolean; // Whether the report data has been loaded.
|
reportLoaded: boolean; // Whether the report data has been loaded.
|
||||||
selectedGroupName: string; // The name of the selected group.
|
selectedGroupName: string; // The name of the selected group.
|
||||||
overview: any; // Reports overview data.
|
overview: any; // Reports overview data.
|
||||||
|
finishedOffline: boolean; // Whether a retake was finished in offline.
|
||||||
|
|
||||||
protected syncEventName = AddonModLessonSyncProvider.AUTO_SYNCED;
|
protected syncEventName = AddonModLessonSyncProvider.AUTO_SYNCED;
|
||||||
protected accessInfo: any; // Lesson access info.
|
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.
|
// Update the list of content pages viewed and question attempts.
|
||||||
promises.push(this.lessonProvider.getContentPagesViewedOnline(this.lesson.id, info.attemptscount));
|
promises.push(this.lessonProvider.getContentPagesViewedOnline(this.lesson.id, info.attemptscount));
|
||||||
promises.push(this.lessonProvider.getQuestionsAttemptsOnline(this.lesson.id, info.attemptscount));
|
promises.push(this.lessonProvider.getQuestionsAttemptsOnline(this.lesson.id, info.attemptscount));
|
||||||
|
|
|
@ -32,14 +32,14 @@
|
||||||
<!-- Page content. -->
|
<!-- Page content. -->
|
||||||
<ion-card *ngIf="!eolData && !processData">
|
<ion-card *ngIf="!eolData && !processData">
|
||||||
<!-- Content page. -->
|
<!-- 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>
|
<core-format-text [component]="component" [componentId]="lesson.coursemodule" [text]="pageContent"></core-format-text>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
<!-- Question page. -->
|
<!-- Question page. -->
|
||||||
<!-- We need to set ngIf loaded to make formGroup directive restart every time a page changes, see MOBILE-2540. -->
|
<!-- 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">
|
<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>
|
<core-format-text [component]="component" [componentId]="lesson.coursemodule" [text]="pageContent"></core-format-text>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,8 @@ import { AddonModLessonProvider } from './lesson';
|
||||||
export class AddonModLessonHelperProvider {
|
export class AddonModLessonHelperProvider {
|
||||||
|
|
||||||
constructor(private domUtils: CoreDomUtilsProvider, private fb: FormBuilder, private translate: TranslateService,
|
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.
|
* 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();
|
return contents.innerHTML.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cannot find contents element, return the page.contents (some elements like videos might not work).
|
// 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;
|
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 {
|
export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivityComponent {
|
||||||
@Input() group = 0;
|
@Input() group = 0;
|
||||||
|
|
||||||
|
component = AddonModWorkshopProvider.COMPONENT;
|
||||||
moduleName = 'workshop';
|
moduleName = 'workshop';
|
||||||
workshop: any;
|
workshop: any;
|
||||||
page = 0;
|
page = 0;
|
||||||
|
@ -64,6 +65,7 @@ export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivity
|
||||||
protected obsAssessmentSaved: any;
|
protected obsAssessmentSaved: any;
|
||||||
protected appResumeSubscription: any;
|
protected appResumeSubscription: any;
|
||||||
protected syncObserver: any;
|
protected syncObserver: any;
|
||||||
|
protected syncEventName = AddonModWorkshopSyncProvider.AUTO_SYNCED;
|
||||||
|
|
||||||
constructor(injector: Injector, private workshopProvider: AddonModWorkshopProvider, @Optional() content: Content,
|
constructor(injector: Injector, private workshopProvider: AddonModWorkshopProvider, @Optional() content: Content,
|
||||||
private workshopOffline: AddonModWorkshopOfflineProvider, private groupsProvider: CoreGroupsProvider,
|
private workshopOffline: AddonModWorkshopOfflineProvider, private groupsProvider: CoreGroupsProvider,
|
||||||
|
|
|
@ -1608,6 +1608,7 @@
|
||||||
"core.remove": "Remove",
|
"core.remove": "Remove",
|
||||||
"core.required": "Required",
|
"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.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.resources": "Resources",
|
||||||
"core.restore": "Restore",
|
"core.restore": "Restore",
|
||||||
"core.retry": "Retry",
|
"core.retry": "Retry",
|
||||||
|
|
|
@ -605,7 +605,7 @@ export class CoreSite {
|
||||||
|
|
||||||
// Session expired, trigger event.
|
// Session expired, trigger event.
|
||||||
this.eventsProvider.trigger(CoreEventsProvider.SESSION_EXPIRED, {}, this.id);
|
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');
|
error.message = this.translate.instant('core.lostconnection');
|
||||||
} else if (error.errorcode === 'userdeleted') {
|
} else if (error.errorcode === 'userdeleted') {
|
||||||
// User deleted, trigger event.
|
// User deleted, trigger event.
|
||||||
|
@ -614,17 +614,15 @@ export class CoreSite {
|
||||||
|
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
} else if (error.errorcode === 'forcepasswordchangenotice') {
|
} 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);
|
this.eventsProvider.trigger(CoreEventsProvider.PASSWORD_CHANGE_FORCED, {}, this.id);
|
||||||
error.message = this.translate.instant('core.forcepasswordchangenotice');
|
error.message = this.translate.instant('core.forcepasswordchangenotice');
|
||||||
|
|
||||||
return Promise.reject(error);
|
|
||||||
} else if (error.errorcode === 'usernotfullysetup') {
|
} 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);
|
this.eventsProvider.trigger(CoreEventsProvider.USER_NOT_FULLY_SETUP, {}, this.id);
|
||||||
error.message = this.translate.instant('core.usernotfullysetup');
|
error.message = this.translate.instant('core.usernotfullysetup');
|
||||||
|
|
||||||
return Promise.reject(error);
|
|
||||||
} else if (error.errorcode === 'sitepolicynotagreed') {
|
} else if (error.errorcode === 'sitepolicynotagreed') {
|
||||||
// Site policy not agreed, trigger event.
|
// Site policy not agreed, trigger event.
|
||||||
this.eventsProvider.trigger(CoreEventsProvider.SITE_POLICY_NOT_AGREED, {}, this.id);
|
this.eventsProvider.trigger(CoreEventsProvider.SITE_POLICY_NOT_AGREED, {}, this.id);
|
||||||
|
|
|
@ -62,13 +62,6 @@ export class CoreLocalFileComponent implements OnInit {
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.manage = this.utils.isTrueOrOne(this.manage);
|
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();
|
this.loadFileBasicData();
|
||||||
|
|
||||||
// Get the size and timemodified.
|
// Get the size and timemodified.
|
||||||
|
@ -88,6 +81,13 @@ export class CoreLocalFileComponent implements OnInit {
|
||||||
this.fileName = this.file.name;
|
this.fileName = this.file.name;
|
||||||
this.fileIcon = this.mimeUtils.getFileIcon(this.file.name);
|
this.fileIcon = this.mimeUtils.getFileIcon(this.file.name);
|
||||||
this.fileExtension = this.mimeUtils.getFileExtension(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">
|
<div *ngIf="publicKey">
|
||||||
<!-- A button to open the recaptcha modal. -->
|
<!-- A button to open the recaptcha modal. -->
|
||||||
<!-- Use anchor instead of button to prevent marking form as submitted. -->
|
<!-- 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="model[modelValueName]" class="text-success">{{ 'core.answered' | translate }}</p>
|
||||||
<p *ngIf="expired" class="text-danger">{{ 'core.login.recaptchaexpired' | translate }}</p>
|
<p *ngIf="expired" class="text-danger">{{ 'core.login.recaptchaexpired' | translate }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -49,7 +49,7 @@ export class CoreSplitViewComponent implements OnInit, OnDestroy {
|
||||||
@ViewChild('menu') menu: Menu;
|
@ViewChild('menu') menu: Menu;
|
||||||
@Input() when?: string | boolean = 'md';
|
@Input() when?: string | boolean = 'md';
|
||||||
|
|
||||||
protected isEnabled = false;
|
protected isEnabled;
|
||||||
protected masterPageName = '';
|
protected masterPageName = '';
|
||||||
protected masterPageIndex = 0;
|
protected masterPageIndex = 0;
|
||||||
protected loadDetailPage: any = false;
|
protected loadDetailPage: any = false;
|
||||||
|
@ -174,7 +174,7 @@ export class CoreSplitViewComponent implements OnInit, OnDestroy {
|
||||||
* @return {boolean} If split view is enabled.
|
* @return {boolean} If split view is enabled.
|
||||||
*/
|
*/
|
||||||
isOn(): boolean {
|
isOn(): boolean {
|
||||||
return this.isEnabled;
|
return !!this.isEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -182,8 +182,15 @@ 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} 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 {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 {
|
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 {
|
||||||
if (this.isEnabled) {
|
if (this.isEnabled) {
|
||||||
this.detailNav.setRoot(page, params);
|
this.detailNav.setRoot(page, params);
|
||||||
} else {
|
} else {
|
||||||
|
@ -194,6 +201,7 @@ export class CoreSplitViewComponent implements OnInit, OnDestroy {
|
||||||
this.masterNav.push(page, params);
|
this.masterNav.push(page, params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the details panel to default info.
|
* Set the details panel to default info.
|
||||||
|
|
|
@ -294,10 +294,6 @@ export class LocalNotificationsMock extends LocalNotifications {
|
||||||
notification.timeoutAfter = this.parseToInt('timeoutAfter', notification);
|
notification.timeoutAfter = this.parseToInt('timeoutAfter', notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof notification.data == 'object') {
|
|
||||||
notification.data = JSON.stringify(notification.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.convertPriority(notification);
|
this.convertPriority(notification);
|
||||||
this.convertTrigger(notification);
|
this.convertTrigger(notification);
|
||||||
this.convertActions(notification);
|
this.convertActions(notification);
|
||||||
|
|
|
@ -115,7 +115,7 @@
|
||||||
|
|
||||||
<!-- ReCAPTCHA -->
|
<!-- ReCAPTCHA -->
|
||||||
<ng-container *ngIf="settings.recaptchapublickey">
|
<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>
|
<ion-item text-wrap>
|
||||||
<core-recaptcha [publicKey]="settings.recaptchapublickey" [model]="captcha" [siteUrl]="siteUrl"></core-recaptcha>
|
<core-recaptcha [publicKey]="settings.recaptchapublickey" [model]="captcha" [siteUrl]="siteUrl"></core-recaptcha>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
|
@ -261,7 +261,8 @@ export class CoreLoginEmailSignupPage {
|
||||||
(fieldsData) => {
|
(fieldsData) => {
|
||||||
params.customprofilefields = fieldsData;
|
params.customprofilefields = fieldsData;
|
||||||
|
|
||||||
this.wsProvider.callAjax('auth_email_signup_user', params, { siteUrl: this.siteUrl }).then((result) => {
|
return this.wsProvider.callAjax('auth_email_signup_user', params, { siteUrl: this.siteUrl });
|
||||||
|
}).then((result) => {
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
// Show alert and ho back.
|
// Show alert and ho back.
|
||||||
const message = this.translate.instant('core.login.emailconfirmsent', { $a: params.email });
|
const message = this.translate.instant('core.login.emailconfirmsent', { $a: params.email });
|
||||||
|
@ -279,7 +280,6 @@ export class CoreLoginEmailSignupPage {
|
||||||
this.domUtils.showErrorModal('core.login.usernotaddederror', true);
|
this.domUtils.showErrorModal('core.login.usernotaddederror', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
this.domUtils.showErrorModalDefault(error, 'core.login.usernotaddederror', true);
|
this.domUtils.showErrorModalDefault(error, 'core.login.usernotaddederror', true);
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
|
|
|
@ -44,15 +44,27 @@ export class CoreSharedFilesModule {
|
||||||
delegate.registerHandler(handler);
|
delegate.registerHandler(handler);
|
||||||
|
|
||||||
if (platform.is('ios')) {
|
if (platform.is('ios')) {
|
||||||
|
let lastCheck = 0;
|
||||||
|
|
||||||
// Check if there are new files at app start and when the app is resumed.
|
// Check if there are new files at app start and when the app is resumed.
|
||||||
helper.searchIOSNewSharedFiles();
|
helper.searchIOSNewSharedFiles();
|
||||||
platform.resume.subscribe(() => {
|
platform.resume.subscribe(() => {
|
||||||
|
// 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();
|
helper.searchIOSNewSharedFiles();
|
||||||
|
}, 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
eventsProvider.on(CoreEventsProvider.APP_LAUNCHED_URL, (url) => {
|
eventsProvider.on(CoreEventsProvider.APP_LAUNCHED_URL, (url) => {
|
||||||
if (url && url.indexOf('file://') === 0) {
|
if (url && url.indexOf('file://') === 0) {
|
||||||
// We received a file in iOS, it's probably a shared file. Treat it.
|
// We received a file in iOS, it's probably a shared file. Treat it.
|
||||||
|
lastCheck = Date.now();
|
||||||
helper.searchIOSNewSharedFiles(url);
|
helper.searchIOSNewSharedFiles(url);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -196,6 +196,7 @@
|
||||||
"remove": "Remove",
|
"remove": "Remove",
|
||||||
"required": "Required",
|
"required": "Required",
|
||||||
"requireduserdatamissing": "This user lacks some required profile data. Please enter the data in your site and try again.<br>{{$a}}",
|
"requireduserdatamissing": "This user lacks some required profile data. Please enter the data in your site and try again.<br>{{$a}}",
|
||||||
|
"resourcedisplayopen": "Open",
|
||||||
"resources": "Resources",
|
"resources": "Resources",
|
||||||
"restore": "Restore",
|
"restore": "Restore",
|
||||||
"retry": "Retry",
|
"retry": "Retry",
|
||||||
|
|
|
@ -324,7 +324,16 @@ export class CoreFileProvider {
|
||||||
path = this.removeStartingSlash(path.replace(this.basePath, ''));
|
path = this.removeStartingSlash(path.replace(this.basePath, ''));
|
||||||
this.logger.debug('Remove file: ' + path);
|
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…
Reference in New Issue