forked from CIT/Vmeda.Online
		
	MOBILE-3643 forum: Migrate single activity view
This commit is contained in:
		
							parent
							
								
									2dd0aa4815
								
							
						
					
					
						commit
						e450659697
					
				@ -1,127 +1,124 @@
 | 
			
		||||
<!-- Content. -->
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <core-split-view>
 | 
			
		||||
        <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="doRefresh($event)">
 | 
			
		||||
            <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
			
		||||
        </ion-refresher>
 | 
			
		||||
<core-split-view>
 | 
			
		||||
    <ion-refresher slot="fixed" [disabled]="!discussions.loaded" (ionRefresh)="doRefresh($event)">
 | 
			
		||||
        <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
			
		||||
    </ion-refresher>
 | 
			
		||||
 | 
			
		||||
        <core-loading [hideUntil]="loaded" class="core-loading-center">
 | 
			
		||||
            <core-course-module-description *ngIf="forum && forum.type != 'single'"
 | 
			
		||||
                [description]="description" [component]="component" [componentId]="componentId" [note]="descriptionNote"
 | 
			
		||||
                contextLevel="module" [contextInstanceId]="module && module.id" [courseId]="courseId">
 | 
			
		||||
            </core-course-module-description>
 | 
			
		||||
    <core-loading [hideUntil]="discussions.loaded" class="core-loading-center">
 | 
			
		||||
        <core-course-module-description *ngIf="forum && forum.type != 'single'"
 | 
			
		||||
            [description]="description" [component]="component" [componentId]="componentId" [note]="descriptionNote"
 | 
			
		||||
            contextLevel="module" [contextInstanceId]="module && module.id" [courseId]="courseId">
 | 
			
		||||
        </core-course-module-description>
 | 
			
		||||
 | 
			
		||||
            <!-- Forum discussions found to be synchronized -->
 | 
			
		||||
            <ion-card class="core-warning-card" *ngIf="hasOffline || hasOfflineRatings">
 | 
			
		||||
                <ion-item>
 | 
			
		||||
                    <ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon>
 | 
			
		||||
                    <ion-label>{{ 'core.hasdatatosync' | translate:{$a: moduleName} }}</ion-label>
 | 
			
		||||
                </ion-item>
 | 
			
		||||
            </ion-card>
 | 
			
		||||
        <!-- Forum discussions found to be synchronized -->
 | 
			
		||||
        <ion-card class="core-warning-card" *ngIf="hasOffline || hasOfflineRatings">
 | 
			
		||||
            <ion-item>
 | 
			
		||||
                <ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon>
 | 
			
		||||
                <ion-label>{{ 'core.hasdatatosync' | translate:{$a: moduleName} }}</ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
        </ion-card>
 | 
			
		||||
 | 
			
		||||
            <!-- Cut-off date or due date message -->
 | 
			
		||||
            <ion-card class="core-info-card" *ngIf="availabilityMessage">
 | 
			
		||||
                <ion-item>
 | 
			
		||||
                    <ion-icon name="fas-info-circle" slot="start"></ion-icon>
 | 
			
		||||
                    <ion-label>{{ availabilityMessage }}</ion-label>
 | 
			
		||||
                </ion-item>
 | 
			
		||||
            </ion-card>
 | 
			
		||||
        <!-- Cut-off date or due date message -->
 | 
			
		||||
        <ion-card class="core-info-card" *ngIf="availabilityMessage">
 | 
			
		||||
            <ion-item>
 | 
			
		||||
                <ion-icon name="fas-info-circle" slot="start"></ion-icon>
 | 
			
		||||
                <ion-label>{{ availabilityMessage }}</ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
        </ion-card>
 | 
			
		||||
 | 
			
		||||
            <ng-container *ngIf="forum">
 | 
			
		||||
                <core-empty-box *ngIf="discussions.length == 0 && offlineDiscussions.length == 0" icon="chatbubbles" [message]="'addon.mod_forum.forumnodiscussionsyet' | translate">
 | 
			
		||||
                </core-empty-box>
 | 
			
		||||
        <ng-container *ngIf="forum">
 | 
			
		||||
            <core-empty-box *ngIf="discussions.empty && offlineDiscussions.length == 0" icon="chatbubbles" [message]="'addon.mod_forum.forumnodiscussionsyet' | translate">
 | 
			
		||||
            </core-empty-box>
 | 
			
		||||
 | 
			
		||||
                <div *ngIf="discussions.length > 0 && sortingAvailable && selectedSortOrder" class="ion-text-wrap addon-forum-sorting-select">
 | 
			
		||||
                    <ion-button *ngIf="sortingAvailable" id="addon-mod-forum-sort-order-button"
 | 
			
		||||
                        class="core-button-select button-no-uppercase"
 | 
			
		||||
                        aria-haspopup="true" aria-controls="addon-mod-forum-sort-order-selector"
 | 
			
		||||
                        [attr.aria-label]="('core.sort' | translate)" [attr.aria-expanded]="sortOrderSelectorExpanded"
 | 
			
		||||
                        (click)="showSortOrderSelector($event)">
 | 
			
		||||
                        <span class="core-button-select-text">{{ selectedSortOrder.label | translate }}</span>
 | 
			
		||||
                        <div class="select-icon" slot="end"><div class="select-icon-inner"></div></div>
 | 
			
		||||
                    </ion-button>
 | 
			
		||||
                </div>
 | 
			
		||||
            <div *ngIf="!discussions.empty && sortingAvailable && selectedSortOrder" class="ion-text-wrap addon-forum-sorting-select">
 | 
			
		||||
                <ion-button *ngIf="sortingAvailable" id="addon-mod-forum-sort-order-button"
 | 
			
		||||
                    class="core-button-select button-no-uppercase"
 | 
			
		||||
                    aria-haspopup="true" aria-controls="addon-mod-forum-sort-order-selector"
 | 
			
		||||
                    [attr.aria-label]="('core.sort' | translate)" [attr.aria-expanded]="sortOrderSelectorExpanded"
 | 
			
		||||
                    (click)="showSortOrderSelector($event)">
 | 
			
		||||
                    <span class="core-button-select-text">{{ selectedSortOrder.label | translate }}</span>
 | 
			
		||||
                    <div class="select-icon" slot="end"><div class="select-icon-inner"></div></div>
 | 
			
		||||
                </ion-button>
 | 
			
		||||
            </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-item-selected]="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>
 | 
			
		||||
            <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 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>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
 | 
			
		||||
                <ion-item *ngFor="let discussion of discussions"
 | 
			
		||||
                    class="addon-mod-forum-discussion" detail="true"
 | 
			
		||||
                    [class.core-split-item-selected]="discussion.discussion == selectedDiscussion"
 | 
			
		||||
                    (click)="openDiscussion(discussion)">
 | 
			
		||||
                    <ion-label>
 | 
			
		||||
                        <div class="addon-mod-forum-discussion-title">
 | 
			
		||||
                            <h2 class="ion-text-wrap">
 | 
			
		||||
                                <ion-icon name="fa-map-pin" *ngIf="discussion.pinned">
 | 
			
		||||
                                </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>
 | 
			
		||||
                            </h2>
 | 
			
		||||
                            <ion-button *ngIf="canPin || discussion.canlock || discussion.canfavourite"
 | 
			
		||||
                                fill="clear" color="dark"
 | 
			
		||||
                                [attr.aria-label]="('core.displayoptions' | translate)"
 | 
			
		||||
                                (click)="showOptionsMenu($event, discussion)">
 | 
			
		||||
                                <ion-icon name="more" slot="icon-only">
 | 
			
		||||
                                </ion-icon>
 | 
			
		||||
                            </ion-button>
 | 
			
		||||
            <ion-item *ngFor="let discussion of discussions.items"
 | 
			
		||||
                class="addon-mod-forum-discussion" detail="true"
 | 
			
		||||
                [class.core-selected-item]="discussions.isSelected(discussion)"
 | 
			
		||||
                (click)="discussions.select(discussion)">
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <div class="addon-mod-forum-discussion-title">
 | 
			
		||||
                        <h2 class="ion-text-wrap">
 | 
			
		||||
                            <ion-icon name="fa-map-pin" *ngIf="discussion.pinned">
 | 
			
		||||
                            </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>
 | 
			
		||||
                        </h2>
 | 
			
		||||
                        <ion-button *ngIf="canPin || discussion.canlock || discussion.canfavourite"
 | 
			
		||||
                            fill="clear" color="dark"
 | 
			
		||||
                            [attr.aria-label]="('core.displayoptions' | translate)"
 | 
			
		||||
                            (click)="showOptionsMenu($event, discussion)">
 | 
			
		||||
                            <ion-icon name="more" slot="icon-only">
 | 
			
		||||
                            </ion-icon>
 | 
			
		||||
                        </ion-button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="addon-mod-forum-discussion-info">
 | 
			
		||||
                        <core-user-avatar *ngIf="discussion.userfullname" [user]="discussion" slot="start" [courseId]="courseId">
 | 
			
		||||
                        </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>{{discussion.created * 1000 | coreFormatDate: "strftimerecentfull"}}</p>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="addon-mod-forum-discussion-info">
 | 
			
		||||
                            <core-user-avatar *ngIf="discussion.userfullname" [user]="discussion" slot="start" [courseId]="courseId">
 | 
			
		||||
                            </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>{{discussion.created * 1000 | coreFormatDate: "strftimerecentfull"}}</p>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <ion-row class="ion-text-center addon-mod-forum-discussion-more-info">
 | 
			
		||||
                            <ion-col class="ion-text-start">
 | 
			
		||||
                                <ion-note>
 | 
			
		||||
                                    <ion-icon name="time"></ion-icon> {{ 'addon.mod_forum.lastpost' | translate }}
 | 
			
		||||
                                    <ng-container *ngIf="discussion.timemodified > discussion.created">{{discussion.timemodified | coreTimeAgo}}</ng-container>
 | 
			
		||||
                                    <ng-container *ngIf="discussion.timemodified <= discussion.created">{{discussion.created | coreTimeAgo}}</ng-container>
 | 
			
		||||
                                </ion-note>
 | 
			
		||||
                            </ion-col>
 | 
			
		||||
                            <ion-col class="ion-text-end">
 | 
			
		||||
                                <ion-note>
 | 
			
		||||
                                    <ion-icon name="fas-comments"></ion-icon> {{ 'addon.mod_forum.numreplies' | translate:{numreplies: discussion.numreplies} }}
 | 
			
		||||
                                    <ion-badge *ngIf="discussion.numunread" class="ion-text-center"
 | 
			
		||||
                                        [attr.aria-label]="'addon.mod_forum.unreadpostsnumber' | translate:{ '$a' : discussion.numunread}">
 | 
			
		||||
                                        {{ discussion.numunread }}
 | 
			
		||||
                                    </ion-badge>
 | 
			
		||||
                                </ion-note>
 | 
			
		||||
                            </ion-col>
 | 
			
		||||
                        </ion-row>
 | 
			
		||||
                    </ion-label>
 | 
			
		||||
                </ion-item>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <ion-row class="ion-text-center addon-mod-forum-discussion-more-info">
 | 
			
		||||
                        <ion-col class="ion-text-start">
 | 
			
		||||
                            <ion-note>
 | 
			
		||||
                                <ion-icon name="time"></ion-icon> {{ 'addon.mod_forum.lastpost' | translate }}
 | 
			
		||||
                                <ng-container *ngIf="discussion.timemodified > discussion.created">{{discussion.timemodified | coreTimeAgo}}</ng-container>
 | 
			
		||||
                                <ng-container *ngIf="discussion.timemodified <= discussion.created">{{discussion.created | coreTimeAgo}}</ng-container>
 | 
			
		||||
                            </ion-note>
 | 
			
		||||
                        </ion-col>
 | 
			
		||||
                        <ion-col class="ion-text-end">
 | 
			
		||||
                            <ion-note>
 | 
			
		||||
                                <ion-icon name="fas-comments"></ion-icon> {{ 'addon.mod_forum.numreplies' | translate:{numreplies: discussion.numreplies} }}
 | 
			
		||||
                                <ion-badge *ngIf="discussion.numunread" class="ion-text-center"
 | 
			
		||||
                                    [attr.aria-label]="'addon.mod_forum.unreadpostsnumber' | translate:{ '$a' : discussion.numunread}">
 | 
			
		||||
                                    {{ discussion.numunread }}
 | 
			
		||||
                                </ion-badge>
 | 
			
		||||
                            </ion-note>
 | 
			
		||||
                        </ion-col>
 | 
			
		||||
                    </ion-row>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
        </ng-container>
 | 
			
		||||
    </core-loading>
 | 
			
		||||
 | 
			
		||||
            </ng-container>
 | 
			
		||||
        </core-loading>
 | 
			
		||||
 | 
			
		||||
        <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="forum && canAddDiscussion">
 | 
			
		||||
            <ion-fab-button (click)="openNewDiscussion()" [attr.aria-label]="addDiscussionText">
 | 
			
		||||
                <ion-icon name="add"></ion-icon>
 | 
			
		||||
            </ion-fab-button>
 | 
			
		||||
        </ion-fab>
 | 
			
		||||
    </core-split-view>
 | 
			
		||||
