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