Merge pull request #2082 from dpalou/MOBILE-3068

Mobile 3068
main
Dani Palou 2019-08-28 12:42:33 +02:00 committed by GitHub
commit fcf1677559
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 96 additions and 27 deletions

View File

@ -223,7 +223,7 @@ export class AddonBlogEntriesComponent implements OnInit {
this.filter['userid'] = this.currentUserId; this.filter['userid'] = this.currentUserId;
promises.push(this.blogProvider.invalidateEntries(this.filter)); promises.push(this.blogProvider.invalidateEntries(this.filter));
if (!this.showMyEntriesToggle) { if (!this.onlyMyEntries) {
delete this.filter['userid']; delete this.filter['userid'];
} }

View File

@ -1,4 +1,4 @@
<a *ngIf="commentsEnabled" ion-item text-wrap (click)="showComments()" detail-none> <a *ngIf="commentsEnabled" ion-item text-wrap (click)="showComments($event)" detail-none>
<h2>{{plugin.name}}</h2> <h2>{{plugin.name}}</h2>
<core-comments contextLevel="module" [instanceId]="assign.cmid" component="assignsubmission_comments" [itemId]="submission.id" area="submission_comments" [title]="plugin.name"></core-comments> <core-comments contextLevel="module" [instanceId]="assign.cmid" component="assignsubmission_comments" [itemId]="submission.id" area="submission_comments" [title]="plugin.name"></core-comments>
</a> </a>

View File

@ -48,7 +48,7 @@ export class AddonModAssignSubmissionCommentsComponent extends AddonModAssignSub
/** /**
* Show the comments. * Show the comments.
*/ */
showComments(): void { showComments(e?: Event): void {
this.commentsComponent && this.commentsComponent.openComments(); this.commentsComponent && this.commentsComponent.openComments(e);
} }
} }

View File