</ion-content>
 | 
			
		||||
    <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="forum && canAddDiscussion">
 | 
			
		||||
        <ion-fab-button (click)="openNewDiscussion()" [attr.aria-label]="addDiscussionText">
 | 
			
		||||
            <ion-icon name="add"></ion-icon>
 | 
			
		||||
        </ion-fab-button>
 | 
			
		||||
    </ion-fab>
 | 
			
		||||
</core-split-view>
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,8 @@
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { Component, Optional, OnInit, OnDestroy } from '@angular/core';
 | 
			
		||||
import { Component, Optional, OnInit, OnDestroy, ViewChild, AfterViewInit } from '@angular/core';
 | 
			
		||||
import { ActivatedRoute, ActivatedRouteSnapshot, Params } from '@angular/router';
 | 
			
		||||
import { IonContent } from '@ionic/angular';
 | 
			
		||||
import { CoreCourseModuleMainActivityComponent } from '@features/course/classes/main-activity-component';
 | 
			
		||||
import {
 | 
			
		||||
@ -34,6 +35,8 @@ import { CoreUser } from '@features/user/services/user';
 | 
			
		||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { CoreCourse } from '@features/course/services/course';
 | 
			
		||||
import { CorePageItemsListManager } from '@classes/page-items-list-manager';
 | 
			
		||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component that displays a forum entry page.
 | 
			
		||||
@ -43,32 +46,32 @@ import { CoreCourse } from '@features/course/services/course';
 | 
			
		||||
    templateUrl: 'index.html',
 | 
			
		||||
    styleUrls: ['index.scss'],
 | 
			
		||||
})
 | 
			
		||||
