From ce09ee8a6c0a6800f86046e6ec444135f5417d91 Mon Sep 17 00:00:00 2001
From: Noel De Martin
Date: Tue, 28 Mar 2023 13:44:20 +0200
Subject: [PATCH] MOBILE-2652 glossary: Refactor navigation
Instead of showing the form for offline entries, we're showing them as normal entries and the form is only used for creating new entries. Additionally, the form won't be shown as a split view item any longer, it will always open a new page.
---
scripts/langindex.json | 1 +
.../classes/glossary-entries-source.ts | 30 +-
.../classes/glossary-entries-swipe-manager.ts | 31 --
.../index/addon-mod-glossary-index.html | 11 +-
.../mod/glossary/components/index/index.scss | 13 +
.../mod/glossary/components/index/index.ts | 8 +-
.../mod/glossary/glossary-lazy.module.ts | 16 +-
src/addons/mod/glossary/glossary.module.ts | 53 +--
src/addons/mod/glossary/lang.json | 1 +
src/addons/mod/glossary/pages/edit/edit.html | 2 +-
src/addons/mod/glossary/pages/edit/edit.ts | 346 ++++++++----------
.../mod/glossary/pages/entry/entry.html | 43 ++-
src/addons/mod/glossary/pages/entry/entry.ts | 181 +++++----
.../glossary/services/handlers/edit-link.ts | 10 +-
.../glossary/services/handlers/entry-link.ts | 10 +-
.../glossary/tests/behat/navigation.feature | 1 +
16 files changed, 360 insertions(+), 397 deletions(-)
delete mode 100644 src/addons/mod/glossary/classes/glossary-entries-swipe-manager.ts
create mode 100644 src/addons/mod/glossary/components/index/index.scss
diff --git a/scripts/langindex.json b/scripts/langindex.json
index 4d1fdd0b8..cfc5ef1f8 100644
--- a/scripts/langindex.json
+++ b/scripts/langindex.json
@@ -697,6 +697,7 @@
"addon.mod_glossary.definition": "glossary",
"addon.mod_glossary.deleteentry": "glossary",
"addon.mod_glossary.entriestobesynced": "local_moodlemobileapp",
+ "addon.mod_glossary.entry": "glossary",
"addon.mod_glossary.entrydeleted": "glossary",
"addon.mod_glossary.entrypendingapproval": "local_moodlemobileapp",
"addon.mod_glossary.entryusedynalink": "glossary",
diff --git a/src/addons/mod/glossary/classes/glossary-entries-source.ts b/src/addons/mod/glossary/classes/glossary-entries-source.ts
index 057856e55..cd45af84c 100644
--- a/src/addons/mod/glossary/classes/glossary-entries-source.ts
+++ b/src/addons/mod/glossary/classes/glossary-entries-source.ts
@@ -29,8 +29,6 @@ import { AddonModGlossaryOffline, AddonModGlossaryOfflineEntry } from '../servic
*/
export class AddonModGlossaryEntriesSource extends CoreRoutedItemsManagerSource {
- static readonly NEW_ENTRY: AddonModGlossaryNewEntryForm = { newEntry: true };
-
readonly COURSE_ID: number;
readonly CM_ID: number;
readonly GLOSSARY_PATH_PREFIX: string;
@@ -54,16 +52,6 @@ export class AddonModGlossaryEntriesSource extends CoreRoutedItemsManagerSource<
this.GLOSSARY_PATH_PREFIX = glossaryPathPrefix;
}
- /**
- * Type guard to infer NewEntryForm objects.
- *
- * @param entry Item to check.
- * @returns Whether the item is a new entry form.
- */
- isNewEntryForm(entry: AddonModGlossaryEntryItem): entry is AddonModGlossaryNewEntryForm {
- return 'newEntry' in entry;
- }
-
/**
* Type guard to infer entry objects.
*
@@ -81,22 +69,18 @@ export class AddonModGlossaryEntriesSource extends CoreRoutedItemsManagerSource<
* @returns Whether the item is an offline entry.
*/
isOfflineEntry(entry: AddonModGlossaryEntryItem): entry is AddonModGlossaryOfflineEntry {
- return !this.isNewEntryForm(entry) && !this.isOnlineEntry(entry);
+ return !this.isOnlineEntry(entry);
}
/**
* @inheritdoc
*/
getItemPath(entry: AddonModGlossaryEntryItem): string {
- if (this.isOnlineEntry(entry)) {
- return `${this.GLOSSARY_PATH_PREFIX}entry/${entry.id}`;
- }
-
if (this.isOfflineEntry(entry)) {
- return `${this.GLOSSARY_PATH_PREFIX}edit/${entry.timecreated}`;
+ return `${this.GLOSSARY_PATH_PREFIX}entry/new-${entry.timecreated}`;
}
- return `${this.GLOSSARY_PATH_PREFIX}edit/0`;
+ return `${this.GLOSSARY_PATH_PREFIX}entry/${entry.id}`;
}
/**
@@ -263,7 +247,6 @@ export class AddonModGlossaryEntriesSource extends CoreRoutedItemsManagerSource<
offlineEntries.sort((a, b) => a.concept.localeCompare(b.concept));
- entries.push(AddonModGlossaryEntriesSource.NEW_ENTRY);
entries.push(...offlineEntries);
}
@@ -315,12 +298,7 @@ export class AddonModGlossaryEntriesSource extends CoreRoutedItemsManagerSource<
/**
* Type of items that can be held by the entries manager.
*/
-export type AddonModGlossaryEntryItem = AddonModGlossaryEntry | AddonModGlossaryOfflineEntry | AddonModGlossaryNewEntryForm;
-
-/**
- * Type to select the new entry form.
- */
-export type AddonModGlossaryNewEntryForm = { newEntry: true };
+export type AddonModGlossaryEntryItem = AddonModGlossaryEntry | AddonModGlossaryOfflineEntry;
/**
* Fetch mode to sort entries.
diff --git a/src/addons/mod/glossary/classes/glossary-entries-swipe-manager.ts b/src/addons/mod/glossary/classes/glossary-entries-swipe-manager.ts
deleted file mode 100644
index b1136068b..000000000
--- a/src/addons/mod/glossary/classes/glossary-entries-swipe-manager.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-// (C) Copyright 2015 Moodle Pty Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import { CoreSwipeNavigationItemsManager } from '@classes/items-management/swipe-navigation-items-manager';
-import { AddonModGlossaryEntriesSource, AddonModGlossaryEntryItem } from './glossary-entries-source';
-
-/**
- * Helper to manage swiping within a collection of glossary entries.
- */
-export abstract class AddonModGlossaryEntriesSwipeManager
- extends CoreSwipeNavigationItemsManager {
-
- /**
- * @inheritdoc
- */
- protected skipItemInSwipe(item: AddonModGlossaryEntryItem): boolean {
- return this.getSource().isNewEntryForm(item);
- }
-
-}
diff --git a/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html b/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html
index 2413ed563..1198552e1 100644
--- a/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html
+++ b/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html
@@ -31,7 +31,7 @@
[componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()">
- 0">
+ 0" class="addon-mod-glossary-index--offline-entries">
{{ 'addon.mod_glossary.entriestobesynced' | translate }}
@@ -40,9 +40,12 @@
-
-
+
+
+
+
+
diff --git a/src/addons/mod/glossary/components/index/index.scss b/src/addons/mod/glossary/components/index/index.scss
new file mode 100644
index 000000000..96c31cca1
--- /dev/null
+++ b/src/addons/mod/glossary/components/index/index.scss
@@ -0,0 +1,13 @@
+:host {
+
+ .addon-mod-glossary-index--offline-entries {
+ border-bottom: 1px solid var(--stroke);
+ }
+
+ .addon-mod-glossary-index--offline-entry {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ }
+
+}
diff --git a/src/addons/mod/glossary/components/index/index.ts b/src/addons/mod/glossary/components/index/index.ts
index b7a797451..904f91028 100644
--- a/src/addons/mod/glossary/components/index/index.ts
+++ b/src/addons/mod/glossary/components/index/index.ts
@@ -26,6 +26,7 @@ import { CoreRatingProvider } from '@features/rating/services/rating';
import { CoreRatingOffline } from '@features/rating/services/rating-offline';
import { CoreRatingSyncProvider } from '@features/rating/services/rating-sync';
import { IonContent } from '@ionic/angular';
+import { CoreNavigator } from '@services/navigator';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreTextUtils } from '@services/utils/text';
@@ -61,6 +62,7 @@ import { AddonModGlossaryModePickerPopoverComponent } from '../mode-picker/mode-
@Component({
selector: 'addon-mod-glossary-index',
templateUrl: 'addon-mod-glossary-index.html',
+ styleUrls: ['index.scss'],
})
export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivityComponent
implements OnInit, AfterViewInit, OnDestroy {
@@ -399,7 +401,11 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
* Opens new entry editor.
*/
openNewEntry(): void {
- this.entries?.select(AddonModGlossaryEntriesSource.NEW_ENTRY);
+ CoreNavigator.navigate(
+ this.splitView.outletActivated
+ ? '../new'
+ : './entry/new',
+ );
}
/**
diff --git a/src/addons/mod/glossary/glossary-lazy.module.ts b/src/addons/mod/glossary/glossary-lazy.module.ts
index c96ce6e7d..8f12bc001 100644
--- a/src/addons/mod/glossary/glossary-lazy.module.ts
+++ b/src/addons/mod/glossary/glossary-lazy.module.ts
@@ -27,13 +27,9 @@ const mobileRoutes: Routes = [
component: AddonModGlossaryIndexPage,
},
{
- path: ':courseId/:cmId/entry/:entryId',
+ path: ':courseId/:cmId/entry/:entrySlug',
loadChildren: () => import('./glossary-entry-lazy.module').then(m => m.AddonModGlossaryEntryLazyModule),
},
- {
- path: ':courseId/:cmId/edit/:timecreated',
- loadChildren: () => import('./glossary-edit-lazy.module').then(m => m.AddonModGlossaryEditLazyModule),
- },
];
const tabletRoutes: Routes = [
@@ -42,18 +38,18 @@ const tabletRoutes: Routes = [
component: AddonModGlossaryIndexPage,
children: [
{
- path: 'entry/:entryId',
+ path: 'entry/:entrySlug',
loadChildren: () => import('./glossary-entry-lazy.module').then(m => m.AddonModGlossaryEntryLazyModule),
},
- {
- path: 'edit/:timecreated',
- loadChildren: () => import('./glossary-edit-lazy.module').then(m => m.AddonModGlossaryEditLazyModule),
- },
],
},
];
const routes: Routes = [
+ {
+ path: ':courseId/:cmId/entry/new',
+ loadChildren: () => import('./glossary-edit-lazy.module').then(m => m.AddonModGlossaryEditLazyModule),
+ },
...conditionalRoutes(mobileRoutes, () => CoreScreen.isMobile),
...conditionalRoutes(tabletRoutes, () => CoreScreen.isTablet),
];
diff --git a/src/addons/mod/glossary/glossary.module.ts b/src/addons/mod/glossary/glossary.module.ts
index 82def7f99..3b58c3b10 100644
--- a/src/addons/mod/glossary/glossary.module.ts
+++ b/src/addons/mod/glossary/glossary.module.ts
@@ -49,50 +49,35 @@ export const ADDON_MOD_GLOSSARY_SERVICES: Type[] = [
];
const mainMenuRoutes: Routes = [
- {
- path: `${AddonModGlossaryModuleHandlerService.PAGE_NAME}/entry/:entryId`,
- loadChildren: () => import('./glossary-entry-lazy.module').then(m => m.AddonModGlossaryEntryLazyModule),
- data: { swipeEnabled: false },
- },
- {
- path: `${AddonModGlossaryModuleHandlerService.PAGE_NAME}/edit/:timecreated`,
- loadChildren: () => import('./glossary-edit-lazy.module').then(m => m.AddonModGlossaryEditLazyModule),
- data: { swipeEnabled: false },
- },
+ // Course activity navigation.
{
path: AddonModGlossaryModuleHandlerService.PAGE_NAME,
loadChildren: () => import('./glossary-lazy.module').then(m => m.AddonModGlossaryLazyModule),
},
+
+ // Single Activity format navigation.
+ {
+ path: `${COURSE_CONTENTS_PATH}/${AddonModGlossaryModuleHandlerService.PAGE_NAME}/entry/new`,
+ loadChildren: () => import('./glossary-edit-lazy.module').then(m => m.AddonModGlossaryEditLazyModule),
+ data: { glossaryPathPrefix: `${AddonModGlossaryModuleHandlerService.PAGE_NAME}/` },
+ },
...conditionalRoutes(
- [
- {
- path: `${COURSE_CONTENTS_PATH}/${AddonModGlossaryModuleHandlerService.PAGE_NAME}/entry/:entryId`,
- loadChildren: () => import('./glossary-entry-lazy.module').then(m => m.AddonModGlossaryEntryLazyModule),
- data: { glossaryPathPrefix: `${AddonModGlossaryModuleHandlerService.PAGE_NAME}/` },
- },
- {
- path: `${COURSE_CONTENTS_PATH}/${AddonModGlossaryModuleHandlerService.PAGE_NAME}/edit/:timecreated`,
- loadChildren: () => import('./glossary-edit-lazy.module').then(m => m.AddonModGlossaryEditLazyModule),
- data: { glossaryPathPrefix: `${AddonModGlossaryModuleHandlerService.PAGE_NAME}/` },
- },
- ],
+ [{
+ path: `${COURSE_CONTENTS_PATH}/${AddonModGlossaryModuleHandlerService.PAGE_NAME}/entry/:entrySlug`,
+ loadChildren: () => import('./glossary-entry-lazy.module').then(m => m.AddonModGlossaryEntryLazyModule),
+ data: { glossaryPathPrefix: `${AddonModGlossaryModuleHandlerService.PAGE_NAME}/` },
+ }],
() => CoreScreen.isMobile,
),
];
+// Single Activity format navigation.
const courseContentsRoutes: Routes = conditionalRoutes(
- [
- {
- path: `${AddonModGlossaryModuleHandlerService.PAGE_NAME}/entry/:entryId`,
- loadChildren: () => import('./glossary-entry-lazy.module').then(m => m.AddonModGlossaryEntryLazyModule),
- data: { glossaryPathPrefix: `${AddonModGlossaryModuleHandlerService.PAGE_NAME}/` },
- },
- {
- path: `${AddonModGlossaryModuleHandlerService.PAGE_NAME}/edit/:timecreated`,
- loadChildren: () => import('./glossary-edit-lazy.module').then(m => m.AddonModGlossaryEditLazyModule),
- data: { glossaryPathPrefix: `${AddonModGlossaryModuleHandlerService.PAGE_NAME}/` },
- },
- ],
+ [{
+ path: `${AddonModGlossaryModuleHandlerService.PAGE_NAME}/entry/:entrySlug`,
+ loadChildren: () => import('./glossary-entry-lazy.module').then(m => m.AddonModGlossaryEntryLazyModule),
+ data: { glossaryPathPrefix: `${AddonModGlossaryModuleHandlerService.PAGE_NAME}/` },
+ }],
() => CoreScreen.isTablet,
);
diff --git a/src/addons/mod/glossary/lang.json b/src/addons/mod/glossary/lang.json
index 6206a6430..124f2c100 100644
--- a/src/addons/mod/glossary/lang.json
+++ b/src/addons/mod/glossary/lang.json
@@ -17,6 +17,7 @@
"definition": "Definition",
"deleteentry": "Delete entry",
"entriestobesynced": "Entries to be synced",
+ "entry": "Entry",
"entrydeleted": "Entry deleted",
"entrypendingapproval": "This entry is pending approval.",
"entryusedynalink": "This entry should be automatically linked",
diff --git a/src/addons/mod/glossary/pages/edit/edit.html b/src/addons/mod/glossary/pages/edit/edit.html
index 835718d27..eee439c4a 100644
--- a/src/addons/mod/glossary/pages/edit/edit.html
+++ b/src/addons/mod/glossary/pages/edit/edit.html
@@ -11,7 +11,7 @@
-
+
- {{ entry.timemodified | coreDateDayOrTime }}
+ {{ onlineEntry.timemodified | coreDateDayOrTime }}
@@ -53,32 +59,37 @@
-
-
+
+
- 0">
+
+
+
+
+ 0">
{{ 'core.tag.tags' | translate }}:
-
+
-
+
{{ 'addon.mod_glossary.entrypendingapproval' | translate }}
- 0 && commentsEnabled" contextLevel="module"
- [instanceId]="glossary.coursemodule" component="mod_glossary" [itemId]="entry.id" area="glossary_entry"
- [courseId]="glossary.course" [showItem]="true">
+ 0 && commentsEnabled"
+ contextLevel="module" [instanceId]="glossary.coursemodule" component="mod_glossary" [itemId]="onlineEntry.id"
+ area="glossary_entry" [courseId]="glossary.course" [showItem]="true">
-
-
+
diff --git a/src/addons/mod/glossary/pages/entry/entry.ts b/src/addons/mod/glossary/pages/entry/entry.ts
index 1db3fc59e..7c6e6076d 100644
--- a/src/addons/mod/glossary/pages/entry/entry.ts
+++ b/src/addons/mod/glossary/pages/entry/entry.ts
@@ -12,9 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import { AddonModGlossaryOffline, AddonModGlossaryOfflineEntry } from '@addons/mod/glossary/services/glossary-offline';
import { Component, OnDestroy, OnInit, Optional, ViewChild } from '@angular/core';
import { ActivatedRoute, ActivatedRouteSnapshot } from '@angular/router';
import { CoreRoutedItemsManagerSourcesTracker } from '@classes/items-management/routed-items-manager-sources-tracker';
+import { CoreSwipeNavigationItemsManager } from '@classes/items-management/swipe-navigation-items-manager';
import { CoreSplitViewComponent } from '@components/split-view/split-view';
import { CoreCommentsCommentsComponent } from '@features/comments/components/comments/comments';
import { CoreComments } from '@features/comments/services/comments';
@@ -26,8 +28,7 @@ import { CoreNetwork } from '@services/network';
import { CoreDomUtils, ToastDuration } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { Translate } from '@singletons';
-import { AddonModGlossaryEntriesSource } from '../../classes/glossary-entries-source';
-import { AddonModGlossaryEntriesSwipeManager } from '../../classes/glossary-entries-swipe-manager';
+import { AddonModGlossaryEntriesSource, AddonModGlossaryEntryItem } from '../../classes/glossary-entries-source';
import {
AddonModGlossary,
AddonModGlossaryEntry,
@@ -48,8 +49,9 @@ export class AddonModGlossaryEntryPage implements OnInit, OnDestroy {
component = AddonModGlossaryProvider.COMPONENT;
componentId?: number;
- entry?: AddonModGlossaryEntry;
- entries?: AddonModGlossaryEntryEntriesSwipeManager;
+ onlineEntry?: AddonModGlossaryEntry;
+ offlineEntry?: AddonModGlossaryOfflineEntry;
+ entries!: AddonModGlossaryEntryEntriesSwipeManager;
glossary?: AddonModGlossaryGlossary;
loaded = false;
showAuthor = false;
@@ -59,52 +61,67 @@ export class AddonModGlossaryEntryPage implements OnInit, OnDestroy {
canDelete = false;
commentsEnabled = false;
courseId!: number;
- cmId?: number;
-
- protected entryId!: number;
+ cmId!: number;
constructor(@Optional() protected splitView: CoreSplitViewComponent, protected route: ActivatedRoute) {}
+ get entry(): AddonModGlossaryEntry | AddonModGlossaryOfflineEntry | undefined {
+ return this.onlineEntry ?? this.offlineEntry;
+ }
+
/**
* @inheritdoc
*/
async ngOnInit(): Promise {
+ let onlineEntryId: number | null = null;
+ let offlineEntry: {
+ concept: string;
+ timecreated: number;
+ } | null = null;
try {
- const routeData = this.route.snapshot.data;
this.courseId = CoreNavigator.getRequiredRouteNumberParam('courseId');
- this.entryId = CoreNavigator.getRequiredRouteNumberParam('entryId');
this.tagsEnabled = CoreTag.areTagsAvailableInSite();
this.commentsEnabled = !CoreComments.areCommentsDisabledInSite();
+ this.cmId = CoreNavigator.getRequiredRouteNumberParam('cmId');
- if (routeData.swipeEnabled ?? true) {
- this.cmId = CoreNavigator.getRequiredRouteNumberParam('cmId');
- const source = CoreRoutedItemsManagerSourcesTracker.getOrCreateSource(
- AddonModGlossaryEntriesSource,
- [this.courseId, this.cmId, routeData.glossaryPathPrefix ?? ''],
- );
+ const entrySlug = CoreNavigator.getRequiredRouteParam('entrySlug');
+ const routeData = this.route.snapshot.data;
+ const source = CoreRoutedItemsManagerSourcesTracker.getOrCreateSource(
+ AddonModGlossaryEntriesSource,
+ [this.courseId, this.cmId, routeData.glossaryPathPrefix ?? ''],
+ );
- this.entries = new AddonModGlossaryEntryEntriesSwipeManager(source);
+ this.entries = new AddonModGlossaryEntryEntriesSwipeManager(source);
- await this.entries.start();
+ await this.entries.start();
+
+ if (entrySlug.startsWith('new-')) {
+ offlineEntry = {
+ concept : CoreNavigator.getRequiredRouteParam('concept'),
+ timecreated: Number(entrySlug.slice(4)),
+ };
} else {
- this.cmId = CoreNavigator.getRouteNumberParam('cmId');
+ onlineEntryId = Number(entrySlug);
}
} catch (error) {
CoreDomUtils.showErrorModal(error);
-
CoreNavigator.back();
return;
}
try {
- await this.fetchEntry();
+ if (onlineEntryId) {
+ await this.loadOnlineEntry(onlineEntryId);
- if (!this.glossary || !this.componentId) {
- return;
+ if (!this.glossary || !this.componentId) {
+ return;
+ }
+
+ await CoreUtils.ignoreErrors(AddonModGlossary.logEntryView(onlineEntryId, this.componentId, this.glossary?.name));
+ } else if (offlineEntry) {
+ await this.loadOfflineEntry(offlineEntry.concept, offlineEntry.timecreated);
}
-
- await CoreUtils.ignoreErrors(AddonModGlossary.logEntryView(this.entryId, this.componentId, this.glossary.name));
} finally {
this.loaded = true;
}
@@ -114,14 +131,18 @@ export class AddonModGlossaryEntryPage implements OnInit, OnDestroy {
* @inheritdoc
*/
ngOnDestroy(): void {
- this.entries?.destroy();
+ this.entries.destroy();
}
/**
* Delete entry.
*/
async deleteEntry(): Promise {
- const entryId = this.entry?.id;
+ if (!this.onlineEntry) {
+ return;
+ }
+
+ const entryId = this.onlineEntry.id;
const glossaryId = this.glossary?.id;
const cancelled = await CoreUtils.promiseFails(
CoreDomUtils.showConfirm(Translate.instant('addon.mod_glossary.areyousuredelete')),
@@ -141,7 +162,7 @@ export class AddonModGlossaryEntryPage implements OnInit, OnDestroy {
await CoreUtils.ignoreErrors(AddonModGlossary.invalidateEntriesByCategory(glossaryId));
await CoreUtils.ignoreErrors(AddonModGlossary.invalidateEntriesByDate(glossaryId, 'CREATION'));
await CoreUtils.ignoreErrors(AddonModGlossary.invalidateEntriesByDate(glossaryId, 'UPDATE'));
- await CoreUtils.ignoreErrors(this.entries?.getSource().invalidateCache(false));
+ await CoreUtils.ignoreErrors(this.entries.getSource().invalidateCache(false));
CoreDomUtils.showToast('addon.mod_glossary.entrydeleted', true, ToastDuration.LONG);
@@ -164,67 +185,100 @@ export class AddonModGlossaryEntryPage implements OnInit, OnDestroy {
* @returns Promise resolved when done.
*/
async doRefresh(refresher?: IonRefresher): Promise {
- if (this.glossary?.allowcomments && this.entry && this.entry.id > 0 && this.commentsEnabled && this.comments) {
- // Refresh comments. Don't add it to promises because we don't want the comments fetch to block the entry fetch.
+ if (this.onlineEntry && this.glossary?.allowcomments && this.onlineEntry.id > 0 && this.commentsEnabled && this.comments) {
+ // Refresh comments asynchronously (without blocking the current promise).
CoreUtils.ignoreErrors(this.comments.doRefresh());
}
try {
- await CoreUtils.ignoreErrors(AddonModGlossary.invalidateEntry(this.entryId));
+ if (this.onlineEntry) {
+ await CoreUtils.ignoreErrors(AddonModGlossary.invalidateEntry(this.onlineEntry.id));
+ await this.loadOnlineEntry(this.onlineEntry.id);
+ } else if (this.offlineEntry) {
+ const entrySlug = CoreNavigator.getRequiredRouteParam('entrySlug');
+ const timecreated = Number(entrySlug.slice(4));
- await this.fetchEntry();
+ await this.loadOfflineEntry(timecreated);
+ }
} finally {
refresher?.complete();
}
}
/**
- * Convenience function to get the glossary entry.
- *
- * @returns Promise resolved when done.
+ * Load online entry data.
*/
- protected async fetchEntry(): Promise {
+ protected async loadOnlineEntry(entryId: number): Promise {
try {
- const result = await AddonModGlossary.getEntry(this.entryId);
+ const result = await AddonModGlossary.getEntry(entryId);
const canDeleteEntries = CoreNetwork.isOnline() && await AddonModGlossary.canDeleteEntries();
- this.entry = result.entry;
+ this.onlineEntry = result.entry;
this.ratingInfo = result.ratinginfo;
this.canDelete = canDeleteEntries && !!result.permissions?.candelete;
- if (this.glossary) {
- // Glossary already loaded, nothing else to load.
- return;
- }
-
- // Load the glossary.
- this.glossary = await AddonModGlossary.getGlossaryById(this.courseId, this.entry.glossaryid);
- this.componentId = this.glossary.coursemodule;
-
- switch (this.glossary.displayformat) {
- case 'fullwithauthor':
- case 'encyclopedia':
- this.showAuthor = true;
- this.showDate = true;
- break;
- case 'fullwithoutauthor':
- this.showAuthor = false;
- this.showDate = true;
- break;
- default: // Default, and faq, simple, entrylist, continuous.
- this.showAuthor = false;
- this.showDate = false;
- }
+ await this.loadGlossary();
} catch (error) {
CoreDomUtils.showErrorModalDefault(error, 'addon.mod_glossary.errorloadingentry', true);
}
}
+ /**
+ * Load offline entry data.
+ *
+ * @param concept Entry concept.
+ * @param timecreated Entry Timecreated.
+ */
+ protected async loadOfflineEntry(concept: string, timecreated: number): Promise {
+ try {
+ const glossary = await this.loadGlossary();
+
+ this.offlineEntry = await AddonModGlossaryOffline.getOfflineEntry(glossary.id, concept, timecreated);
+ } catch (error) {
+ CoreDomUtils.showErrorModalDefault(error, 'addon.mod_glossary.errorloadingentry', true);
+ }
+ }
+
+ /**
+ * Load glossary data.
+ *
+ * @returns Glossary.
+ */
+ protected async loadGlossary(): Promise {
+ if (this.glossary) {
+ return this.glossary;
+ }
+
+ this.glossary = await AddonModGlossary.getGlossary(this.courseId, this.cmId);
+ this.componentId = this.glossary.coursemodule;
+
+ switch (this.glossary.displayformat) {
+ case 'fullwithauthor':
+ case 'encyclopedia':
+ this.showAuthor = true;
+ this.showDate = true;
+ break;
+ case 'fullwithoutauthor':
+ this.showAuthor = false;
+ this.showDate = true;
+ break;
+ default: // Default, and faq, simple, entrylist, continuous.
+ this.showAuthor = false;
+ this.showDate = false;
+ }
+
+ return this.glossary;
+ }
+
/**
* Function called when rating is updated online.
*/
ratingUpdated(): void {
- AddonModGlossary.invalidateEntry(this.entryId);
+ if (!this.onlineEntry) {
+ return;
+ }
+
+ AddonModGlossary.invalidateEntry(this.onlineEntry.id);
}
}
@@ -232,13 +286,14 @@ export class AddonModGlossaryEntryPage implements OnInit, OnDestroy {
/**
* Helper to manage swiping within a collection of glossary entries.
*/
-class AddonModGlossaryEntryEntriesSwipeManager extends AddonModGlossaryEntriesSwipeManager {
+class AddonModGlossaryEntryEntriesSwipeManager
+ extends CoreSwipeNavigationItemsManager {
/**
* @inheritdoc
*/
protected getSelectedItemPathFromRoute(route: ActivatedRouteSnapshot): string | null {
- return `${this.getSource().GLOSSARY_PATH_PREFIX}entry/${route.params.entryId}`;
+ return `${this.getSource().GLOSSARY_PATH_PREFIX}entry/${route.params.entrySlug}`;
}
}
diff --git a/src/addons/mod/glossary/services/handlers/edit-link.ts b/src/addons/mod/glossary/services/handlers/edit-link.ts
index 8859a6d72..541a975ed 100644
--- a/src/addons/mod/glossary/services/handlers/edit-link.ts
+++ b/src/addons/mod/glossary/services/handlers/edit-link.ts
@@ -51,14 +51,8 @@ export class AddonModGlossaryEditLinkHandlerService extends CoreContentLinksHand
);
await CoreNavigator.navigateToSitePath(
- AddonModGlossaryModuleHandlerService.PAGE_NAME + '/edit/0',
- {
- params: {
- courseId: module.course,
- cmId: module.id,
- },
- siteId,
- },
+ AddonModGlossaryModuleHandlerService.PAGE_NAME + `/${module.course}/${module.id}/entry/new`,
+ { siteId },
);
} catch (error) {
CoreDomUtils.showErrorModalDefault(error, 'addon.mod_glossary.errorloadingglossary', true);
diff --git a/src/addons/mod/glossary/services/handlers/entry-link.ts b/src/addons/mod/glossary/services/handlers/entry-link.ts
index d58a0bac3..2402b7f53 100644
--- a/src/addons/mod/glossary/services/handlers/entry-link.ts
+++ b/src/addons/mod/glossary/services/handlers/entry-link.ts
@@ -56,14 +56,8 @@ export class AddonModGlossaryEntryLinkHandlerService extends CoreContentLinksHan
);
await CoreNavigator.navigateToSitePath(
- AddonModGlossaryModuleHandlerService.PAGE_NAME + `/entry/${entryId}`,
- {
- params: {
- courseId: module.course,
- cmId: module.id,
- },
- siteId,
- },
+ AddonModGlossaryModuleHandlerService.PAGE_NAME + `/${module.course}/${module.id}/entry/${entryId}`,
+ { siteId },
);
} catch (error) {
CoreDomUtils.showErrorModalDefault(error, 'addon.mod_glossary.errorloadingentry', true);
diff --git a/src/addons/mod/glossary/tests/behat/navigation.feature b/src/addons/mod/glossary/tests/behat/navigation.feature
index 659d286ff..d245ac8da 100644
--- a/src/addons/mod/glossary/tests/behat/navigation.feature
+++ b/src/addons/mod/glossary/tests/behat/navigation.feature
@@ -280,6 +280,7 @@ Feature: Test glossary navigation
| Concept | Tomato |
| Definition | Tomato is a fruit |
And I press "Save" in the app
+ And I press "Add a new entry" in the app
And I set the following fields to these values in the app:
| Concept | Cashew |
| Definition | Cashew is a fruit |