commit
						1f1912bf98
					
				@ -507,11 +507,13 @@
 | 
			
		||||
  "addon.mod_data.foundrecords": "data",
 | 
			
		||||
  "addon.mod_data.gettinglocation": "local_moodlemobileapp",
 | 
			
		||||
  "addon.mod_data.latlongboth": "data",
 | 
			
		||||
  "addon.mod_data.locationnotenabled": "local_moodlemobileapp",
 | 
			
		||||
  "addon.mod_data.locationpermissiondenied": "local_moodlemobileapp",
 | 
			
		||||
  "addon.mod_data.menuchoose": "data",
 | 
			
		||||
  "addon.mod_data.modulenameplural": "data",
 | 
			
		||||
  "addon.mod_data.more": "data",
 | 
			
		||||
  "addon.mod_data.mylocation": "local_moodlemobileapp",
 | 
			
		||||
  "addon.mod_data.noaccess": "data",
 | 
			
		||||
  "addon.mod_data.nomatch": "data",
 | 
			
		||||
  "addon.mod_data.norecords": "data",
 | 
			
		||||
  "addon.mod_data.notapproved": "data",
 | 
			
		||||
 | 
			
		||||
@ -180,29 +180,34 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
 | 
			
		||||
     * @param showErrors If show errors to the user of hide them.
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected fetchContent(refresh: boolean = false, sync: boolean = false, showErrors: boolean = false): Promise<any> {
 | 
			
		||||
    protected async fetchContent(refresh: boolean = false, sync: boolean = false, showErrors: boolean = false): Promise<any> {
 | 
			
		||||
        let canAdd = false,
 | 
			
		||||
            canSearch = false;
 | 
			
		||||
 | 
			
		||||
        return this.dataProvider.getDatabase(this.courseId, this.module.id).then((data) => {
 | 
			
		||||
            this.data = data;
 | 
			
		||||
            this.hasComments = data.comments;
 | 
			
		||||
        this.data = await this.dataProvider.getDatabase(this.courseId, this.module.id);
 | 
			
		||||
        this.hasComments = this.data.comments;
 | 
			
		||||
 | 
			
		||||
            this.description = data.intro || data.description;
 | 
			
		||||
            this.dataRetrieved.emit(data);
 | 
			
		||||
        this.description = this.data.intro || this.data.description;
 | 
			
		||||
        this.dataRetrieved.emit(this.data);
 | 
			
		||||
 | 
			
		||||
        if (sync) {
 | 
			
		||||
            try {
 | 
			
		||||
                // Try to synchronize the data.
 | 
			
		||||
                return this.syncActivity(showErrors).catch(() => {
 | 
			
		||||
                await this.syncActivity(showErrors);
 | 
			
		||||
            } catch (error) {
 | 
			
		||||
                // Ignore errors.
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }).then(() => {
 | 
			
		||||
            return this.dataProvider.getDatabaseAccessInformation(this.data.id, {cmId: this.module.id});
 | 
			
		||||
        }).then((accessData) => {
 | 
			
		||||
            this.access = accessData;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            if (!accessData.timeavailable) {
 | 
			
		||||
        this.groupInfo = await this.groupsProvider.getActivityGroupInfo(this.data.coursemodule);
 | 
			
		||||
        this.selectedGroup = this.groupsProvider.validateGroupId(this.selectedGroup, this.groupInfo);
 | 
			
		||||
 | 
			
		||||
        this.access = await this.dataProvider.getDatabaseAccessInformation(this.data.id, {
 | 
			
		||||
            cmId: this.module.id,
 | 
			
		||||
            groupId: this.selectedGroup || undefined
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (!this.access.timeavailable) {
 | 
			
		||||
            const time = this.timeUtils.timestamp();
 | 
			
		||||
 | 
			
		||||
            this.timeAvailableFrom = this.data.timeavailablefrom && time < this.data.timeavailablefrom ?
 | 
			
		||||
@ -214,35 +219,28 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
 | 
			
		||||
 | 
			
		||||
            this.isEmpty = true;
 | 
			
		||||
            this.groupInfo = null;
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        } else {
 | 
			
		||||
            canSearch = true;
 | 
			
		||||
            canAdd = accessData.canaddentry;
 | 
			
		||||
 | 
			
		||||
            return this.groupsProvider.getActivityGroupInfo(this.data.coursemodule).then((groupInfo) => {
 | 
			
		||||
                this.groupInfo = groupInfo;
 | 
			
		||||
                this.selectedGroup = this.groupsProvider.validateGroupId(this.selectedGroup, groupInfo);
 | 
			
		||||
            });
 | 
			
		||||
        }).then(() => {
 | 
			
		||||
            return this.dataProvider.getFields(this.data.id, {cmId: this.module.id}).then((fields) => {
 | 
			
		||||
                if (fields.length == 0) {
 | 
			
		||||
                    canSearch = false;
 | 
			
		||||
                    canAdd = false;
 | 
			
		||||
            canAdd = this.access.canaddentry;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const fields = await this.dataProvider.getFields(this.data.id, {cmId: this.module.id});
 | 
			
		||||
        this.search.advanced = [];
 | 
			
		||||
 | 
			
		||||
        this.fields = this.utils.arrayToObject(fields, 'id');
 | 
			
		||||
        this.fieldsArray = this.utils.objectToArray(this.fields);
 | 
			
		||||
        if (this.fieldsArray.length == 0) {
 | 
			
		||||
            canSearch = false;
 | 
			
		||||
            canAdd = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                return this.fetchEntriesData();
 | 
			
		||||
            });
 | 
			
		||||
        }).finally(() => {
 | 
			
		||||
        try {
 | 
			
		||||
            await this.fetchEntriesData();
 | 
			
		||||
        } finally {
 | 
			
		||||
            this.canAdd = canAdd;
 | 
			
		||||
            this.canSearch = canSearch;
 | 
			
		||||
            this.fillContextMenu(refresh);
 | 
			
		||||
        });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -252,13 +250,6 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
 | 
			
		||||
     */
 | 
			
		||||
    protected fetchEntriesData(): Promise<any> {
 | 
			
		||||
 | 
			
		||||
        return this.dataProvider.getDatabaseAccessInformation(this.data.id, {
 | 
			
		||||
            groupId: this.selectedGroup,
 | 
			
		||||
            cmId: this.module.id,
 | 
			
		||||
        }).then((accessData) => {
 | 
			
		||||
            // Update values for current group.
 | 
			
		||||
            this.access.canaddentry = accessData.canaddentry;
 | 
			
		||||
 | 
			
		||||
        const search = this.search.searching && !this.search.searchingAdvanced ? this.search.text : undefined;
 | 
			
		||||
        const advSearch = this.search.searching && this.search.searchingAdvanced ? this.search.advanced : undefined;
 | 
			
		||||
 | 
			
		||||
@ -269,7 +260,6 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
 | 
			
		||||
            sort: Number(this.search.sortBy),
 | 
			
		||||
            order: this.search.sortDirection,
 | 
			
		||||
            page: this.search.page,
 | 
			
		||||
            });
 | 
			
		||||
        }).then((entries) => {
 | 
			
		||||
            const numEntries = entries.entries.length;
 | 
			
		||||
            const numOfflineEntries = entries.offlineEntries.length;
 | 
			
		||||
@ -390,18 +380,29 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
 | 
			
		||||
     * @param groupId Group ID.
 | 
			
		||||
     * @return Resolved when new group is selected or rejected if not.
 | 
			
		||||
     */
 | 
			
		||||
    setGroup(groupId: number): Promise<any> {
 | 
			
		||||
    async setGroup(groupId: number): Promise<void> {
 | 
			
		||||
        this.selectedGroup = groupId;
 | 
			
		||||
        this.search.page = 0;
 | 
			
		||||
 | 
			
		||||
        return this.fetchEntriesData().then(() => {
 | 
			
		||||
        // Only update canAdd if there's any field, otheerwise, canAdd will remain false.
 | 
			
		||||
        if (this.fieldsArray.length > 0) {
 | 
			
		||||
            // Update values for current group.
 | 
			
		||||
            this.access = await this.dataProvider.getDatabaseAccessInformation(this.data.id, {
 | 
			
		||||
                groupId: this.selectedGroup,
 | 
			
		||||
                cmId: this.module.id,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this.canAdd = this.access.canaddentry;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await this.fetchEntriesData();
 | 
			
		||||
 | 
			
		||||
            // Log activity view for coherence with Moodle web.
 | 
			
		||||
            return this.logView();
 | 
			
		||||
        }).catch((message) => {
 | 
			
		||||
            this.domUtils.showErrorModalDefault(message, 'core.course.errorgetmodule', true);
 | 
			
		||||
 | 
			
		||||
            return Promise.reject(null);
 | 
			
		||||
        });
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            this.domUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,7 @@
 | 
			
		||||
    "modulenameplural": "Databases",
 | 
			
		||||
    "more": "More",
 | 
			
		||||
    "mylocation": "My location",
 | 
			
		||||
    "noaccess": "You do not have access to this page",
 | 
			
		||||
    "nomatch": "No matching entries found!",
 | 
			
		||||
    "norecords": "No entries in database",
 | 
			
		||||
    "notapproved": "Entry is not approved yet.",
 | 
			
		||||
 | 
			
		||||
@ -18,8 +18,8 @@
 | 
			
		||||
            </ion-select>
 | 
			
		||||
        </ion-item>
 | 
			
		||||
 | 
			
		||||
        <div class="addon-data-contents addon-data-entries-{{data.id}}" *ngIf="data">
 | 
			
		||||
            <core-style [css]="data.csstemplate" prefix=".addon-data-entries-{{data.id}}"></core-style>
 | 
			
		||||
        <div class="addon-data-contents {{cssClass}}" *ngIf="data">
 | 
			
		||||
            <core-style [css]="data.csstemplate" prefix=".{{cssClass}}"></core-style>
 | 
			
		||||
 | 
			
		||||
            <form (ngSubmit)="save($event)" [formGroup]="editForm" #editFormEl>
 | 
			
		||||
                <core-compile-html [text]="editFormRender" [jsData]="jsData" [extraImports]="extraImports"></core-compile-html>
 | 
			
		||||
 | 
			
		||||
@ -52,6 +52,8 @@ export class AddonModDataEditPage {
 | 
			
		||||
    protected siteId: string;
 | 
			
		||||
    protected offline: boolean;
 | 
			
		||||
    protected forceLeave = false; // To allow leaving the page without checking for changes.
 | 
			
		||||
    protected initialSelectedGroup = null;
 | 
			
		||||
    protected isEditing = false;
 | 
			
		||||
 | 
			
		||||
    title = '';
 | 
			
		||||
    component = AddonModDataProvider.COMPONENT;
 | 
			
		||||
@ -75,7 +77,10 @@ export class AddonModDataEditPage {
 | 
			
		||||
        this.module = params.get('module') || {};
 | 
			
		||||
        this.entryId = params.get('entryId') || null;
 | 
			
		||||
        this.courseId = params.get('courseId');
 | 
			
		||||
        this.selectedGroup = params.get('group') || 0;
 | 
			
		||||
        this.selectedGroup = this.entryId ? null : (params.get('group') || 0);
 | 
			
		||||
 | 
			
		||||
        // If entryId is lower than 0 or null, it is a new entry or an offline entry.
 | 
			
		||||
        this.isEditing = this.entryId && this.entryId > 0;
 | 
			
		||||
 | 
			
		||||
        this.siteId = sitesProvider.getCurrentSiteId();
 | 
			
		||||
 | 
			
		||||
@ -88,7 +93,7 @@ export class AddonModDataEditPage {
 | 
			
		||||
     * View loaded.
 | 
			
		||||
     */
 | 
			
		||||
    ionViewDidLoad(): void {
 | 
			
		||||
        this.fetchEntryData();
 | 
			
		||||
        this.fetchEntryData(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -103,7 +108,8 @@ export class AddonModDataEditPage {
 | 
			
		||||
 | 
			
		||||
        const inputData = this.editForm.value;
 | 
			
		||||
 | 
			
		||||
        const changed = await this.dataHelper.hasEditDataChanged(inputData, this.fieldsArray, this.data.id, this.entry.contents);
 | 
			
		||||
        let changed = await this.dataHelper.hasEditDataChanged(inputData, this.fieldsArray, this.data.id, this.entry.contents);
 | 
			
		||||
        changed = changed || (!this.isEditing && this.initialSelectedGroup != this.selectedGroup);
 | 
			
		||||
 | 
			
		||||
        if (changed) {
 | 
			
		||||
            // Show confirmation if some data has been modified.
 | 
			
		||||
@ -120,38 +126,78 @@ export class AddonModDataEditPage {
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch the entry data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param [refresh] To refresh all downloaded data.
 | 
			
		||||
     * @return Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected fetchEntryData(): Promise<any> {
 | 
			
		||||
        return this.dataProvider.getDatabase(this.courseId, this.module.id).then((data) => {
 | 
			
		||||
            this.title = data.name || this.title;
 | 
			
		||||
            this.data = data;
 | 
			
		||||
            this.cssClass = 'addon-data-entries-' + data.id;
 | 
			
		||||
    protected async fetchEntryData(refresh: boolean = false): Promise<void> {
 | 
			
		||||
        try {
 | 
			
		||||
            this.data = await this.dataProvider.getDatabase(this.courseId, this.module.id);
 | 
			
		||||
            this.title = this.data.name || this.title;
 | 
			
		||||
            this.cssClass = 'addon-data-entries-' + this.data.id;
 | 
			
		||||
 | 
			
		||||
            return this.dataProvider.getDatabaseAccessInformation(data.id, {cmId: this.module.id});
 | 
			
		||||
        }).then((accessData) => {
 | 
			
		||||
            if (this.entryId) {
 | 
			
		||||
                return this.groupsProvider.getActivityGroupInfo(this.data.coursemodule).then((groupInfo) => {
 | 
			
		||||
                    this.groupInfo = groupInfo;
 | 
			
		||||
                    this.selectedGroup = this.groupsProvider.validateGroupId(this.selectedGroup, groupInfo);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }).then(() => {
 | 
			
		||||
            return this.dataProvider.getFields(this.data.id, {cmId: this.module.id});
 | 
			
		||||
        }).then((fieldsData) => {
 | 
			
		||||
            this.fieldsArray = fieldsData;
 | 
			
		||||
            this.fields = this.utils.arrayToObject(fieldsData, 'id');
 | 
			
		||||
            this.fieldsArray = await this.dataProvider.getFields(this.data.id, {cmId: this.module.id});
 | 
			
		||||
            this.fields = this.utils.arrayToObject(this.fieldsArray, 'id');
 | 
			
		||||
 | 
			
		||||
            const entry = await this.dataHelper.fetchEntry(this.data, this.fieldsArray, this.entryId);
 | 
			
		||||
 | 
			
		||||
            return this.dataHelper.fetchEntry(this.data, fieldsData, this.entryId);
 | 
			
		||||
        }).then((entry) => {
 | 
			
		||||
            this.entry = entry.entry;
 | 
			
		||||
 | 
			
		||||
            this.editFormRender = this.displayEditFields();
 | 
			
		||||
        }).catch((message) => {
 | 
			
		||||
            this.domUtils.showErrorModalDefault(message, 'core.course.errorgetmodule', true);
 | 
			
		||||
        }).finally(() => {
 | 
			
		||||
            this.loaded = true;
 | 
			
		||||
            // Load correct group.
 | 
			
		||||
            this.selectedGroup = this.selectedGroup == null ? this.entry.groupid : this.selectedGroup;
 | 
			
		||||
 | 
			
		||||
            // Check permissions when adding a new entry or offline entry.
 | 
			
		||||
            if (!this.isEditing) {
 | 
			
		||||
                let haveAccess = false;
 | 
			
		||||
 | 
			
		||||
                if (refresh) {
 | 
			
		||||
                    this.groupInfo = await this.groupsProvider.getActivityGroupInfo(this.data.coursemodule);
 | 
			
		||||
                    this.selectedGroup = this.groupsProvider.validateGroupId(this.selectedGroup, this.groupInfo);
 | 
			
		||||
                    this.initialSelectedGroup = this.selectedGroup;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (this.groupInfo.groups.length > 0) {
 | 
			
		||||
                    if (refresh) {
 | 
			
		||||
                        const canAddGroup = {};
 | 
			
		||||
 | 
			
		||||
                        await Promise.all(this.groupInfo.groups.map(async (group) => {
 | 
			
		||||
                            const accessData = await this.dataProvider.getDatabaseAccessInformation(this.data.id, {
 | 
			
		||||
                                cmId: this.module.id, groupId: group.id});
 | 
			
		||||
 | 
			
		||||
                            canAddGroup[group.id] = accessData.canaddentry;
 | 
			
		||||
                        }));
 | 
			
		||||
 | 
			
		||||
                        this.groupInfo.groups = this.groupInfo.groups.filter((group) => {
 | 
			
		||||
                            return !!canAddGroup[group.id];
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                        haveAccess = canAddGroup[this.selectedGroup];
 | 
			
		||||
                    } else {
 | 
			
		||||
                        // Groups already filtered, so it have access.
 | 
			
		||||
                        haveAccess = true;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    const accessData = await this.dataProvider.getDatabaseAccessInformation(this.data.id, {cmId: this.module.id});
 | 
			
		||||
                    haveAccess = accessData.canaddentry;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (!haveAccess) {
 | 
			
		||||
                    // You shall not pass, go back.
 | 
			
		||||
                    this.domUtils.showErrorModal('addon.mod_data.noaccess', true);
 | 
			
		||||
 | 
			
		||||
                    // Go back to entry list.
 | 
			
		||||
                    this.forceLeave = true;
 | 
			
		||||
                    this.navCtrl.pop();
 | 
			
		||||
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.editFormRender = this.displayEditFields();
 | 
			
		||||
        } catch (message) {
 | 
			
		||||
            this.domUtils.showErrorModalDefault(message, 'core.course.errorgetmodule', true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.loaded = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -160,7 +206,7 @@ export class AddonModDataEditPage {
 | 
			
		||||
     * @param e Event.
 | 
			
		||||
     * @return Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    save(e: Event): Promise<any> {
 | 
			
		||||
    save(e: Event): Promise<void> {
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
        e.stopPropagation();
 | 
			
		||||
 | 
			
		||||
@ -169,6 +215,7 @@ export class AddonModDataEditPage {
 | 
			
		||||
        return this.dataHelper.hasEditDataChanged(inputData, this.fieldsArray, this.data.id,
 | 
			
		||||
                this.entry.contents).then((changed) => {
 | 
			
		||||
 | 
			
		||||
            changed = changed || (!this.isEditing && this.initialSelectedGroup != this.selectedGroup);
 | 
			
		||||
            if (!changed) {
 | 
			
		||||
                if (this.entryId) {
 | 
			
		||||
                    return this.returnToEntryList();
 | 
			
		||||
@ -196,7 +243,7 @@ export class AddonModDataEditPage {
 | 
			
		||||
                    return Promise.reject(e);
 | 
			
		||||
            }).then((editData) => {
 | 
			
		||||
                if (editData.length > 0) {
 | 
			
		||||
                    if (this.entryId) {
 | 
			
		||||
                    if (this.isEditing) {
 | 
			
		||||
                        return this.dataProvider.editEntry(this.data.id, this.entryId, this.courseId, editData, this.fields,
 | 
			
		||||
                            undefined, this.offline);
 | 
			
		||||
                    }
 | 
			
		||||
@ -213,20 +260,20 @@ export class AddonModDataEditPage {
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // This is done if entry is updated when editing or creating if not.
 | 
			
		||||
                if ((this.entryId && result.updated) || (!this.entryId && result.newentryid)) {
 | 
			
		||||
                if ((this.isEditing && result.updated) || (!this.isEditing && result.newentryid)) {
 | 
			
		||||
 | 
			
		||||
                    this.domUtils.triggerFormSubmittedEvent(this.formElement, result.sent, this.siteId);
 | 
			
		||||
 | 
			
		||||
                    if (result.sent) {
 | 
			
		||||
                        this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'data' });
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    const promises = [];
 | 
			
		||||
 | 
			
		||||
                    this.entryId = this.entryId || result.newentryid;
 | 
			
		||||
                    if (result.sent) {
 | 
			
		||||
                        this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'data' });
 | 
			
		||||
 | 
			
		||||
                        if (this.isEditing) {
 | 
			
		||||
                            promises.push(this.dataProvider.invalidateEntryData(this.data.id, this.entryId, this.siteId));
 | 
			
		||||
                        }
 | 
			
		||||
                        promises.push(this.dataProvider.invalidateEntriesData(this.data.id, this.siteId));
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return Promise.all(promises).then(() => {
 | 
			
		||||
                        this.eventsProvider.trigger(AddonModDataProvider.ENTRY_CHANGED,
 | 
			
		||||
@ -264,7 +311,7 @@ export class AddonModDataEditPage {
 | 
			
		||||
     * @param groupId Group identifier to set.
 | 
			
		||||
     * @return Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    setGroup(groupId: number): Promise<any> {
 | 
			
		||||
    setGroup(groupId: number): Promise<void> {
 | 
			
		||||
        this.selectedGroup = groupId;
 | 
			
		||||
        this.loaded = false;
 | 
			
		||||
 | 
			
		||||
@ -322,7 +369,7 @@ export class AddonModDataEditPage {
 | 
			
		||||
     *
 | 
			
		||||
     * @return Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected returnToEntryList(): Promise<any> {
 | 
			
		||||
    protected returnToEntryList(): Promise<void> {
 | 
			
		||||
        const inputData = this.editForm.value;
 | 
			
		||||
 | 
			
		||||
        return this.dataHelper.getEditTmpFiles(inputData, this.fieldsArray, this.data.id,
 | 
			
		||||
 | 
			
		||||
@ -117,46 +117,51 @@ export class AddonModDataProvider {
 | 
			
		||||
     * @param forceOffline Force editing entry in offline.
 | 
			
		||||
     * @return Promise resolved when the action is done.
 | 
			
		||||
     */
 | 
			
		||||
    addEntry(dataId: number, entryId: number, courseId: number, contents: AddonModDataSubfieldData[], groupId: number = 0,
 | 
			
		||||
    async addEntry(dataId: number, entryId: number, courseId: number, contents: AddonModDataSubfieldData[], groupId: number = 0,
 | 
			
		||||
            fields: any, siteId?: string, forceOffline: boolean = false): Promise<any> {
 | 
			
		||||
        siteId = siteId || this.sitesProvider.getCurrentSiteId();
 | 
			
		||||
 | 
			
		||||
        // Convenience function to store a data to be synchronized later.
 | 
			
		||||
        const storeOffline = (): Promise<any> => {
 | 
			
		||||
            return this.dataOffline.saveEntry(dataId, entryId, 'add', courseId, groupId, contents, undefined, siteId)
 | 
			
		||||
                    .then((entry) => {
 | 
			
		||||
        const storeOffline = async (): Promise<any> => {
 | 
			
		||||
            const entry = await this.dataOffline.saveEntry(dataId, entryId, 'add', courseId, groupId, contents, undefined, siteId);
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                // Return provissional entry Id.
 | 
			
		||||
                newentryid: entry,
 | 
			
		||||
                sent: false,
 | 
			
		||||
            };
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Checks to store offline.
 | 
			
		||||
        if (!this.appProvider.isOnline() || forceOffline) {
 | 
			
		||||
            const notifications = this.checkFields(fields, contents);
 | 
			
		||||
            if (notifications) {
 | 
			
		||||
                return Promise.resolve({
 | 
			
		||||
                    fieldnotifications: notifications
 | 
			
		||||
                });
 | 
			
		||||
                return { fieldnotifications: notifications };
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Remove unnecessary not synced actions.
 | 
			
		||||
        await this.deleteEntryOfflineAction(dataId, entryId, 'add', siteId);
 | 
			
		||||
 | 
			
		||||
        // App is offline, store the action.
 | 
			
		||||
        if (!this.appProvider.isOnline() || forceOffline) {
 | 
			
		||||
            return storeOffline();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this.addEntryOnline(dataId, contents, groupId, siteId).then((result) => {
 | 
			
		||||
        try {
 | 
			
		||||
            const result = await this.addEntryOnline(dataId, contents, groupId, siteId);
 | 
			
		||||
            result.sent = true;
 | 
			
		||||
 | 
			
		||||
            return result;
 | 
			
		||||
        }).catch((error) => {
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            if (this.utils.isWebServiceError(error)) {
 | 
			
		||||
                // The WebService has thrown an error, this means that responses cannot be submitted.
 | 
			
		||||
                return Promise.reject(error);
 | 
			
		||||
                throw error;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Couldn't connect to server, store in offline.
 | 
			
		||||
            return storeOffline();
 | 
			
		||||
        });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -193,48 +198,49 @@ export class AddonModDataProvider {
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved when the action is done.
 | 
			
		||||
     */
 | 
			
		||||
    approveEntry(dataId: number, entryId: number, approve: boolean, courseId: number, siteId?: string): Promise<any> {
 | 
			
		||||
    async approveEntry(dataId: number, entryId: number, approve: boolean, courseId: number, siteId?: string): Promise<any> {
 | 
			
		||||
        siteId = siteId || this.sitesProvider.getCurrentSiteId();
 | 
			
		||||
 | 
			
		||||
        // Convenience function to store a data to be synchronized later.
 | 
			
		||||
        const storeOffline = (): Promise<any> => {
 | 
			
		||||
        const storeOffline = async (): Promise<any> => {
 | 
			
		||||
            const action = approve ? 'approve' : 'disapprove';
 | 
			
		||||
 | 
			
		||||
            return this.dataOffline.saveEntry(dataId, entryId, action, courseId, undefined, undefined, undefined, siteId)
 | 
			
		||||
                    .then(() => {
 | 
			
		||||
            await this.dataOffline.saveEntry(dataId, entryId, action, courseId, undefined, undefined, undefined, siteId);
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                sent: false,
 | 
			
		||||
            };
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Get if the opposite action is not synced.
 | 
			
		||||
        const oppositeAction = approve ? 'disapprove' : 'approve';
 | 
			
		||||
 | 
			
		||||
        return this.dataOffline.getEntry(dataId, entryId, oppositeAction, siteId).then(() => {
 | 
			
		||||
            // Found. Just delete the action.
 | 
			
		||||
            return this.dataOffline.deleteEntry(dataId, entryId, oppositeAction, siteId);
 | 
			
		||||
        }).catch(() => {
 | 
			
		||||
        const found = await this.deleteEntryOfflineAction(dataId, entryId, oppositeAction, siteId);
 | 
			
		||||
        if (found) {
 | 
			
		||||
            // Offline action has been found and deleted. Stop here.
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!this.appProvider.isOnline()) {
 | 
			
		||||
            // App is offline, store the action.
 | 
			
		||||
            return storeOffline();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            return this.approveEntryOnline(entryId, approve, siteId).then(() => {
 | 
			
		||||
        try {
 | 
			
		||||
            await this.approveEntryOnline(entryId, approve, siteId);
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                sent: true,
 | 
			
		||||
            };
 | 
			
		||||
            }).catch((error) => {
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            if (this.utils.isWebServiceError(error)) {
 | 
			
		||||
                // The WebService has thrown an error, this means that responses cannot be submitted.
 | 
			
		||||
                    return Promise.reject(error);
 | 
			
		||||
                throw error;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Couldn't connect to server, store in offline.
 | 
			
		||||
            return storeOffline();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -298,38 +304,22 @@ export class AddonModDataProvider {
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved when the action is done.
 | 
			
		||||
     */
 | 
			
		||||
    deleteEntry(dataId: number, entryId: number, courseId: number, siteId?: string): Promise<any> {
 | 
			
		||||
    async deleteEntry(dataId: number, entryId: number, courseId: number, siteId?: string): Promise<any> {
 | 
			
		||||
        siteId = siteId || this.sitesProvider.getCurrentSiteId();
 | 
			
		||||
 | 
			
		||||
        // Convenience function to store a data to be synchronized later.
 | 
			
		||||
        const storeOffline = (): Promise<any> => {
 | 
			
		||||
            return this.dataOffline.saveEntry(dataId, entryId, 'delete', courseId, undefined, undefined, undefined, siteId)
 | 
			
		||||
                    .then(() => {
 | 
			
		||||
        const storeOffline = async (): Promise<any> => {
 | 
			
		||||
            await this.dataOffline.saveEntry(dataId, entryId, 'delete', courseId, undefined, undefined, undefined, siteId);
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                sent: false,
 | 
			
		||||
            };
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let justAdded = false;
 | 
			
		||||
 | 
			
		||||
        // Check if the opposite action is not synced and just delete it.
 | 
			
		||||
        return this.dataOffline.getEntryActions(dataId, entryId, siteId).then((entries) => {
 | 
			
		||||
            if (entries && entries.length) {
 | 
			
		||||
                // Found. Delete other actions first.
 | 
			
		||||
                const proms = entries.map((entry) => {
 | 
			
		||||
                    if (entry.action == 'add') {
 | 
			
		||||
                        justAdded = true;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return this.dataOffline.deleteEntry(dataId, entryId, entry.action, siteId);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Promise.all(proms);
 | 
			
		||||
            }
 | 
			
		||||
        }).then(() => {
 | 
			
		||||
            if (justAdded) {
 | 
			
		||||
                // The field was added offline, delete and stop.
 | 
			
		||||
        const addedOffline = await this.deleteEntryOfflineAction(dataId, entryId, 'add', siteId);
 | 
			
		||||
        if (addedOffline) {
 | 
			
		||||
            // Offline add action found and deleted. Stop here.
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -338,20 +328,21 @@ export class AddonModDataProvider {
 | 
			
		||||
            return storeOffline();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            return this.deleteEntryOnline(entryId, siteId).then(() => {
 | 
			
		||||
        try {
 | 
			
		||||
            await this.deleteEntryOnline(entryId, siteId);
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                sent: true,
 | 
			
		||||
            };
 | 
			
		||||
            }).catch((error) => {
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            if (this.utils.isWebServiceError(error)) {
 | 
			
		||||
                // The WebService has thrown an error, this means that responses cannot be submitted.
 | 
			
		||||
                    return Promise.reject(error);
 | 
			
		||||
                throw error;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Couldn't connect to server, store in offline.
 | 
			
		||||
            return storeOffline();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -371,6 +362,29 @@ export class AddonModDataProvider {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete entry offline action.
 | 
			
		||||
     *
 | 
			
		||||
     * @param dataId Database ID.
 | 
			
		||||
     * @param entryId Entry ID.
 | 
			
		||||
     * @param action Action name to delete.
 | 
			
		||||
     * @param siteId Site ID.
 | 
			
		||||
     * @return Resolved with true if the action has been found and deleted.
 | 
			
		||||
     */
 | 
			
		||||
    protected async deleteEntryOfflineAction(dataId: number, entryId: number, action: string, siteId: string): Promise<boolean> {
 | 
			
		||||
        // Get other not not synced actions.
 | 
			
		||||
        try {
 | 
			
		||||
            await this.dataOffline.getEntry(dataId, entryId, action, siteId);
 | 
			
		||||
 | 
			
		||||
            await this.dataOffline.deleteEntry(dataId, entryId, action, siteId);
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            // Not found.
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates an existing entry.
 | 
			
		||||
     *
 | 
			
		||||
@ -383,81 +397,49 @@ export class AddonModDataProvider {
 | 
			
		||||
     * @param forceOffline Force editing entry in offline.
 | 
			
		||||
     * @return Promise resolved when the action is done.
 | 
			
		||||
     */
 | 
			
		||||
    editEntry(dataId: number, entryId: number, courseId: number, contents: AddonModDataSubfieldData[], fields: any, siteId?: string,
 | 
			
		||||
            forceOffline: boolean = false): Promise<any> {
 | 
			
		||||
    async editEntry(dataId: number, entryId: number, courseId: number, contents: AddonModDataSubfieldData[], fields: any,
 | 
			
		||||
            siteId?: string, forceOffline: boolean = false): Promise<any> {
 | 
			
		||||
        siteId = siteId || this.sitesProvider.getCurrentSiteId();
 | 
			
		||||
 | 
			
		||||
        // Convenience function to store a data to be synchronized later.
 | 
			
		||||
        const storeOffline = (): Promise<any> => {
 | 
			
		||||
            return this.dataOffline.saveEntry(dataId, entryId, 'edit', courseId, undefined, contents, undefined, siteId)
 | 
			
		||||
                    .then(() => {
 | 
			
		||||
        const storeOffline = async (): Promise<any> => {
 | 
			
		||||
            await this.dataOffline.saveEntry(dataId, entryId, 'edit', courseId, undefined, contents, undefined, siteId);
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                updated: true,
 | 
			
		||||
                sent: false,
 | 
			
		||||
            };
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let justAdded = false,
 | 
			
		||||
            groupId;
 | 
			
		||||
 | 
			
		||||
        if (!this.appProvider.isOnline() || forceOffline) {
 | 
			
		||||
            const notifications = this.checkFields(fields, contents);
 | 
			
		||||
            if (notifications) {
 | 
			
		||||
                return Promise.resolve({
 | 
			
		||||
                    fieldnotifications: notifications
 | 
			
		||||
                });
 | 
			
		||||
                return { fieldnotifications: notifications };
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Get other not not synced actions.
 | 
			
		||||
        return this.dataOffline.getEntryActions(dataId, entryId, siteId).then((entries) => {
 | 
			
		||||
            if (entries && entries.length) {
 | 
			
		||||
                // Found. Delete add and edit actions first.
 | 
			
		||||
                const proms = [];
 | 
			
		||||
                entries.forEach((entry) => {
 | 
			
		||||
                    if (entry.action == 'add') {
 | 
			
		||||
                        justAdded = true;
 | 
			
		||||
                        groupId = entry.groupid;
 | 
			
		||||
                        proms.push(this.dataOffline.deleteEntry(dataId, entryId, entry.action, siteId));
 | 
			
		||||
                    } else if (entry.action == 'edit') {
 | 
			
		||||
                        proms.push(this.dataOffline.deleteEntry(dataId, entryId, entry.action, siteId));
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Promise.all(proms);
 | 
			
		||||
            }
 | 
			
		||||
        }).then(() => {
 | 
			
		||||
            if (justAdded) {
 | 
			
		||||
                // The field was added offline, add again and stop.
 | 
			
		||||
                return this.addEntry(dataId, entryId, courseId, contents, groupId, fields, siteId, forceOffline)
 | 
			
		||||
                        .then((result) => {
 | 
			
		||||
                    result.updated = true;
 | 
			
		||||
                    result.sent = true;
 | 
			
		||||
 | 
			
		||||
                    return result;
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        // Remove unnecessary not synced actions.
 | 
			
		||||
        await this.deleteEntryOfflineAction(dataId, entryId, 'edit', siteId);
 | 
			
		||||
 | 
			
		||||
        if (!this.appProvider.isOnline() || forceOffline) {
 | 
			
		||||
            // App is offline, store the action.
 | 
			
		||||
            return storeOffline();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            return this.editEntryOnline(entryId, contents, siteId).then((result) => {
 | 
			
		||||
        try {
 | 
			
		||||
            const result = await this.editEntryOnline(entryId, contents, siteId);
 | 
			
		||||
            result.sent = true;
 | 
			
		||||
 | 
			
		||||
            return result;
 | 
			
		||||
            }).catch((error) => {
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            if (this.utils.isWebServiceError(error)) {
 | 
			
		||||
                // The WebService has thrown an error, this means that responses cannot be submitted.
 | 
			
		||||
                    return Promise.reject(error);
 | 
			
		||||
                throw error;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Couldn't connect to server, store in offline.
 | 
			
		||||
            return storeOffline();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
        }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,6 @@ import { CoreEventsProvider } from '@providers/events';
 | 
			
		||||
import { CoreSitesProvider } from '@providers/sites';
 | 
			
		||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
			
		||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
 | 
			
		||||
import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
			
		||||
import { CoreCourseProvider } from '@core/course/providers/course';
 | 
			
		||||
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
 | 
			
		||||
import { AddonModDataFieldsDelegate } from './fields-delegate';
 | 
			
		||||
@ -35,12 +34,19 @@ import { CoreRatingOfflineProvider } from '@core/rating/providers/offline';
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AddonModDataHelperProvider {
 | 
			
		||||
 | 
			
		||||
    constructor(private sitesProvider: CoreSitesProvider, protected dataProvider: AddonModDataProvider,
 | 
			
		||||
        private translate: TranslateService, private fieldsDelegate: AddonModDataFieldsDelegate,
 | 
			
		||||
        private dataOffline: AddonModDataOfflineProvider, private fileUploaderProvider: CoreFileUploaderProvider,
 | 
			
		||||
        private textUtils: CoreTextUtilsProvider, private eventsProvider: CoreEventsProvider, private utils: CoreUtilsProvider,
 | 
			
		||||
        private domUtils: CoreDomUtilsProvider, private courseProvider: CoreCourseProvider,
 | 
			
		||||
        private ratingOffline: CoreRatingOfflineProvider) {}
 | 
			
		||||
    constructor(
 | 
			
		||||
        protected sitesProvider: CoreSitesProvider,
 | 
			
		||||
        protected dataProvider: AddonModDataProvider,
 | 
			
		||||
        protected translate: TranslateService,
 | 
			
		||||
        protected fieldsDelegate: AddonModDataFieldsDelegate,
 | 
			
		||||
        protected dataOffline: AddonModDataOfflineProvider,
 | 
			
		||||
        protected fileUploaderProvider: CoreFileUploaderProvider,
 | 
			
		||||
        protected textUtils: CoreTextUtilsProvider,
 | 
			
		||||
        protected eventsProvider: CoreEventsProvider,
 | 
			
		||||
        protected domUtils: CoreDomUtilsProvider,
 | 
			
		||||
        protected courseProvider: CoreCourseProvider,
 | 
			
		||||
        protected ratingOffline: CoreRatingOfflineProvider
 | 
			
		||||
        ) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the record with the offline actions applied.
 | 
			
		||||
@ -632,35 +638,44 @@ export class AddonModDataHelperProvider {
 | 
			
		||||
     * @param courseId Course ID. It not defined, it will be fetched.
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     */
 | 
			
		||||
    showDeleteEntryModal(dataId: number, entryId: number, courseId?: number, siteId?: string): void {
 | 
			
		||||
    async showDeleteEntryModal(dataId: number, entryId: number, courseId?: number, siteId?: string): Promise<void> {
 | 
			
		||||
        siteId = siteId || this.sitesProvider.getCurrentSiteId();
 | 
			
		||||
 | 
			
		||||
        this.domUtils.showDeleteConfirm('addon.mod_data.confirmdeleterecord').then(() => {
 | 
			
		||||
            const modal = this.domUtils.showModalLoading();
 | 
			
		||||
        let modal;
 | 
			
		||||
        try {
 | 
			
		||||
            await this.domUtils.showDeleteConfirm('addon.mod_data.confirmdeleterecord');
 | 
			
		||||
 | 
			
		||||
            return this.getActivityCourseIdIfNotSet(dataId, courseId, siteId).then((courseId) => {
 | 
			
		||||
                return this.dataProvider.deleteEntry(dataId, entryId, courseId, siteId);
 | 
			
		||||
            }).catch((message) => {
 | 
			
		||||
            modal = this.domUtils.showModalLoading();
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                if (entryId > 0) {
 | 
			
		||||
                    courseId = await this.getActivityCourseIdIfNotSet(dataId, courseId, siteId);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.dataProvider.deleteEntry(dataId, entryId, courseId, siteId);
 | 
			
		||||
            } catch (message) {
 | 
			
		||||
                this.domUtils.showErrorModalDefault(message, 'addon.mod_data.errordeleting', true);
 | 
			
		||||
 | 
			
		||||
                return Promise.reject(null);
 | 
			
		||||
            }).then(() => {
 | 
			
		||||
                return this.utils.allPromises([
 | 
			
		||||
                    this.dataProvider.invalidateEntryData(dataId, entryId, siteId),
 | 
			
		||||
                    this.dataProvider.invalidateEntriesData(dataId, siteId)
 | 
			
		||||
                ]).catch(() => {
 | 
			
		||||
                modal && modal.dismiss();
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                await this.dataProvider.invalidateEntryData(dataId, entryId, siteId);
 | 
			
		||||
                await this.dataProvider.invalidateEntriesData(dataId, siteId);
 | 
			
		||||
            } catch (error) {
 | 
			
		||||
                // Ignore errors.
 | 
			
		||||
                });
 | 
			
		||||
            }).then(() => {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.eventsProvider.trigger(AddonModDataProvider.ENTRY_CHANGED, {dataId, entryId,  deleted: true}, siteId);
 | 
			
		||||
 | 
			
		||||
            this.domUtils.showToast('addon.mod_data.recorddeleted', true, 3000);
 | 
			
		||||
            }).finally(() => {
 | 
			
		||||
                modal.dismiss();
 | 
			
		||||
            });
 | 
			
		||||
        }).catch(() => {
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            // Ignore error, it was already displayed.
 | 
			
		||||
        });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        modal && modal.dismiss();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -513,6 +513,7 @@
 | 
			
		||||
    "addon.mod_data.modulenameplural": "Databases",
 | 
			
		||||
    "addon.mod_data.more": "More",
 | 
			
		||||
    "addon.mod_data.mylocation": "My location",
 | 
			
		||||
    "addon.mod_data.noaccess": "You do not have access to this page",
 | 
			
		||||
    "addon.mod_data.nomatch": "No matching entries found!",
 | 
			
		||||
    "addon.mod_data.norecords": "No entries in database",
 | 
			
		||||
    "addon.mod_data.notapproved": "Entry is not approved yet.",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user