export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityComponent implements OnInit, OnDestroy {
 | 
			
		||||
export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
    @ViewChild(CoreSplitViewComponent) splitView!: CoreSplitViewComponent;
 | 
			
		||||
 | 
			
		||||
    component = AddonModForumProvider.COMPONENT;
 | 
			
		||||
    moduleName = 'forum';
 | 
			
		||||
 | 
			
		||||
    descriptionNote?: string;
 | 
			
		||||
    forum?: AddonModForumData;
 | 
			
		||||
    canLoadMore = false;
 | 
			
		||||
    loadMoreError = false;
 | 
			
		||||
    discussions: AddonModForumDiscussion[] = [];
 | 
			
		||||
    discussions: AddonModForumDiscussionsManager;
 | 
			
		||||
    offlineDiscussions: AddonModForumOfflineDiscussion[] = [];
 | 
			
		||||
    selectedDiscussion = 0; // Disucssion ID or negative timecreated if it's an offline discussion.
 | 
			
		||||
    canAddDiscussion = false;
 | 
			
		||||
    addDiscussionText!: string;
 | 
			
		||||
    availabilityMessage: string | null = null;
 | 
			
		||||
 | 
			
		||||
    sortingAvailable!: boolean;
 | 
			
		||||
    sortOrders: AddonModForumSortOrder[] = [];
 | 
			
		||||
    selectedSortOrder: AddonModForumSortOrder | null = null;
 | 
			
		||||
    sortOrderSelectorExpanded = false;
 | 
			
		||||
    canPin = false;
 | 
			
		||||
 | 
			
		||||
    protected syncEventName = AddonModForumSyncProvider.AUTO_SYNCED;
 | 
			
		||||
    protected page = 0;
 | 
			
		||||
    protected trackPosts = false;
 | 
			
		||||
    trackPosts = false;
 | 
			
		||||
    protected usesGroups = false;
 | 
			
		||||
    protected canPin = false;
 | 
			
		||||
    protected syncManualObserver: any; // It will observe the sync manual event.
 | 
			
		||||
    protected replyObserver: any;
 | 
			
		||||
    protected newDiscObserver: any;
 | 
			
		||||
@ -80,10 +83,17 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
 | 
			
		||||
    protected ratingSyncObserver: any;
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        route: ActivatedRoute,
 | 
			
		||||
        @Optional() protected content?: IonContent,
 | 
			
		||||
        @Optional() courseContentsPage?: CoreCourseContentsPage,
 | 
			
		||||
    ) {
 | 
			
		||||
        super('AddonModForumIndexComponent', content, courseContentsPage);
 | 
			
		||||
 | 
			
		||||
        this.discussions = new AddonModForumDiscussionsManager(
 | 
			
		||||
            route.component,
 | 
			
		||||
            this,
 | 
			
		||||
            courseContentsPage ? 'mod_forum/' : '',
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -95,6 +105,9 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
 | 
			
		||||
        this.sortOrders = AddonModForum.instance.getAvailableSortOrders();
 | 
			
		||||
 | 
			
		||||
        await super.ngOnInit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async ngAfterViewInit(): Promise<void> {
 | 
			
		||||
        await this.loadContent(false, true);
 | 
			
		||||
 | 
			
		||||
        if (!this.forum) {
 | 
			
		||||
@ -110,6 +123,8 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
 | 
			
		||||
                    return;
 | 
			
		||||
                }),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        this.discussions.start(this.splitView);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -389,10 +404,7 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.discussions = this.page === 0
 | 
			
		||||
            ? discussions
 | 
			
		||||
            : this.discussions.concat(discussions);
 | 
			
		||||
 | 
			
		||||
        this.discussions.setItems(this.page === 0 ? discussions : this.discussions.items.concat(discussions));
 | 
			
		||||
        this.canLoadMore = response.canLoadMore;
 | 
			
		||||
        this.page++;
 | 
			
		||||
 | 
			
		||||
@ -486,24 +498,6 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
 | 
			
		||||
        return result.updated;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens a discussion.
 | 
			
		||||
     *
 | 
			
		||||
     * @param discussion Discussion object.
 | 
			
		||||
     */
 | 
			
		||||
    openDiscussion(discussion: AddonModForumDiscussion): void {
 | 
			
		||||
        alert(`Open discussion ${discussion.id}: Not implemented!`);
 | 
			
		||||
 | 
			
		||||
        // @todo
 | 
			
		||||
        // const params = {
 | 
			
		||||
        //     courseId: this.courseId,
 | 
			
		||||
        //     cmId: this.module.id,
 | 
			
		||||
        //     forumId: this.forum.id,
 | 
			
		||||
        //     discussion: discussion,
 | 
			
		||||
        //     trackPosts: this.trackPosts,
 | 
			
		||||
        // };
 | 
			
		||||
        // this.splitviewCtrl.push('AddonModForumDiscussionPage', params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Opens the new discussion form.
 | 
			
		||||
@ -560,4 +554,80 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
 | 
			
		||||
        // this.sortOrderSelectorExpanded = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show the context menu.
 | 
			
		||||
     *
 | 
			
		||||
     * @param e Click Event.
 | 
			
		||||
     */
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | 
			
		||||
    showOptionsMenu(e: Event, discussion: any): void {
 | 
			
		||||
        alert('Show options menu not implemented');
 | 
			
		||||
 | 
			
		||||
        // @todo
 | 
			
		||||
        // e.preventDefault();
 | 
			
		||||
        // e.stopPropagation();
 | 
			
		||||
 | 
			
		||||
        // const popover = this.popoverCtrl.create(AddonForumDiscussionOptionsMenuComponent, {
 | 
			
		||||
        //     discussion: discussion,
 | 
			
		||||
        //     forumId: this.forum.id,
 | 
			
		||||
        //     cmId: this.module.id,
 | 
			
		||||
        // });
 | 
			
		||||
        // popover.onDidDismiss((data) => {
 | 
			
		||||
        //     if (data && data.action) {
 | 
			
		||||
        //         switch (data.action) {
 | 
			
		||||
        //             case 'lock':
 | 
			
		||||
        //                 discussion.locked = data.value;
 | 
			
		||||
        //                 break;
 | 
			
		||||
        //             case 'pin':
 | 
			
		||||
        //                 discussion.pinned = data.value;
 | 
			
		||||
        //                 break;
 | 
			
		||||
        //             case 'star':
 | 
			
		||||
        //                 discussion.starred = data.value;
 | 
			
		||||
        //                 break;
 | 
			
		||||
        //             default:
 | 
			
		||||
        //                 break;
 | 
			
		||||
        //         }
 | 
			
		||||
        //     }
 | 
			
		||||
        // });
 | 
			
		||||
        // popover.present({
 | 
			
		||||
        //     ev: e,
 | 
			
		||||
        // });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class AddonModForumDiscussionsManager extends CorePageItemsListManager<AddonModForumDiscussion> {
 | 
			
		||||
 | 
			
		||||
    private discussionsPathPrefix: string;
 | 
			
		||||
    private component: AddonModForumIndexComponent;
 | 
			
		||||
 | 
			
		||||
    constructor(pageComponent: unknown, component: AddonModForumIndexComponent, discussionsPathPrefix: string) {
 | 
			
		||||
        super(pageComponent);
 | 
			
		||||
 | 
			
		||||
        this.component = component;
 | 
			
		||||
        this.discussionsPathPrefix = discussionsPathPrefix;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getItemQueryParams(discussion: AddonModForumDiscussion): Params {
 | 
			
		||||
        return {
 | 
			
		||||
            discussion,
 | 
			
		||||
            courseId: this.component.courseId,
 | 
			
		||||
            cmId: this.component.module!.id,
 | 
			
		||||
            forumId: this.component.forum!.id,
 | 
			
		||||
            trackPosts: this.component.trackPosts,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected getItemPath(discussion: AddonModForumDiscussion): string {
 | 
			
		||||
        const discussionId = discussion.id;
 | 
			
		||||
 | 
			
		||||
        return this.discussionsPathPrefix + discussionId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected getSelectedItemPath(route: ActivatedRouteSnapshot): string | null {
 | 
			
		||||
        const discussionId = route.params.discussionId;
 | 
			
		||||
 | 
			
		||||
        return discussionId ? this.discussionsPathPrefix + discussionId : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,6 @@ import { CoreSharedModule } from '@/core/shared.module';
 | 
			
		||||
 | 
			
		||||
import { AddonModForumComponentsModule } from './components/components.module';
 | 
			
		||||
import { AddonModForumIndexPage } from './pages/index';
 | 
			
		||||
import { AddonModForumDiscussionPage } from './pages/discussion/discussion';
 | 
			
		||||
import { conditionalRoutes } from '@/app/app-routing.module';
 | 
			
		||||
import { CoreScreen } from '@services/screen';
 | 
			
		||||
 | 
			
		||||
@ -30,7 +29,8 @@ const mobileRoutes: Routes = [
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        path: ':courseId/:cmId/:discussionId',
 | 
			
		||||
        component: AddonModForumDiscussionPage,
 | 
			
		||||
        loadChildren: () => import('./pages/discussion/discussion.module').then(m => m.AddonForumDiscussionPageModule),
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,8 @@ const tabletRoutes: Routes = [
 | 
			
		||||
        children: [
 | 
			
		||||
            {
 | 
			
		||||
                path: ':discussionId',
 | 
			
		||||
                component: AddonModForumDiscussionPage,
 | 
			
		||||
                loadChildren: () => import('./pages/discussion/discussion.module').then(m => m.AddonForumDiscussionPageModule),
 | 
			
		||||
 | 
			
		||||
            },
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
@ -60,7 +61,6 @@ const routes: Routes = [
 | 
			
		||||
    ],
 | 
			
		||||
    declarations: [
 | 
			
		||||
        AddonModForumIndexPage,
 | 
			
		||||
        AddonModForumDiscussionPage,
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class AddonModForumLazyModule {}
 | 
			
		||||
 | 
			
		||||
@ -15,24 +15,47 @@
 | 
			
		||||
import { APP_INITIALIZER, NgModule } from '@angular/core';
 | 
			
		||||
import { Routes } from '@angular/router';
 | 
			
		||||
 | 
			
		||||
import { conditionalRoutes } from '@/app/app-routing.module';
 | 
			
		||||
import { CORE_SITE_SCHEMAS } from '@services/sites';
 | 
			
		||||
import { CoreCourseContentsRoutingModule } from '@features/course/pages/contents/contents-routing.module';
 | 
			
		||||
import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
 | 
			
		||||
import { CoreMainMenuTabRoutingModule } from '@features/mainmenu/mainmenu-tab-routing.module';
 | 
			
		||||
import { CoreScreen } from '@services/screen';
 | 
			
		||||
 | 
			
		||||
import { AddonModForumComponentsModule } from './components/components.module';
 | 
			
		||||
import { AddonModForumModuleHandler, AddonModForumModuleHandlerService } from './services/handlers/module';
 | 
			
		||||
import { SITE_SCHEMA } from './services/offline-db';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
const mainMenuRoutes: Routes = [
 | 
			
		||||
    {
 | 
			
		||||
        path: AddonModForumModuleHandlerService.PAGE_NAME,
 | 
			
		||||
        loadChildren: () => import('./forum-lazy.module').then(m => m.AddonModForumLazyModule),
 | 
			
		||||
    },
 | 
			
		||||
    ...conditionalRoutes(
 | 
			
		||||
        [
 | 
			
		||||
            {
 | 
			
		||||
                path: 'course/index/contents/mod_forum/:discussionId',
 | 
			
		||||
                loadChildren: () => import('./pages/discussion/discussion.module').then(m => m.AddonForumDiscussionPageModule),
 | 
			
		||||
            },
 | 
			
		||||
        ],
 | 
			
		||||
        () => CoreScreen.instance.isMobile,
 | 
			
		||||
    ),
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const courseContentsRoutes: Routes = conditionalRoutes(
 | 
			
		||||
    [
 | 
			
		||||
        {
 | 
			
		||||
            path: 'mod_forum/:discussionId',
 | 
			
		||||
            loadChildren: () => import('./pages/discussion/discussion.module').then(m => m.AddonForumDiscussionPageModule),
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
    () => CoreScreen.instance.isTablet,
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    imports: [
 | 
			
		||||
        CoreMainMenuTabRoutingModule.forChild(routes),
 | 
			
		||||
        CoreMainMenuTabRoutingModule.forChild(mainMenuRoutes),
 | 
			
		||||
        CoreCourseContentsRoutingModule.forChild({ children: courseContentsRoutes }),
 | 
			
		||||
        AddonModForumComponentsModule,
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										38
									
								
								src/addons/mod/forum/pages/discussion/discussion.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/addons/mod/forum/pages/discussion/discussion.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
// (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 { NgModule } from '@angular/core';
 | 
			
		||||
import { RouterModule, Routes } from '@angular/router';
 | 
			
		||||
 | 
			
		||||
import { AddonModForumComponentsModule } from '@addons/mod/forum/components/components.module';
 | 
			
		||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
			
		||||
 | 
			
		||||
import { AddonModForumDiscussionPage } from './discussion.page';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [{
 | 
			
		||||
    path: '',
 | 
			
		||||
    component: AddonModForumDiscussionPage,
 | 
			
		||||
}];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    imports: [
 | 
			
		||||
        RouterModule.forChild(routes),
 | 
			
		||||
        CoreSharedModule,
 | 
			
		||||
        AddonModForumComponentsModule,
 | 
			
		||||
    ],
 | 
			
		||||
    declarations: [
 | 
			
		||||
        AddonModForumDiscussionPage,
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class AddonForumDiscussionPageModule {}
 | 
			
		||||
@ -142,10 +142,10 @@ export abstract class CorePageItemsListManager<Item> {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Navigate to item.
 | 
			
		||||
        const path = route.firstChild ? `../${itemPath}` : itemPath;
 | 
			
		||||
        const params = this.getItemQueryParams(item);
 | 
			
		||||
        const pathPrefix = route.firstChild ? itemPath.split('/').fill('../').join('') : '';
 | 
			
		||||
 | 
			
		||||
        await CoreNavigator.instance.navigate(path, { params });
 | 
			
		||||
        await CoreNavigator.instance.navigate(pathPrefix + itemPath, { params });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { AfterViewInit, Component, ElementRef, HostBinding, Input, OnDestroy, ViewChild } from '@angular/core';
 | 
			
		||||
import { AfterViewInit, Component, ElementRef, Input, OnDestroy, ViewChild } from '@angular/core';
 | 
			
		||||
import { ActivatedRouteSnapshot } from '@angular/router';
 | 
			
		||||
import { IonContent, IonRouterOutlet } from '@ionic/angular';
 | 
			
		||||
import { CoreScreen } from '@services/screen';
 | 
			
		||||
@ -33,7 +33,6 @@ export class CoreSplitViewComponent implements AfterViewInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
    @ViewChild(IonContent) menuContent!: IonContent;
 | 
			
		||||
    @ViewChild(IonRouterOutlet) contentOutlet!: IonRouterOutlet;
 | 
			
		||||
    @HostBinding('class') classes = '';
 | 
			
		||||
    @Input() placeholderText = 'core.emptysplit';
 | 
			
		||||
    @Input() mode?: CoreSplitViewMode;
 | 
			
		||||
    isNested = false;
 | 
			
		||||
@ -92,7 +91,7 @@ export class CoreSplitViewComponent implements AfterViewInit, OnDestroy {
 | 
			
		||||
            classes.push('nested');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.classes = classes.join(' ');
 | 
			
		||||
        this.element.nativeElement.setAttribute('class', classes.join(' '));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,33 @@
 | 
			
		||||
// (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 { InjectionToken, ModuleWithProviders, NgModule } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
import { ModuleRoutesConfig } from '@/app/app-routing.module';
 | 
			
		||||
 | 
			
		||||
export const COURSE_CONTENTS_ROUTES = new InjectionToken('COURSE_CONTENTS_ROUTES');
 | 
			
		||||
 | 
			
		||||
@NgModule()
 | 
			
		||||
export class CoreCourseContentsRoutingModule {
 | 
			
		||||
 | 
			
		||||
    static forChild(routes: ModuleRoutesConfig): ModuleWithProviders<CoreCourseContentsRoutingModule> {
 | 
			
		||||
        return {
 | 
			
		||||
            ngModule: CoreCourseContentsRoutingModule,
 | 
			
		||||
            providers: [
 | 
			
		||||
                { provide: COURSE_CONTENTS_ROUTES, multi: true, useValue: routes },
 | 
			
		||||
            ],
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -12,23 +12,34 @@
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { RouterModule, Routes } from '@angular/router';
 | 
			
		||||
import { Injector, NgModule } from '@angular/core';
 | 
			
		||||
import { RouterModule, ROUTES, Routes } from '@angular/router';
 | 
			
		||||
 | 
			
		||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
			
		||||
import { CoreCourseContentsPage } from './contents';
 | 
			
		||||
import { CoreCourseComponentsModule } from '@features/course/components/components.module';
 | 
			
		||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
			
		||||
import { resolveModuleRoutes } from '@/app/app-routing.module';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
    {
 | 
			
		||||
        path: '',
 | 
			
		||||
        component: CoreCourseContentsPage,
 | 
			
		||||
    },
 | 
			
		||||
];
 | 
			
		||||
import { CoreCourseContentsPage } from './contents';
 | 
			
		||||
import { COURSE_CONTENTS_ROUTES } from './contents-routing.module';
 | 
			
		||||
 | 
			
		||||
function buildRoutes(injector: Injector): Routes {
 | 
			
		||||
    const routes = resolveModuleRoutes(injector, COURSE_CONTENTS_ROUTES);
 | 
			
		||||
 | 
			
		||||
    return [
 | 
			
		||||
        {
 | 
			
		||||
            path: '',
 | 
			
		||||
            component: CoreCourseContentsPage,
 | 
			
		||||
            children: routes.children,
 | 
			
		||||
        },
 | 
			
		||||
        ...routes.siblings,
 | 
			
		||||
    ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    providers: [
 | 
			
		||||
        { provide: ROUTES, multi: true, useFactory: buildRoutes, deps: [Injector] },
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        RouterModule.forChild(routes),
 | 
			
		||||
        CoreSharedModule,
 | 
			
		||||
        CoreCourseComponentsModule,
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user