diff --git a/src/addon/mod/data/pages/entry/entry.html b/src/addon/mod/data/pages/entry/entry.html index 1767dc9c0..aef6d0da0 100644 --- a/src/addon/mod/data/pages/entry/entry.html +++ b/src/addon/mod/data/pages/entry/entry.html @@ -4,10 +4,10 @@ - + - +
@@ -25,14 +25,14 @@
- +
- + - + diff --git a/src/addon/mod/data/pages/entry/entry.ts b/src/addon/mod/data/pages/entry/entry.ts index 6f6cf7649..2c568ab8d 100644 --- a/src/addon/mod/data/pages/entry/entry.ts +++ b/src/addon/mod/data/pages/entry/entry.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, ViewChild, OnDestroy } from '@angular/core'; +import { ChangeDetectorRef, Component, ViewChild, OnDestroy } from '@angular/core'; import { Content, IonicPage, NavParams, NavController } from 'ionic-angular'; import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; @@ -51,6 +51,9 @@ export class AddonModDataEntryPage implements OnDestroy { moduleName = 'data'; component = AddonModDataProvider.COMPONENT; entryLoaded = false; + renderingEntry = false; + loadingComments = false; + loadingRating = false; selectedGroup = 0; entry: any; offlineActions = []; @@ -61,18 +64,19 @@ export class AddonModDataEntryPage implements OnDestroy { data: any; groupInfo: any; showComments: any; - entryRendered = ''; + entryHtml = ''; siteId: string; extraImports = [AddonModDataComponentsModule]; jsData; ratingInfo: CoreRatingInfo; + isPullingToRefresh = false; // Whether the last fetching of data was started by a pull-to-refresh action constructor(params: NavParams, protected utils: CoreUtilsProvider, protected groupsProvider: CoreGroupsProvider, protected domUtils: CoreDomUtilsProvider, protected fieldsDelegate: AddonModDataFieldsDelegate, protected courseProvider: CoreCourseProvider, protected dataProvider: AddonModDataProvider, protected dataOffline: AddonModDataOfflineProvider, protected dataHelper: AddonModDataHelperProvider, - sitesProvider: CoreSitesProvider, protected navCtrl: NavController, - protected eventsProvider: CoreEventsProvider) { + sitesProvider: CoreSitesProvider, protected navCtrl: NavController, protected eventsProvider: CoreEventsProvider, + private cdr: ChangeDetectorRef) { this.module = params.get('module') || {}; this.entryId = params.get('entryId') || null; this.courseId = params.get('courseId'); @@ -122,12 +126,15 @@ export class AddonModDataEntryPage implements OnDestroy { /** * Fetch the entry data. * - * @param {boolean} refresh If refresh the current data or not. - * @return {Promise} Resolved when done. + * @param {boolean} [refresh] Whether to refresh the current data or not. + * @param {boolean} [isPtr] Whether is a pull to refresh action. + * @return {Promise} Resolved when done. */ - protected fetchEntryData(refresh?: boolean): Promise { + protected fetchEntryData(refresh?: boolean, isPtr?: boolean): Promise { let fieldsArray; + this.isPullingToRefresh = isPtr; + return this.dataProvider.getDatabase(this.courseId, this.module.id).then((data) => { this.title = data.name || this.title; this.data = data; @@ -176,7 +183,7 @@ export class AddonModDataEntryPage implements OnDestroy { const actions = this.dataHelper.getActions(this.data, this.access, this.entry); const templte = this.data.singletemplate || this.dataHelper.getDefaultTemplate('single', fieldsArray); - this.entryRendered = this.dataHelper.displayShowFields(templte, fieldsArray, this.entry, this.offset, 'show', actions); + this.entryHtml = this.dataHelper.displayShowFields(templte, fieldsArray, this.entry, this.offset, 'show', actions); this.showComments = actions.comments; const entries = {}; @@ -191,7 +198,7 @@ export class AddonModDataEntryPage implements OnDestroy { }).catch((message) => { if (!refresh) { // Some call failed, retry without using cache since it might be a new activity. - return this.refreshAllData(); + return this.refreshAllData(isPtr); } this.domUtils.showErrorModalDefault(message, 'core.course.errorgetmodule', true); @@ -219,9 +226,10 @@ export class AddonModDataEntryPage implements OnDestroy { /** * Refresh all the data. * + * @param {boolean} [isPtr] Whether is a pull to refresh action. * @return {Promise} Promise resolved when done. */ - protected refreshAllData(): Promise { + protected refreshAllData(isPtr?: boolean): Promise { const promises = []; promises.push(this.dataProvider.invalidateDatabaseData(this.courseId)); @@ -232,7 +240,7 @@ export class AddonModDataEntryPage implements OnDestroy { } return Promise.all(promises).finally(() => { - return this.fetchEntryData(true); + return this.fetchEntryData(true, isPtr); }); } @@ -244,7 +252,7 @@ export class AddonModDataEntryPage implements OnDestroy { */ refreshDatabase(refresher?: any): Promise { if (this.entryLoaded) { - return this.refreshAllData().finally(() => { + return this.refreshAllData(true).finally(() => { refresher && refresher.complete(); }); } @@ -310,6 +318,30 @@ export class AddonModDataEntryPage implements OnDestroy { }); } + /** + * Function called when entry is being rendered. + */ + setRenderingEntry(rendering: boolean): void { + this.renderingEntry = rendering; + this.cdr.detectChanges(); + } + + /** + * Function called when comments component is loading data. + */ + setLoadingComments(loading: boolean): void { + this.loadingComments = loading; + this.cdr.detectChanges(); + } + + /** + * Function called when rate component is loading data. + */ + setLoadingRating(loading: boolean): void { + this.loadingRating = loading; + this.cdr.detectChanges(); + } + /** * Function called when rating is updated online. */ diff --git a/src/core/comments/components/comments/comments.ts b/src/core/comments/components/comments/comments.ts index 079716675..2e5303a8e 100644 --- a/src/core/comments/components/comments/comments.ts +++ b/src/core/comments/components/comments/comments.ts @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, Input, OnChanges, SimpleChange } from '@angular/core'; -import { NavParams, NavController } from 'ionic-angular'; +import { Component, EventEmitter, Input, OnChanges, Output, SimpleChange } from '@angular/core'; +import { NavController } from 'ionic-angular'; import { CoreCommentsProvider } from '../../providers/comments'; /** @@ -31,11 +31,15 @@ export class CoreCommentsCommentsComponent implements OnChanges { @Input() area = ''; @Input() page = 0; @Input() title?: string; + @Input() displaySpinner = true; // Whether to display the loading spinner. + @Output() onLoading: EventEmitter; // Eevent that indicates whether the component is loading data. commentsLoaded = false; commentsCount: number; - constructor(navParams: NavParams, private navCtrl: NavController, private commentsProvider: CoreCommentsProvider) {} + constructor(private navCtrl: NavController, private commentsProvider: CoreCommentsProvider) { + this.onLoading = new EventEmitter(); + } /** * View loaded. @@ -56,6 +60,7 @@ export class CoreCommentsCommentsComponent implements OnChanges { protected fetchData(): void { this.commentsLoaded = false; + this.onLoading.emit(true); this.commentsProvider.getComments(this.contextLevel, this.instanceId, this.component, this.itemId, this.area, this.page) .then((comments) => { @@ -64,6 +69,7 @@ export class CoreCommentsCommentsComponent implements OnChanges { this.commentsCount = -1; }).finally(() => { this.commentsLoaded = true; + this.onLoading.emit(false); }); } diff --git a/src/core/comments/components/comments/core-comments.html b/src/core/comments/components/comments/core-comments.html index 1b30e656a..7dad81877 100644 --- a/src/core/comments/components/comments/core-comments.html +++ b/src/core/comments/components/comments/core-comments.html @@ -1,4 +1,4 @@ - +
{{ 'core.commentscount' | translate : {'$a': commentsCount} }}
diff --git a/src/core/compile/components/compile-html/compile-html.ts b/src/core/compile/components/compile-html/compile-html.ts index fd7b82ec9..a263241d9 100644 --- a/src/core/compile/components/compile-html/compile-html.ts +++ b/src/core/compile/components/compile-html/compile-html.ts @@ -48,6 +48,7 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy, DoCheck { @Input() extraProviders: any[] = []; // Extra providers. @Input() forceCompile: string | boolean; // Set it to true to force compile even if the text/javascript hasn't changed. @Output() created: EventEmitter = new EventEmitter(); // Will emit an event when the component is instantiated. + @Output() compiling: EventEmitter = new EventEmitter(); // Event that indicates whether the template is being compiled. // Get the container where to put the content. @ViewChild('dynamicComponent', { read: ViewContainerRef }) container: ViewContainerRef; @@ -58,6 +59,7 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy, DoCheck { protected componentRef: ComponentRef; protected element; protected differ: any; // To detect changes in the jsData input. + protected creatingComponent = false; constructor(protected compileProvider: CoreCompileProvider, protected cdr: ChangeDetectorRef, element: ElementRef, @Optional() protected navCtrl: NavController, differs: KeyValueDiffers, protected domUtils: CoreDomUtilsProvider, @@ -70,7 +72,7 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy, DoCheck { * Detect and act upon changes that Angular can’t or won’t detect on its own (objects and arrays). */ ngDoCheck(): void { - if (this.componentInstance) { + if (this.componentInstance && !this.creatingComponent) { // Check if there's any change in the jsData object. const changes = this.differ.diff(this.jsData); if (changes) { @@ -91,6 +93,8 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy, DoCheck { this.text) { // Create a new component and a new module. + this.creatingComponent = true; + this.compiling.emit(true); this.compileProvider.createAndCompileComponent(this.text, this.getComponentClass(), this.extraImports) .then((factory) => { // Destroy previous components. @@ -107,6 +111,9 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy, DoCheck { this.domUtils.showErrorModal(error); this.loaded = true; + }).finally(() => { + this.creatingComponent = false; + this.compiling.emit(false); }); } } diff --git a/src/core/rating/components/rate/rate.ts b/src/core/rating/components/rate/rate.ts index 581de6e66..b2c897523 100644 --- a/src/core/rating/components/rate/rate.ts +++ b/src/core/rating/components/rate/rate.ts @@ -35,6 +35,7 @@ export class CoreRatingRateComponent implements OnChanges { @Input() aggregateMethod: number; @Input() scaleId: number; @Input() userId: number; + @Output() onLoading: EventEmitter; // Eevent that indicates whether the component is loading data. @Output() onUpdate: EventEmitter; // Event emitted when the rating is updated online. item: CoreRatingInfoItem; @@ -43,6 +44,7 @@ export class CoreRatingRateComponent implements OnChanges { constructor(private domUtils: CoreDomUtilsProvider, private translate: TranslateService, private ratingProvider: CoreRatingProvider, private ratingOffline: CoreRatingOfflineProvider) { + this.onLoading = new EventEmitter(); this.onUpdate = new EventEmitter(); } @@ -77,6 +79,7 @@ export class CoreRatingRateComponent implements OnChanges { }); } + this.onLoading.emit(true); this.ratingOffline.getRating(this.contextLevel, this.instanceId, this.ratingInfo.component, this.ratingInfo.ratingarea, this.itemId).then((rating) => { this.rating = rating.rating; @@ -86,6 +89,8 @@ export class CoreRatingRateComponent implements OnChanges { } else { this.rating = CoreRatingProvider.UNSET_RATING; } + }).finally(() => { + this.onLoading.emit(false); }); }