forked from EVOgeek/Vmeda.Online
		
	MOBILE-3643 forum: Migrate offline discussions
This commit is contained in:
		
							parent
							
								
									26f18ac5f4
								
							
						
					
					
						commit
						d41523d4bb
					
				| @ -1,3 +1,17 @@ | |||||||
|  | <!-- Buttons to add to the header. --> | ||||||
|  | <core-navbar-buttons slot="end"> | ||||||
|  |     <core-context-menu> | ||||||
|  |         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" iconAction="open"></core-context-menu-item> | ||||||
|  |         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item> | ||||||
|  |         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item> | ||||||
|  |         <core-context-menu-item *ngIf="discussions.loaded && !(hasOffline || hasOfflineRatings) && isOnline" [priority]="700" [content]="'addon.mod_forum.refreshdiscussions' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item> | ||||||
|  |         <core-context-menu-item *ngIf="discussions.loaded && (hasOffline || hasOfflineRatings) && isOnline"  [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item> | ||||||
|  |         <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item> | ||||||
|  |         <core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.clearstoreddata' | translate:{$a: size}" iconDescription="cube" (action)="removeFiles($event)" iconAction="trash" [closeOnClick]="false"></core-context-menu-item> | ||||||
|  |         <core-context-menu-item *ngIf="sortingAvailable" [priority]="300" [content]="'core.sort' | translate" (action)="showSortOrderSelector()" iconAction="fa-sort"></core-context-menu-item> | ||||||
|  |     </core-context-menu> | ||||||
|  | </core-navbar-buttons> | ||||||
|  | 
 | ||||||
| <!-- Content. --> | <!-- Content. --> | ||||||
| <core-split-view> | <core-split-view> | ||||||
|     <ion-refresher slot="fixed" [disabled]="!discussions.loaded" (ionRefresh)="doRefresh($event)"> |     <ion-refresher slot="fixed" [disabled]="!discussions.loaded" (ionRefresh)="doRefresh($event)"> | ||||||
| @ -27,7 +41,7 @@ | |||||||
|         </ion-card> |         </ion-card> | ||||||
| 
 | 
 | ||||||
|         <ng-container *ngIf="forum"> |         <ng-container *ngIf="forum"> | ||||||
|             <core-empty-box *ngIf="discussions.empty && offlineDiscussions.length == 0" icon="chatbubbles" [message]="'addon.mod_forum.forumnodiscussionsyet' | translate"> |             <core-empty-box *ngIf="discussions.empty" icon="chatbubbles" [message]="'addon.mod_forum.forumnodiscussionsyet' | translate"> | ||||||
|             </core-empty-box> |             </core-empty-box> | ||||||
| 
 | 
 | ||||||
|             <div *ngIf="!discussions.empty && sortingAvailable && selectedSortOrder" class="ion-text-wrap addon-forum-sorting-select"> |             <div *ngIf="!discussions.empty && sortingAvailable && selectedSortOrder" class="ion-text-wrap addon-forum-sorting-select"> | ||||||
| @ -41,39 +55,15 @@ | |||||||
|                 </ion-button> |                 </ion-button> | ||||||
|             </div> |             </div> | ||||||
| 
 | 
 | ||||||
|             <ion-item *ngFor="let discussion of offlineDiscussions" |  | ||||||
|                 class="ion-text-wrap addon-mod-forum-discussion" detail="true" |  | ||||||
|                 [attr.lines="none"]="discussion.groupname" [class.core-selected-item]="discussion.timecreated == -selectedDiscussion" |  | ||||||
|                 (click)="openNewDiscussion(discussion.timecreated)"> |  | ||||||
|                 <ion-label> |  | ||||||
|                     <div class="addon-mod-forum-discussion-title"> |  | ||||||
|                         <h2> |  | ||||||
|                             <core-format-text [text]="discussion.subject" contextLevel="module" [contextInstanceId]="module && module.id" [courseId]="courseId"></core-format-text> |  | ||||||
|                         </h2> |  | ||||||
|                     </div> |  | ||||||
|                     <div class="addon-mod-forum-discussion-info"> |  | ||||||
|                         <core-user-avatar [user]="discussion" slot="start" [courseId]="courseId" *ngIf="discussion.userfullname"> |  | ||||||
|                         </core-user-avatar> |  | ||||||
|                         <div class="addon-mod-forum-discussion-author"> |  | ||||||
|                             <h3 *ngIf="discussion.userfullname">{{discussion.userfullname}}</h3> |  | ||||||
|                             <p *ngIf="discussion.groupname"><ion-icon name="people"></ion-icon> {{ discussion.groupname }}</p> |  | ||||||
|                             <p><ion-icon name="time"></ion-icon> {{ 'core.notsent' | translate }}</p> |  | ||||||
|                         </div> |  | ||||||
|                     </div> |  | ||||||
|                 </ion-label> |  | ||||||
|             </ion-item> |  | ||||||
| 
 |  | ||||||
|             <ion-item *ngFor="let discussion of discussions.items" |             <ion-item *ngFor="let discussion of discussions.items" | ||||||
|                 class="addon-mod-forum-discussion" detail="true" |                 class="addon-mod-forum-discussion" detail="true" | ||||||
|                 [class.core-selected-item]="discussions.isSelected(discussion)" |                 [lines]="discussion.groupname && 'none'" [class.core-selected-item]="discussions.isSelected(discussion)" | ||||||
|                 (click)="discussions.select(discussion)"> |                 (click)="discussions.select(discussion)"> | ||||||
|                 <ion-label> |                 <ion-label> | ||||||
|                     <div class="addon-mod-forum-discussion-title"> |                     <div class="addon-mod-forum-discussion-title"> | ||||||
|                         <h2 class="ion-text-wrap"> |                         <h2 class="ion-text-wrap"> | ||||||
|                             <ion-icon name="fa-map-pin" *ngIf="discussion.pinned"> |                             <ion-icon name="fa-map-pin" *ngIf="discussion.pinned"></ion-icon> | ||||||
|                             </ion-icon> |                             <ion-icon name="fa-star" class="addon-forum-star" *ngIf="!discussion.pinned && discussion.starred"></ion-icon> | ||||||
|                             <ion-icon name="fa-star" class="addon-forum-star" *ngIf="!discussion.pinned && discussion.starred"> |  | ||||||
|                             </ion-icon> |  | ||||||
|                             <core-format-text [text]="discussion.subject" contextLevel="module" [contextInstanceId]="module && module.id" [courseId]="courseId"></core-format-text> |                             <core-format-text [text]="discussion.subject" contextLevel="module" [contextInstanceId]="module && module.id" [courseId]="courseId"></core-format-text> | ||||||
|                         </h2> |                         </h2> | ||||||
|                         <ion-button *ngIf="canPin || discussion.canlock || discussion.canfavourite" |                         <ion-button *ngIf="canPin || discussion.canlock || discussion.canfavourite" | ||||||
| @ -85,15 +75,15 @@ | |||||||
|                         </ion-button> |                         </ion-button> | ||||||
|                     </div> |                     </div> | ||||||
|                     <div class="addon-mod-forum-discussion-info"> |                     <div class="addon-mod-forum-discussion-info"> | ||||||
|                         <core-user-avatar *ngIf="discussion.userfullname" [user]="discussion" slot="start" [courseId]="courseId"> |                         <core-user-avatar *ngIf="discussion.userfullname" [user]="discussion" slot="start" [courseId]="courseId"></core-user-avatar> | ||||||
|                         </core-user-avatar> |  | ||||||
|                         <div class="addon-mod-forum-discussion-author"> |                         <div class="addon-mod-forum-discussion-author"> | ||||||
|                             <h3 *ngIf="discussion.userfullname">{{discussion.userfullname}}</h3> |                             <h3 *ngIf="discussion.userfullname">{{discussion.userfullname}}</h3> | ||||||
|                             <p *ngIf="discussion.groupname"><ion-icon name="people"></ion-icon> {{ discussion.groupname }}</p> |                             <p *ngIf="discussion.groupname"><ion-icon name="people"></ion-icon> {{ discussion.groupname }}</p> | ||||||
|                             <p>{{discussion.created * 1000 | coreFormatDate: "strftimerecentfull"}}</p> |                             <p *ngIf="discussions.isOnlineDiscussion(discussion)">{{discussion.created * 1000 | coreFormatDate: "strftimerecentfull"}}</p> | ||||||
|  |                             <p *ngIf="discussions.isOfflineDiscussion(discussion)"><ion-icon name="time"></ion-icon> {{ 'core.notsent' | translate }}</p> | ||||||
|                         </div> |                         </div> | ||||||
|                     </div> |                     </div> | ||||||
|                     <ion-row class="ion-text-center addon-mod-forum-discussion-more-info"> |                     <ion-row *ngIf="discussions.isOnlineDiscussion(discussion)" class="ion-text-center addon-mod-forum-discussion-more-info"> | ||||||
|                         <ion-col class="ion-text-start"> |                         <ion-col class="ion-text-start"> | ||||||
|                             <ion-note> |                             <ion-note> | ||||||
|                                 <ion-icon name="time"></ion-icon> {{ 'addon.mod_forum.lastpost' | translate }} |                                 <ion-icon name="time"></ion-icon> {{ 'addon.mod_forum.lastpost' | translate }} | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ import { ModalController, PopoverController, Translate } from '@singletons'; | |||||||
| import { CoreCourseContentsPage } from '@features/course/pages/contents/contents'; | import { CoreCourseContentsPage } from '@features/course/pages/contents/contents'; | ||||||
| import { AddonModForumHelper } from '@addons/mod/forum/services/helper.service'; | import { AddonModForumHelper } from '@addons/mod/forum/services/helper.service'; | ||||||
| import { CoreGroups, CoreGroupsProvider } from '@services/groups'; | import { CoreGroups, CoreGroupsProvider } from '@services/groups'; | ||||||
| import { CoreEvents } from '@singletons/events'; | import { CoreEvents, CoreEventObserver } from '@singletons/events'; | ||||||
| import { AddonModForumSyncProvider } from '@addons/mod/forum/services/sync.service'; | import { AddonModForumSyncProvider } from '@addons/mod/forum/services/sync.service'; | ||||||
| import { CoreSites } from '@services/sites'; | import { CoreSites } from '@services/sites'; | ||||||
| import { CoreUser } from '@features/user/services/user'; | import { CoreUser } from '@features/user/services/user'; | ||||||
| @ -40,24 +40,7 @@ import { CoreSplitViewComponent } from '@components/split-view/split-view'; | |||||||
| import { AddonModForumDiscussionOptionsMenuComponent } from '../discussion-options-menu/discussion-options-menu'; | import { AddonModForumDiscussionOptionsMenuComponent } from '../discussion-options-menu/discussion-options-menu'; | ||||||
| import { AddonModForumSortOrderSelectorComponent } from '../sort-order-selector/sort-order-selector'; | import { AddonModForumSortOrderSelectorComponent } from '../sort-order-selector/sort-order-selector'; | ||||||
| import { CoreScreen } from '@services/screen'; | import { CoreScreen } from '@services/screen'; | ||||||
| 
 | import { CoreArray } from '@singletons/array'; | ||||||
| /** |  | ||||||
|  * Type to use for selecting new discussion form in the discussions manager. |  | ||||||
|  */ |  | ||||||
| type NewDiscussionForm = { |  | ||||||
|     newDiscussion: true; |  | ||||||
|     timeCreated: number; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Type guard to infer NewDiscussionForm objects. |  | ||||||
|  * |  | ||||||
|  * @param discussion Object to check. |  | ||||||
|  * @return Whether the object is a new discussion form. |  | ||||||
|  */ |  | ||||||
| function isNewDiscussionForm(discussion: Record<string, unknown>): discussion is NewDiscussionForm { |  | ||||||
|     return 'newDiscussion' in discussion; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Component that displays a forum entry page. |  * Component that displays a forum entry page. | ||||||
| @ -78,8 +61,6 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | |||||||
|     canLoadMore = false; |     canLoadMore = false; | ||||||
|     loadMoreError = false; |     loadMoreError = false; | ||||||
|     discussions: AddonModForumDiscussionsManager; |     discussions: AddonModForumDiscussionsManager; | ||||||
|     offlineDiscussions: AddonModForumOfflineDiscussion[] = []; |  | ||||||
|     selectedDiscussion = 0; // Disucssion ID or negative timecreated if it's an offline discussion.
 |  | ||||||
|     canAddDiscussion = false; |     canAddDiscussion = false; | ||||||
|     addDiscussionText!: string; |     addDiscussionText!: string; | ||||||
|     availabilityMessage: string | null = null; |     availabilityMessage: string | null = null; | ||||||
| @ -93,11 +74,11 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | |||||||
|     protected page = 0; |     protected page = 0; | ||||||
|     trackPosts = false; |     trackPosts = false; | ||||||
|     protected usesGroups = false; |     protected usesGroups = false; | ||||||
|     protected syncManualObserver: any; // It will observe the sync manual event.
 |     protected syncManualObserver?: CoreEventObserver; // It will observe the sync manual event.
 | ||||||
|     protected replyObserver: any; |     protected replyObserver?: CoreEventObserver; | ||||||
|     protected newDiscObserver: any; |     protected newDiscObserver?: CoreEventObserver; | ||||||
|     protected viewDiscObserver: any; |     protected viewDiscObserver?: CoreEventObserver; | ||||||
|     protected changeDiscObserver: any; |     protected changeDiscObserver?: CoreEventObserver; | ||||||
| 
 | 
 | ||||||
|     hasOfflineRatings?: boolean; |     hasOfflineRatings?: boolean; | ||||||
|     protected ratingOfflineObserver: any; |     protected ratingOfflineObserver: any; | ||||||
| @ -141,6 +122,41 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | |||||||
|             AddonModForumProvider.REPLY_DISCUSSION_EVENT, |             AddonModForumProvider.REPLY_DISCUSSION_EVENT, | ||||||
|             this.eventReceived.bind(this, false), |             this.eventReceived.bind(this, false), | ||||||
|         ); |         ); | ||||||
|  |         this.changeDiscObserver = CoreEvents.on(AddonModForumProvider.CHANGE_DISCUSSION_EVENT, (data: any) => { | ||||||
|  |             if ((this.forum && this.forum.id === data.forumId) || data.cmId === this.module!.id) { | ||||||
|  |                 AddonModForum.instance.invalidateDiscussionsList(this.forum!.id).finally(() => { | ||||||
|  |                     if (data.discussionId) { | ||||||
|  |                         // Discussion changed, search it in the list of discussions.
 | ||||||
|  |                         const discussion = this.discussions.items.find( | ||||||
|  |                             (disc) => this.discussions.isOnlineDiscussion(disc) && data.discussionId == disc.discussion, | ||||||
|  |                         ) as AddonModForumDiscussion; | ||||||
|  | 
 | ||||||
|  |                         if (discussion) { | ||||||
|  |                             if (typeof data.locked != 'undefined') { | ||||||
|  |                                 discussion.locked = data.locked; | ||||||
|  |                             } | ||||||
|  |                             if (typeof data.pinned != 'undefined') { | ||||||
|  |                                 discussion.pinned = data.pinned; | ||||||
|  |                             } | ||||||
|  |                             if (typeof data.starred != 'undefined') { | ||||||
|  |                                 discussion.starred = data.starred; | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|  |                             this.showLoadingAndRefresh(false); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     if (typeof data.deleted != 'undefined' && data.deleted) { | ||||||
|  |                         if (data.post.parentid == 0 && CoreScreen.instance.isTablet && !this.discussions.empty) { | ||||||
|  |                             // Discussion deleted, clear details page.
 | ||||||
|  |                             this.discussions.select(this.discussions[0]); | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         this.showLoadingAndRefresh(false); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async ngAfterViewInit(): Promise<void> { |     async ngAfterViewInit(): Promise<void> { | ||||||
| @ -356,7 +372,7 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | |||||||
|         this.hasOffline = !!offlineDiscussions.length; |         this.hasOffline = !!offlineDiscussions.length; | ||||||
| 
 | 
 | ||||||
|         if (!this.hasOffline) { |         if (!this.hasOffline) { | ||||||
|             this.offlineDiscussions = []; |             this.discussions.setOfflineDiscussions([]); | ||||||
| 
 | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| @ -387,7 +403,7 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | |||||||
|         // Sort discussion by time (newer first).
 |         // Sort discussion by time (newer first).
 | ||||||
|         offlineDiscussions.sort((a, b) => b.timecreated - a.timecreated); |         offlineDiscussions.sort((a, b) => b.timecreated - a.timecreated); | ||||||
| 
 | 
 | ||||||
|         this.offlineDiscussions = offlineDiscussions; |         this.discussions.setOfflineDiscussions(offlineDiscussions); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -435,7 +451,12 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         this.discussions.setItems(this.page === 0 ? discussions : this.discussions.items.concat(discussions)); |         if (this.page === 0) { | ||||||
|  |             this.discussions.setOnlineDiscussions(discussions); | ||||||
|  |         } else { | ||||||
|  |             this.discussions.setItems(this.discussions.items.concat(discussions)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         this.canLoadMore = response.canLoadMore; |         this.canLoadMore = response.canLoadMore; | ||||||
|         this.page++; |         this.page++; | ||||||
| 
 | 
 | ||||||
| @ -540,18 +561,20 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | |||||||
|             this.showLoadingAndRefresh(false).finally(() => { |             this.showLoadingAndRefresh(false).finally(() => { | ||||||
|                 // If it's a new discussion in tablet mode, try to open it.
 |                 // If it's a new discussion in tablet mode, try to open it.
 | ||||||
|                 if (isNewDiscussion && CoreScreen.instance.isTablet) { |                 if (isNewDiscussion && CoreScreen.instance.isTablet) { | ||||||
|                     if (data.discussionIds) { |                     const discussion = this.discussions.items.find(disc => { | ||||||
|                         // Discussion sent to server, search it in the list of discussions.
 |                         if (this.discussions.isOfflineDiscussion(disc)) { | ||||||
|                         const discussion = this.discussions.items.find( |                             return disc.timecreated === data.discTimecreated; | ||||||
|                             (disc) => |                         } | ||||||
|                                 !isNewDiscussionForm(disc) && |  | ||||||
|                                 data.discussionIds.indexOf(disc.discussion) >= 0, |  | ||||||
|                         ); |  | ||||||
| 
 | 
 | ||||||
|  |                         if (this.discussions.isOnlineDiscussion(disc)) { | ||||||
|  |                             return CoreArray.contains(data.discussionIds, disc.discussion); | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         return false; | ||||||
|  |                     }); | ||||||
|  | 
 | ||||||
|  |                     if (discussion || !this.discussions.empty) { | ||||||
|                         this.discussions.select(discussion ?? this.discussions.items[0]); |                         this.discussions.select(discussion ?? this.discussions.items[0]); | ||||||
|                     } else if (data.discTimecreated) { |  | ||||||
|                         // It's an offline discussion, open it.
 |  | ||||||
|                         this.openNewDiscussion(data.discTimecreated); |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             }); |             }); | ||||||
| @ -566,11 +589,8 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | |||||||
|      * |      * | ||||||
|      * @param timeCreated Creation time of the offline discussion. |      * @param timeCreated Creation time of the offline discussion. | ||||||
|      */ |      */ | ||||||
|     openNewDiscussion(timeCreated: number = 0): void { |     openNewDiscussion(): void { | ||||||
|         this.discussions.select({ |         this.discussions.select({ newDiscussion: true }); | ||||||
|             newDiscussion: true, |  | ||||||
|             timeCreated, |  | ||||||
|         }); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -650,7 +670,20 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom | |||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class AddonModForumDiscussionsManager extends CorePageItemsListManager<AddonModForumDiscussion | NewDiscussionForm> { | /** | ||||||
|  |  * Type to select the new discussion form. | ||||||
|  |  */ | ||||||
|  | type NewDiscussionForm = { newDiscussion: true }; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Type of items that can be held by the discussions manager. | ||||||
|  |  */ | ||||||
|  | type DiscussionItem = AddonModForumDiscussion | AddonModForumOfflineDiscussion | NewDiscussionForm; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Discussions manager. | ||||||
|  |  */ | ||||||
|  | class AddonModForumDiscussionsManager extends CorePageItemsListManager<DiscussionItem> { | ||||||
| 
 | 
 | ||||||
|     private discussionsPathPrefix: string; |     private discussionsPathPrefix: string; | ||||||
|     private component: AddonModForumIndexComponent; |     private component: AddonModForumIndexComponent; | ||||||
| @ -662,29 +695,107 @@ class AddonModForumDiscussionsManager extends CorePageItemsListManager<AddonModF | |||||||
|         this.discussionsPathPrefix = discussionsPathPrefix; |         this.discussionsPathPrefix = discussionsPathPrefix; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     getItemQueryParams(discussion: AddonModForumDiscussion | NewDiscussionForm): Params { |     get onlineDiscussions(): AddonModForumDiscussion[] { | ||||||
|  |         return this.items.filter(discussion => this.isOnlineDiscussion(discussion)) as AddonModForumDiscussion[]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @inheritdoc | ||||||
|  |      */ | ||||||
|  |     getItemQueryParams(discussion: DiscussionItem): Params { | ||||||
|         return { |         return { | ||||||
|             courseId: this.component.courseId, |             courseId: this.component.courseId, | ||||||
|             cmId: this.component.module!.id, |             cmId: this.component.module!.id, | ||||||
|             forumId: this.component.forum!.id, |             forumId: this.component.forum!.id, | ||||||
|             ...( |             ...(this.isOnlineDiscussion(discussion) ? { discussion, trackPosts: this.component.trackPosts } : {}), | ||||||
|                 isNewDiscussionForm(discussion) |  | ||||||
|                     ? { timeCreated: discussion.timeCreated } |  | ||||||
|                     : { discussion, trackPosts: this.component.trackPosts } |  | ||||||
|             ), |  | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected getItemPath(discussion: AddonModForumDiscussion | NewDiscussionForm): string { |     /** | ||||||
|         const discussionId = isNewDiscussionForm(discussion) ? 'new' : discussion.id; |      * Type guard to infer NewDiscussionForm objects. | ||||||
| 
 |      * | ||||||
|         return this.discussionsPathPrefix + discussionId; |      * @param discussion Item to check. | ||||||
|  |      * @return Whether the item is a new discussion form. | ||||||
|  |      */ | ||||||
|  |     isNewDiscussionForm(discussion: DiscussionItem): discussion is NewDiscussionForm { | ||||||
|  |         return 'newDiscussion' in discussion; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected getSelectedItemPath(route: ActivatedRouteSnapshot): string | null { |     /** | ||||||
|         const discussionId = route.params.discussionId; |      * Type guard to infer AddonModForumDiscussion objects. | ||||||
|  |      * | ||||||
|  |      * @param discussion Item to check. | ||||||
|  |      * @return Whether the item is an online discussion. | ||||||
|  |      */ | ||||||
|  |     isOfflineDiscussion(discussion: DiscussionItem): discussion is AddonModForumOfflineDiscussion { | ||||||
|  |         return !this.isNewDiscussionForm(discussion) | ||||||
|  |             && !this.isOnlineDiscussion(discussion); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|         return discussionId ? this.discussionsPathPrefix + discussionId : null; |     /** | ||||||
|  |      * Type guard to infer AddonModForumDiscussion objects. | ||||||
|  |      * | ||||||
|  |      * @param discussion Item to check. | ||||||
|  |      * @return Whether the item is an online discussion. | ||||||
|  |      */ | ||||||
|  |     isOnlineDiscussion(discussion: DiscussionItem): discussion is AddonModForumDiscussion { | ||||||
|  |         return 'id' in discussion; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Update online discussion items. | ||||||
|  |      * | ||||||
|  |      * @param onlineDiscussions Online discussions | ||||||
|  |      */ | ||||||
|  |     setOnlineDiscussions(onlineDiscussions: AddonModForumDiscussion[]): void { | ||||||
|  |         const otherDiscussions = this.items.filter(discussion => !this.isOnlineDiscussion(discussion)); | ||||||
|  | 
 | ||||||
|  |         this.setItems(otherDiscussions.concat(onlineDiscussions)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Update offline discussion items. | ||||||
|  |      * | ||||||
|  |      * @param offlineDiscussions Offline discussions | ||||||
|  |      */ | ||||||
|  |     setOfflineDiscussions(offlineDiscussions: AddonModForumOfflineDiscussion[]): void { | ||||||
|  |         const otherDiscussions = this.items.filter(discussion => !this.isOfflineDiscussion(discussion)); | ||||||
|  | 
 | ||||||
|  |         this.setItems((offlineDiscussions as DiscussionItem[]).concat(otherDiscussions)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @inheritdoc | ||||||
|  |      */ | ||||||
|  |     protected getItemPath(discussion: DiscussionItem): string { | ||||||
|  |         const getRelativePath = () => { | ||||||
|  |             if (this.isOnlineDiscussion(discussion)) { | ||||||
|  |                 return discussion.id; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (this.isOfflineDiscussion(discussion)) { | ||||||
|  |                 return `new/${discussion.timecreated}`; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return 'new/0'; | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         return this.discussionsPathPrefix + getRelativePath(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @inheritdoc | ||||||
|  |      */ | ||||||
|  |     protected getSelectedItemPath(route: ActivatedRouteSnapshot): string | null { | ||||||
|  |         if (route.params.discussionId) { | ||||||
|  |             return this.discussionsPathPrefix + route.params.discussionId; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (route.params.timeCreated) { | ||||||
|  |             return this.discussionsPathPrefix + `new/${route.params.timeCreated}`; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ const mobileRoutes: Routes = [ | |||||||
|         component: AddonModForumIndexPage, |         component: AddonModForumIndexPage, | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         path: ':courseId/:cmId/new', |         path: ':courseId/:cmId/new/:timeCreated', | ||||||
|         loadChildren: () => import('./pages/new-discussion/new-discussion.module').then(m => m.AddonForumNewDiscussionPageModule), |         loadChildren: () => import('./pages/new-discussion/new-discussion.module').then(m => m.AddonForumNewDiscussionPageModule), | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
| @ -43,7 +43,7 @@ const tabletRoutes: Routes = [ | |||||||
|         component: AddonModForumIndexPage, |         component: AddonModForumIndexPage, | ||||||
|         children: [ |         children: [ | ||||||
|             { |             { | ||||||
|                 path: 'new', |                 path: 'new/:timeCreated', | ||||||
|                 loadChildren: () => import('./pages/new-discussion/new-discussion.module') |                 loadChildren: () => import('./pages/new-discussion/new-discussion.module') | ||||||
|                     .then(m => m.AddonForumNewDiscussionPageModule), |                     .then(m => m.AddonForumNewDiscussionPageModule), | ||||||
|             }, |             }, | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ const mainMenuRoutes: Routes = [ | |||||||
|     ...conditionalRoutes( |     ...conditionalRoutes( | ||||||
|         [ |         [ | ||||||
|             { |             { | ||||||
|                 path: 'course/index/contents/mod_forum/new', |                 path: 'course/index/contents/mod_forum/new/:timeCreated', | ||||||
|                 loadChildren: () => import('./pages/new-discussion/new-discussion.module') |                 loadChildren: () => import('./pages/new-discussion/new-discussion.module') | ||||||
|                     .then(m => m.AddonForumNewDiscussionPageModule), |                     .then(m => m.AddonForumNewDiscussionPageModule), | ||||||
|             }, |             }, | ||||||
| @ -50,7 +50,7 @@ const mainMenuRoutes: Routes = [ | |||||||
| const courseContentsRoutes: Routes = conditionalRoutes( | const courseContentsRoutes: Routes = conditionalRoutes( | ||||||
|     [ |     [ | ||||||
|         { |         { | ||||||
|             path: 'mod_forum/new', |             path: 'mod_forum/new/:timeCreated', | ||||||
|             loadChildren: () => import('./pages/new-discussion/new-discussion.module') |             loadChildren: () => import('./pages/new-discussion/new-discussion.module') | ||||||
|                 .then(m => m.AddonForumNewDiscussionPageModule), |                 .then(m => m.AddonForumNewDiscussionPageModule), | ||||||
|         }, |         }, | ||||||
|  | |||||||
| @ -12,7 +12,7 @@ | |||||||
| // See the License for the specific language governing permissions and
 | // See the License for the specific language governing permissions and
 | ||||||
| // limitations under the License.
 | // limitations under the License.
 | ||||||
| 
 | 
 | ||||||
| import { ActivatedRouteSnapshot, Params } from '@angular/router'; | import { ActivatedRoute, ActivatedRouteSnapshot, Params } from '@angular/router'; | ||||||
| import { Subscription } from 'rxjs'; | import { Subscription } from 'rxjs'; | ||||||
| 
 | 
 | ||||||
| import { CoreSplitViewComponent } from '@components/split-view/split-view'; | import { CoreSplitViewComponent } from '@components/split-view/split-view'; | ||||||
| @ -135,17 +135,19 @@ export abstract class CorePageItemsListManager<Item> { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // If this item is already selected, do nothing.
 |         // If this item is already selected, do nothing.
 | ||||||
|  |         const itemRoute = this.getItemRoute(route); | ||||||
|         const itemPath = this.getItemPath(item); |         const itemPath = this.getItemPath(item); | ||||||
|  |         const selectedItemPath = itemRoute ? this.getSelectedItemPath(itemRoute.snapshot) : null; | ||||||
| 
 | 
 | ||||||
|         if (route.firstChild?.routeConfig?.path === itemPath) { |         if (selectedItemPath === itemPath) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Navigate to item.
 |         // Navigate to item.
 | ||||||
|         const params = this.getItemQueryParams(item); |         const params = this.getItemQueryParams(item); | ||||||
|         const pathPrefix = route.firstChild ? itemPath.split('/').fill('../').join('') : ''; |         const pathPrefix = selectedItemPath ? selectedItemPath.split('/').fill('../').join('') : ''; | ||||||
| 
 | 
 | ||||||
|         await CoreNavigator.instance.navigate(pathPrefix + itemPath, { params }); |         await CoreNavigator.instance.navigate(pathPrefix + itemPath, { params, reset: true }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -220,4 +222,20 @@ export abstract class CorePageItemsListManager<Item> { | |||||||
|      */ |      */ | ||||||
|     protected abstract getSelectedItemPath(route: ActivatedRouteSnapshot): string | null; |     protected abstract getSelectedItemPath(route: ActivatedRouteSnapshot): string | null; | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Get the active item route, if any. | ||||||
|  |      * | ||||||
|  |      * @param pageRoute Page route. | ||||||
|  |      * @return Item route. | ||||||
|  |      */ | ||||||
|  |     private getItemRoute(pageRoute: ActivatedRoute): ActivatedRoute | null { | ||||||
|  |         let itemRoute = pageRoute.firstChild; | ||||||
|  | 
 | ||||||
|  |         while (itemRoute && !itemRoute.component) { | ||||||
|  |             itemRoute = itemRoute.firstChild; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return itemRoute; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user