@ -85,7 +85,6 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
private prefetchHandler: AddonModDataPrefetchHandler, private prefetchHandler: AddonModDataPrefetchHandler,
private timeUtils: CoreTimeUtilsProvider, private timeUtils: CoreTimeUtilsProvider,
private groupsProvider: CoreGroupsProvider, private groupsProvider: CoreGroupsProvider,
private commentsProvider: CoreCommentsProvider,
private modalCtrl: ModalController, private modalCtrl: ModalController,
private utils: CoreUtilsProvider, private utils: CoreUtilsProvider,
protected navCtrl: NavController) { protected navCtrl: NavController) {
@ -152,8 +151,12 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
promises.push(this.dataProvider.invalidateDatabaseAccessInformationData(this.data.id)); promises.push(this.dataProvider.invalidateDatabaseAccessInformationData(this.data.id));
promises.push(this.groupsProvider.invalidateActivityGroupInfo(this.data.coursemodule)); promises.push(this.groupsProvider.invalidateActivityGroupInfo(this.data.coursemodule));
promises.push(this.dataProvider.invalidateEntriesData(this.data.id)); promises.push(this.dataProvider.invalidateEntriesData(this.data.id));
if (this.hasComments) { if (this.hasComments) {
promises.push(this.commentsProvider.invalidateCommentsByInstance('module', this.data.coursemodule)); this.eventsProvider.trigger(CoreCommentsProvider.REFRESH_COMMENTS_EVENT, {
contextLevel: 'module',
instanceId: this.data.coursemodule
}, this.sitesProvider.getCurrentSiteId());
} }
} }
@ -192,6 +195,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
return this.dataProvider.getDatabase(this.courseId, this.module.id).then((data) => { return this.dataProvider.getDatabase(this.courseId, this.module.id).then((data) => {
this.data = data; this.data = data;
this.hasComments = data.comments;
this.description = data.intro || data.description; this.description = data.intro || data.description;
this.dataRetrieved.emit(data); this.dataRetrieved.emit(data);
@ -258,7 +262,6 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
* @return {Promise<any>} Resolved then done. * @return {Promise<any>} Resolved then done.
*/ */
protected fetchEntriesData(): Promise<any> { protected fetchEntriesData(): Promise<any> {
this.hasComments = false;
return this.dataProvider.getDatabaseAccessInformation(this.data.id, this.selectedGroup).then((accessData) => { return this.dataProvider.getDatabaseAccessInformation(this.data.id, this.selectedGroup).then((accessData) => {
// Update values for current group. // Update values for current group.

View File

@ -27,6 +27,7 @@ import { AddonModDataSyncProvider } from '../../providers/sync';
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate'; import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
import { AddonModDataComponentsModule } from '../../components/components.module'; import { AddonModDataComponentsModule } from '../../components/components.module';
import { CoreCommentsProvider } from '@core/comments/providers/comments'; import { CoreCommentsProvider } from '@core/comments/providers/comments';
import { CoreCommentsCommentsComponent } from '@core/comments/components/comments/comments';
/** /**
* Page that displays the view entry page. * Page that displays the view entry page.
@ -38,6 +39,7 @@ import { CoreCommentsProvider } from '@core/comments/providers/comments';
}) })
export class AddonModDataEntryPage implements OnDestroy { export class AddonModDataEntryPage implements OnDestroy {
@ViewChild(Content) content: Content; @ViewChild(Content) content: Content;
@ViewChild(CoreCommentsCommentsComponent) comments: CoreCommentsCommentsComponent;
protected module: any; protected module: any;
protected entryId: number; protected entryId: number;
@ -211,13 +213,16 @@ export class AddonModDataEntryPage implements OnDestroy {
promises.push(this.dataProvider.invalidateDatabaseData(this.courseId)); promises.push(this.dataProvider.invalidateDatabaseData(this.courseId));
if (this.data) { if (this.data) {
if (this.data.comments && this.entry && this.entry.id > 0 && this.commentsEnabled) {
promises.push(this.commentsProvider.invalidateCommentsData('module', this.data.coursemodule, 'mod_data',
this.entry.id, 'database_entry'));
}
promises.push(this.dataProvider.invalidateEntryData(this.data.id, this.entryId)); promises.push(this.dataProvider.invalidateEntryData(this.data.id, this.entryId));
promises.push(this.groupsProvider.invalidateActivityGroupInfo(this.data.coursemodule)); promises.push(this.groupsProvider.invalidateActivityGroupInfo(this.data.coursemodule));
promises.push(this.dataProvider.invalidateEntriesData(this.data.id)); promises.push(this.dataProvider.invalidateEntriesData(this.data.id));
if (this.data.comments && this.entry && this.entry.id > 0 && this.commentsEnabled && this.comments) {
// Refresh comments. Don't add it to promises because we don't want the comments fetch to block the entry fetch.
this.comments.doRefresh().catch(() => {
// Ignore errors.
});
}
} }
return Promise.all(promises).finally(() => { return Promise.all(promises).finally(() => {

View File

@ -158,11 +158,12 @@ export class AddonModDataHelperProvider {
* @param {any} entry Entry. * @param {any} entry Entry.
* @param {number} offset Entry offset. * @param {number} offset Entry offset.
* @param {string} mode Mode list or show. * @param {string} mode Mode list or show.
* @param {AddonModDataOfflineAction[]} actions Actions that can be performed to the record. * @param {{[name: string]: boolean}} actions Actions that can be performed to the record.
* @return {string} Generated HTML. * @return {string} Generated HTML.
*/ */
displayShowFields(template: string, fields: any[], entry: any, offset: number, mode: string, displayShowFields(template: string, fields: any[], entry: any, offset: number, mode: string,
actions: AddonModDataOfflineAction[]): string { actions: {[name: string]: boolean}): string {
if (!template) { if (!template) {
return ''; return '';
} }
@ -357,9 +358,9 @@ export class AddonModDataHelperProvider {
* @param {any} database Database activity. * @param {any} database Database activity.
* @param {any} accessInfo Access info to the activity. * @param {any} accessInfo Access info to the activity.
* @param {any} record Entry or record where the actions will be performed. * @param {any} record Entry or record where the actions will be performed.
* @return {any} Keyed with the action names and boolean to evalute if it can or cannot be done. * @return {{[name: string]: boolean}} Keyed with the action names and boolean to evalute if it can or cannot be done.
*/ */
getActions(database: any, accessInfo: any, record: any): any { getActions(database: any, accessInfo: any, record: any): {[name: string]: boolean} {
return { return {
more: true, more: true,
moreurl: true, moreurl: true,

View File

@ -13,8 +13,9 @@
// limitations under the License. // limitations under the License.
import { Injector, OnInit, Component } from '@angular/core'; import { Injector, OnInit, Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreBlockBaseComponent } from '../../classes/base-block-component'; import { CoreBlockBaseComponent } from '../../classes/base-block-component';
import { CoreLoginHelperProvider } from '@core/login/providers/helper'; import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
/** /**
* Component to render blocks with only a title and link. * Component to render blocks with only a title and link.
@ -25,11 +26,8 @@ import { CoreLoginHelperProvider } from '@core/login/providers/helper';
}) })
export class CoreBlockOnlyTitleComponent extends CoreBlockBaseComponent implements OnInit { export class CoreBlockOnlyTitleComponent extends CoreBlockBaseComponent implements OnInit {
protected loginHelper: CoreLoginHelperProvider; constructor(injector: Injector, protected navCtrl: NavController, protected linkHelper: CoreContentLinksHelperProvider) {
constructor(injector: Injector) {
super(injector, 'CoreBlockOnlyTitleComponent'); super(injector, 'CoreBlockOnlyTitleComponent');
this.loginHelper = injector.get(CoreLoginHelperProvider);
} }
/** /**
@ -45,6 +43,6 @@ export class CoreBlockOnlyTitleComponent extends CoreBlockBaseComponent impleme
* Go to the block page. * Go to the block page.
*/ */
gotoBlock(): void { gotoBlock(): void {
this.loginHelper.redirect(this.link, this.linkParams); this.linkHelper.goInSite(this.navCtrl, this.link, this.linkParams, undefined, true);
} }
} }

View File

@ -12,11 +12,12 @@
// 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, EventEmitter, Input, OnChanges, OnDestroy, Output, SimpleChange } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, OnDestroy, Output, SimpleChange, Optional } from '@angular/core';
import { NavController } from 'ionic-angular'; import { NavController } from 'ionic-angular';
import { CoreCommentsProvider } from '../../providers/comments'; import { CoreCommentsProvider } from '../../providers/comments';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { CoreSplitViewComponent } from '@components/split-view/split-view';
/** /**
* Component that displays the count of comments. * Component that displays the count of comments.
@ -41,9 +42,12 @@ export class CoreCommentsCommentsComponent implements OnChanges, OnDestroy {
disabled = false; disabled = false;
protected updateSiteObserver; protected updateSiteObserver;
protected refreshCommentsObserver;
constructor(private navCtrl: NavController, private commentsProvider: CoreCommentsProvider, constructor(private navCtrl: NavController, private commentsProvider: CoreCommentsProvider,
sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider) { sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider,
@Optional() private svComponent: CoreSplitViewComponent) {
this.onLoading = new EventEmitter<boolean>(); this.onLoading = new EventEmitter<boolean>();
this.disabled = this.commentsProvider.areCommentsDisabledInSite(); this.disabled = this.commentsProvider.areCommentsDisabledInSite();
@ -58,6 +62,19 @@ export class CoreCommentsCommentsComponent implements OnChanges, OnDestroy {
this.fetchData(); this.fetchData();
} }
}, sitesProvider.getCurrentSiteId()); }, sitesProvider.getCurrentSiteId());
// Refresh comments if event received.
this.refreshCommentsObserver = eventsProvider.on(CoreCommentsProvider.REFRESH_COMMENTS_EVENT, (data) => {
// Verify these comments need to be updated.
if (this.undefinedOrEqual(data, 'contextLevel') && this.undefinedOrEqual(data, 'instanceId') &&
this.undefinedOrEqual(data, 'component') && this.undefinedOrEqual(data, 'itemId') &&
this.undefinedOrEqual(data, 'area')) {
this.doRefresh().catch(() => {
// Ignore errors.
});
}
}, sitesProvider.getCurrentSiteId());
} }
/** /**
@ -77,7 +94,10 @@ export class CoreCommentsCommentsComponent implements OnChanges, OnDestroy {
} }
} }
protected fetchData(): void { /**
* Fetch comments data.
*/
fetchData(): void {
if (this.disabled) { if (this.disabled) {
return; return;
} }
@ -94,13 +114,41 @@ export class CoreCommentsCommentsComponent implements OnChanges, OnDestroy {
}); });
} }
/**
* Refresh comments.
*
* @return {Promise<any>} Promise resolved when done.
*/
doRefresh(): Promise<any> {
return this.invalidateComments().then(() => {
return this.fetchData();
});
}
/**
* Invalidate comments data.
*
* @return {Promise<any>} Promise resolved when done.
*/
invalidateComments(): Promise<any> {
return this.commentsProvider.invalidateCommentsData(this.contextLevel, this.instanceId, this.component, this.itemId,
this.area);
}
/** /**
* Opens the comments page. * Opens the comments page.
*/ */
openComments(): void { openComments(e?: Event): void {
if (e) {
e.preventDefault();
e.stopPropagation();
}
if (!this.disabled && !this.countError) { if (!this.disabled && !this.countError) {
// Open a new state with the interpolated contents. // Open a new state with the interpolated contents.
this.navCtrl.push('CoreCommentsViewerPage', { const navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl;
navCtrl.push('CoreCommentsViewerPage', {
contextLevel: this.contextLevel, contextLevel: this.contextLevel,
instanceId: this.instanceId, instanceId: this.instanceId,
componentName: this.component, componentName: this.component,
@ -116,5 +164,17 @@ export class CoreCommentsCommentsComponent implements OnChanges, OnDestroy {
*/ */
ngOnDestroy(): void { ngOnDestroy(): void {
this.updateSiteObserver && this.updateSiteObserver.off(); this.updateSiteObserver && this.updateSiteObserver.off();
this.refreshCommentsObserver && this.refreshCommentsObserver.off();
}
/**
* Check if a certain value in data is undefined or equal to this instance value.
*
* @param {any} data Data object.
* @param {string} name Name of the property to check.
* @return {boolean} Whether it's undefined or equal.
*/
protected undefinedOrEqual(data: any, name: string): boolean {
return typeof data[name] == 'undefined' || data[name] == this[name];
} }
} }

View File

@ -1,5 +1,5 @@
<core-loading *ngIf="!disabled" [hideUntil]="commentsLoaded || !displaySpinner"> <core-loading *ngIf="!disabled" [hideUntil]="commentsLoaded || !displaySpinner">
<div (click)="openComments()" *ngIf="!countError" [class.core-comments-clickable]="!disabled"> <div (click)="openComments($event)" *ngIf="!countError" [class.core-comments-clickable]="!disabled">
{{ 'core.comments.commentscount' | translate : {'$a': commentsCount} }} {{ 'core.comments.commentscount' | translate : {'$a': commentsCount} }}
</div> </div>
<div *ngIf="countError"> <div *ngIf="countError">

View File

@ -25,6 +25,8 @@ import { CoreCommentsOfflineProvider } from './offline';
@Injectable() @Injectable()
export class CoreCommentsProvider { export class CoreCommentsProvider {
static REFRESH_COMMENTS_EVENT = 'core_comments_refresh_comments';
protected ROOT_CACHE_KEY = 'mmComments:'; protected ROOT_CACHE_KEY = 'mmComments:';
static pageSize = null; static pageSize = null;
static pageSizeOK = false; // If true, the pageSize is definitive. If not, it's a temporal value to reduce WS calls. static pageSizeOK = false; // If true, the pageSize is definitive. If not, it's a temporal value to reduce WS calls.