2021-03-08 13:18:17 +01:00
|
|
|
// (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 { ContextLevel } from '@/core/constants';
|
|
|
|
import { AddonBlog, AddonBlogFilter, AddonBlogPost, AddonBlogProvider } from '@addons/blog/services/blog';
|
|
|
|
import { Component, OnInit } from '@angular/core';
|
|
|
|
import { CoreComments } from '@features/comments/services/comments';
|
2022-01-27 14:59:14 +01:00
|
|
|
import { CoreMainMenuDeepLinkManager } from '@features/mainmenu/classes/deep-link-manager';
|
2021-03-08 13:18:17 +01:00
|
|
|
import { CoreTag } from '@features/tag/services/tag';
|
|
|
|
import { CoreUser, CoreUserProfile } from '@features/user/services/user';
|
|
|
|
import { IonRefresher } from '@ionic/angular';
|
|
|
|
import { CoreNavigator } from '@services/navigator';
|
|
|
|
import { CoreSites } from '@services/sites';
|
|
|
|
import { CoreDomUtils } from '@services/utils/dom';
|
|
|
|
import { CoreTextUtils } from '@services/utils/text';
|
|
|
|
import { CoreUtils } from '@services/utils/utils';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Page that displays the list of blog entries.
|
|
|
|
*/
|
|
|
|
@Component({
|
|
|
|
selector: 'page-addon-blog-entries',
|
|
|
|
templateUrl: 'entries.html',
|
|
|
|
})
|
|
|
|
export class AddonBlogEntriesPage implements OnInit {
|
|
|
|
|
|
|
|
title = '';
|
|
|
|
|
|
|
|
protected filter: AddonBlogFilter = {};
|
|
|
|
protected pageLoaded = 0;
|
|
|
|
protected userPageLoaded = 0;
|
|
|
|
protected canLoadMoreEntries = false;
|
|
|
|
protected canLoadMoreUserEntries = true;
|
|
|
|
protected siteHomeId: number;
|
2022-03-08 07:42:09 +01:00
|
|
|
protected fetchSuccess = false;
|
2021-03-08 13:18:17 +01:00
|
|
|
|
|
|
|
loaded = false;
|
|
|
|
canLoadMore = false;
|
|
|
|
loadMoreError = false;
|
|
|
|
entries: AddonBlogPostFormatted[] = [];
|
|
|
|
currentUserId: number;
|
|
|
|
showMyEntriesToggle = false;
|
|
|
|
onlyMyEntries = false;
|
|
|
|
component = AddonBlogProvider.COMPONENT;
|
|
|
|
commentsEnabled = false;
|
|
|
|
tagsEnabled = false;
|
|
|
|
contextLevel: ContextLevel = ContextLevel.SYSTEM;
|
|
|
|
contextInstanceId = 0;
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
this.currentUserId = CoreSites.getCurrentSiteUserId();
|
|
|
|
this.siteHomeId = CoreSites.getCurrentSiteHomeId();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* View loaded.
|
|
|
|
*/
|
|
|
|
async ngOnInit(): Promise<void> {
|
|
|
|
const userId = CoreNavigator.getRouteNumberParam('userId');
|
|
|
|
const courseId = CoreNavigator.getRouteNumberParam('courseId');
|
|
|
|
const cmId = CoreNavigator.getRouteNumberParam('cmId');
|
|
|
|
const entryId = CoreNavigator.getRouteNumberParam('entryId');
|
|
|
|
const groupId = CoreNavigator.getRouteNumberParam('groupId');
|
|
|
|
const tagId = CoreNavigator.getRouteNumberParam('tagId');
|
|
|
|
|
|
|
|
if (!userId && !courseId && !cmId && !entryId && !groupId && !tagId) {
|
|
|
|
this.title = 'addon.blog.siteblogheading';
|
|
|
|
} else {
|
|
|
|
this.title = 'addon.blog.blogentries';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (userId) {
|
|
|
|
this.filter.userid = userId;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (courseId) {
|
|
|
|
this.filter.courseid = courseId;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmId) {
|
|
|
|
this.filter.cmid = cmId;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entryId) {
|
|
|
|
this.filter.entryid = entryId;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (groupId) {
|
|
|
|
this.filter.groupid = groupId;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tagId) {
|
|
|
|
this.filter.tagid = tagId;
|
|
|
|
}
|
|
|
|
|
2022-11-24 16:34:56 +01:00
|
|
|
this.showMyEntriesToggle = !userId && !this.filter.entryid;
|
|
|
|
|
2021-03-08 13:18:17 +01:00
|
|
|
// Calculate the context level.
|
|
|
|
if (userId && !courseId && !cmId) {
|
|
|
|
this.contextLevel = ContextLevel.USER;
|
|
|
|
this.contextInstanceId = userId;
|
|
|
|
} else if (courseId && courseId != this.siteHomeId) {
|
|
|
|
this.contextLevel = ContextLevel.COURSE;
|
|
|
|
this.contextInstanceId = courseId;
|
|
|
|
} else {
|
|
|
|
this.contextLevel = ContextLevel.SYSTEM;
|
|
|
|
this.contextInstanceId = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.commentsEnabled = !CoreComments.areCommentsDisabledInSite();
|
|
|
|
this.tagsEnabled = CoreTag.areTagsAvailableInSite();
|
|
|
|
|
2022-01-27 14:59:14 +01:00
|
|
|
const deepLinkManager = new CoreMainMenuDeepLinkManager();
|
|
|
|
deepLinkManager.treatLink();
|
|
|
|
|
2021-03-08 13:18:17 +01:00
|
|
|
await this.fetchEntries();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch blog entries.
|
|
|
|
*
|
|
|
|
* @param refresh Empty events array first.
|
|
|
|
* @return Promise with the entries.
|
|
|
|
*/
|
|
|
|
protected async fetchEntries(refresh: boolean = false): Promise<void> {
|
|
|
|
this.loadMoreError = false;
|
|
|
|
|
|
|
|
if (refresh) {
|
|
|
|
this.pageLoaded = 0;
|
|
|
|
this.userPageLoaded = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const loadPage = this.onlyMyEntries ? this.userPageLoaded : this.pageLoaded;
|
|
|
|
|
|
|
|
try {
|
|
|
|
const result = await AddonBlog.getEntries(this.filter, loadPage);
|
|
|
|
|
|
|
|
const promises = result.entries.map(async (entry: AddonBlogPostFormatted) => {
|
|
|
|
switch (entry.publishstate) {
|
|
|
|
case 'draft':
|
|
|
|
entry.publishTranslated = 'publishtonoone';
|
|
|
|
break;
|
|
|
|
case 'site':
|
|
|
|
entry.publishTranslated = 'publishtosite';
|
|
|
|
break;
|
|
|
|
case 'public':
|
|
|
|
entry.publishTranslated = 'publishtoworld';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
entry.publishTranslated = 'privacy:unknown';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate the context. This code was inspired by calendar events, Moodle doesn't do this for blogs.
|
|
|
|
if (entry.moduleid || entry.coursemoduleid) {
|
|
|
|
entry.contextLevel = ContextLevel.MODULE;
|
|
|
|
entry.contextInstanceId = entry.moduleid || entry.coursemoduleid;
|
|
|
|
} else if (entry.courseid) {
|
|
|
|
entry.contextLevel = ContextLevel.COURSE;
|
|
|
|
entry.contextInstanceId = entry.courseid;
|
|
|
|
} else {
|
|
|
|
entry.contextLevel = ContextLevel.USER;
|
|
|
|
entry.contextInstanceId = entry.userid;
|
|
|
|
}
|
|
|
|
|
2021-10-15 12:10:29 +02:00
|
|
|
entry.summary = CoreTextUtils.replacePluginfileUrls(entry.summary, entry.summaryfiles || []);
|
2021-03-08 13:18:17 +01:00
|
|
|
|
2022-03-08 07:42:09 +01:00
|
|
|
entry.user = await CoreUtils.ignoreErrors(CoreUser.getProfile(entry.userid, entry.courseid, true));
|
2021-03-08 13:18:17 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
if (refresh) {
|
|
|
|
this.entries = result.entries;
|
|
|
|
} else {
|
|
|
|
this.entries = CoreUtils.uniqueArray(this.entries
|
|
|
|
.concat(result.entries), 'id')
|
|
|
|
.sort((a, b) => b.created - a.created);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.onlyMyEntries) {
|
|
|
|
const count = this.entries.filter((entry) => entry.userid == this.currentUserId).length;
|
|
|
|
this.canLoadMoreUserEntries = result.totalentries > count;
|
|
|
|
this.canLoadMore = this.canLoadMoreUserEntries;
|
|
|
|
this.userPageLoaded++;
|
|
|
|
} else {
|
|
|
|
this.canLoadMoreEntries = result.totalentries > this.entries.length;
|
|
|
|
this.canLoadMore = this.canLoadMoreEntries;
|
|
|
|
this.pageLoaded++;
|
|
|
|
}
|
|
|
|
|
|
|
|
await Promise.all(promises);
|
2022-03-08 07:42:09 +01:00
|
|
|
|
|
|
|
if (!this.fetchSuccess) {
|
|
|
|
this.fetchSuccess = true;
|
|
|
|
CoreUtils.ignoreErrors(AddonBlog.logView(this.filter));
|
|
|
|
}
|
2021-03-08 13:18:17 +01:00
|
|
|
} catch (error) {
|
|
|
|
CoreDomUtils.showErrorModalDefault(error, 'addon.blog.errorloadentries', true);
|
|
|
|
this.loadMoreError = true; // Set to prevent infinite calls with infinite-loading.
|
|
|
|
} finally {
|
|
|
|
this.loaded = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Toggle between showing only my entries or not.
|
|
|
|
*
|
|
|
|
* @param enabled If true, filter my entries. False otherwise.
|
|
|
|
*/
|
|
|
|
onlyMyEntriesToggleChanged(enabled: boolean): void {
|
|
|
|
this.canLoadMore = enabled ? this.canLoadMoreUserEntries : this.canLoadMoreEntries;
|
|
|
|
|
|
|
|
if (!enabled) {
|
|
|
|
delete this.filter.userid;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const count = this.entries.filter((entry) => entry.userid == this.currentUserId).length;
|
|
|
|
this.userPageLoaded = Math.floor(count / AddonBlogProvider.ENTRIES_PER_PAGE);
|
|
|
|
this.filter.userid = this.currentUserId;
|
|
|
|
|
|
|
|
if (count == 0 && this.canLoadMoreUserEntries) {
|
|
|
|
// First time but no entry loaded. Try to load some.
|
|
|
|
this.loadMore();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to load more entries.
|
|
|
|
*
|
|
|
|
* @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading.
|
|
|
|
* @return Resolved when done.
|
|
|
|
*/
|
|
|
|
loadMore(infiniteComplete?: () => void): Promise<void> {
|
|
|
|
return this.fetchEntries().finally(() => {
|
|
|
|
infiniteComplete && infiniteComplete();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Refresh blog entries on PTR.
|
|
|
|
*
|
|
|
|
* @param refresher Refresher instance.
|
|
|
|
*/
|
2021-03-12 12:22:55 +01:00
|
|
|
refresh(refresher?: IonRefresher): void {
|
2021-03-08 13:18:17 +01:00
|
|
|
const promises = this.entries.map((entry) =>
|
|
|
|
CoreComments.invalidateCommentsData('user', entry.userid, this.component, entry.id, 'format_blog'));
|
|
|
|
|
|
|
|
promises.push(AddonBlog.invalidateEntries(this.filter));
|
|
|
|
|
|
|
|
if (this.showMyEntriesToggle) {
|
|
|
|
this.filter['userid'] = this.currentUserId;
|
|
|
|
promises.push(AddonBlog.invalidateEntries(this.filter));
|
|
|
|
|
|
|
|
if (!this.onlyMyEntries) {
|
|
|
|
delete this.filter['userid'];
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
CoreUtils.allPromises(promises).finally(() => {
|
|
|
|
this.fetchEntries(true).finally(() => {
|
|
|
|
if (refresher) {
|
2021-03-12 12:22:55 +01:00
|
|
|
refresher?.complete();
|
2021-03-08 13:18:17 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Blog post with some calculated data.
|
|
|
|
*/
|
|
|
|
type AddonBlogPostFormatted = AddonBlogPost & {
|
|
|
|
publishTranslated?: string; // Calculated in the app. Key of the string to translate the publish state of the post.
|
|
|
|
user?: CoreUserProfile; // Calculated in the app. Data of the user that wrote the post.
|
|
|
|
contextLevel?: string; // Calculated in the app. The context level of the entry.
|
|
|
|
contextInstanceId?: number; // Calculated in the app. The context instance id.
|
|
|
|
};
|