diff --git a/src/addon/calendar/pages/list/list.html b/src/addon/calendar/pages/list/list.html
index 5b8dfd808..33ec3cebc 100644
--- a/src/addon/calendar/pages/list/list.html
+++ b/src/addon/calendar/pages/list/list.html
@@ -29,9 +29,7 @@
-
-
-
+
\ No newline at end of file
diff --git a/src/addon/calendar/pages/list/list.ts b/src/addon/calendar/pages/list/list.ts
index 324d4b76f..90d85d4e9 100644
--- a/src/addon/calendar/pages/list/list.ts
+++ b/src/addon/calendar/pages/list/list.ts
@@ -179,6 +179,18 @@ export class AddonCalendarListPage implements OnDestroy {
});
}
+ /**
+ * Function to load more events.
+ *
+ * @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
+ * @return {Promise} Resolved when done.
+ */
+ loadMoreEvents(infiniteComplete?: any): Promise {
+ return this.fetchEvents().finally(() => {
+ infiniteComplete && infiniteComplete();
+ });
+ }
+
/**
* Get filtered events.
*
diff --git a/src/addon/messages/pages/discussion/discussion.html b/src/addon/messages/pages/discussion/discussion.html
index 89bd5a6be..da8d7e7c4 100644
--- a/src/addon/messages/pages/discussion/discussion.html
+++ b/src/addon/messages/pages/discussion/discussion.html
@@ -15,9 +15,7 @@
-
-
-
+
diff --git a/src/addon/messages/pages/discussion/discussion.ts b/src/addon/messages/pages/discussion/discussion.ts
index e8cb226dc..3080b974a 100644
--- a/src/addon/messages/pages/discussion/discussion.ts
+++ b/src/addon/messages/pages/discussion/discussion.ts
@@ -543,10 +543,10 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
/**
* Function to load previous messages.
*
- * @param {any} [infiniteScroll] Infinite scroll object.
+ * @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
* @return {Promise} Resolved when done.
*/
- loadPrevious(infiniteScroll: any): Promise {
+ loadPrevious(infiniteComplete?: any): Promise {
// If there is an ongoing fetch, wait for it to finish.
return this.waitForFetch().finally(() => {
this.pagesLoaded++;
@@ -555,7 +555,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
this.pagesLoaded--;
this.domUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingmessages', true);
}).finally(() => {
- infiniteScroll.complete();
+ infiniteComplete && infiniteComplete();
});
});
}
diff --git a/src/addon/mod/forum/components/index/addon-mod-forum-index.html b/src/addon/mod/forum/components/index/addon-mod-forum-index.html
index 8d88b2378..463d9bbdf 100644
--- a/src/addon/mod/forum/components/index/addon-mod-forum-index.html
+++ b/src/addon/mod/forum/components/index/addon-mod-forum-index.html
@@ -88,9 +88,7 @@
-
-
-
+
diff --git a/src/addon/mod/forum/components/index/index.ts b/src/addon/mod/forum/components/index/index.ts
index 8ab76ab1f..685c671c0 100644
--- a/src/addon/mod/forum/components/index/index.ts
+++ b/src/addon/mod/forum/components/index/index.ts
@@ -305,13 +305,16 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
/**
* Convenience function to load more forum discussions.
*
+ * @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
* @return {Promise} Promise resolved when done.
*/
- protected fetchMoreDiscussions(): Promise {
+ fetchMoreDiscussions(infiniteComplete?: any): Promise {
return this.fetchDiscussions(false).catch((message) => {
this.domUtils.showErrorModalDefault(message, 'addon.mod_forum.errorgetforum', true);
this.canLoadMore = false; // Set to false to prevent infinite calls with infinite-loading.
+ }).finally(() => {
+ infiniteComplete && infiniteComplete();
});
}
diff --git a/src/addon/mod/glossary/components/index/addon-mod-glossary-index.html b/src/addon/mod/glossary/components/index/addon-mod-glossary-index.html
index 4ad1add14..8745e6f6b 100644
--- a/src/addon/mod/glossary/components/index/addon-mod-glossary-index.html
+++ b/src/addon/mod/glossary/components/index/addon-mod-glossary-index.html
@@ -56,9 +56,7 @@
-
-
-
+
diff --git a/src/addon/mod/glossary/components/index/index.ts b/src/addon/mod/glossary/components/index/index.ts
index 461178374..9cb87dd68 100644
--- a/src/addon/mod/glossary/components/index/index.ts
+++ b/src/addon/mod/glossary/components/index/index.ts
@@ -289,11 +289,14 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
/**
* Convenience function to load more forum discussions.
*
+ * @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
* @return {Promise} Promise resolved when done.
*/
- loadMoreEntries(): Promise {
+ loadMoreEntries(infiniteComplete?: any): Promise {
return this.fetchEntries(true).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'addon.mod_glossary.errorloadingentries', true);
+ }).finally(() => {
+ infiniteComplete && infiniteComplete();
});
}
diff --git a/src/addon/notifications/pages/list/list.html b/src/addon/notifications/pages/list/list.html
index 05d17c75d..0ee4eb357 100644
--- a/src/addon/notifications/pages/list/list.html
+++ b/src/addon/notifications/pages/list/list.html
@@ -32,8 +32,6 @@
-
-
-
+
diff --git a/src/addon/notifications/pages/list/list.ts b/src/addon/notifications/pages/list/list.ts
index 07de7da86..fe21ee62f 100644
--- a/src/addon/notifications/pages/list/list.ts
+++ b/src/addon/notifications/pages/list/list.ts
@@ -204,11 +204,11 @@ export class AddonNotificationsListPage {
/**
* Load more results.
*
- * @param {any} infiniteScroll The infinit scroll instance.
+ * @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
*/
- loadMoreNotifications(infiniteScroll: any): void {
+ loadMoreNotifications(infiniteComplete?: any): void {
this.fetchNotifications().finally(() => {
- infiniteScroll.complete();
+ infiniteComplete && infiniteComplete();
});
}
diff --git a/src/components/components.module.ts b/src/components/components.module.ts
index 6163a7d83..487778e49 100644
--- a/src/components/components.module.ts
+++ b/src/components/components.module.ts
@@ -49,6 +49,7 @@ import { CoreNavigationBarComponent } from './navigation-bar/navigation-bar';
import { CoreAttachmentsComponent } from './attachments/attachments';
import { CoreIonTabsComponent } from './ion-tabs/ion-tabs';
import { CoreIonTabComponent } from './ion-tabs/ion-tab';
+import { CoreInfiniteLoadingComponent } from './infinite-loading/infinite-loading';
@NgModule({
declarations: [
@@ -83,7 +84,8 @@ import { CoreIonTabComponent } from './ion-tabs/ion-tab';
CoreNavigationBarComponent,
CoreAttachmentsComponent,
CoreIonTabsComponent,
- CoreIonTabComponent
+ CoreIonTabComponent,
+ CoreInfiniteLoadingComponent
],
entryComponents: [
CoreContextMenuPopoverComponent,
@@ -125,7 +127,8 @@ import { CoreIonTabComponent } from './ion-tabs/ion-tab';
CoreNavigationBarComponent,
CoreAttachmentsComponent,
CoreIonTabsComponent,
- CoreIonTabComponent
+ CoreIonTabComponent,
+ CoreInfiniteLoadingComponent
]
})
export class CoreComponentsModule {}
diff --git a/src/components/infinite-loading/core-infinite-loading.html b/src/components/infinite-loading/core-infinite-loading.html
new file mode 100644
index 000000000..e52c393a5
--- /dev/null
+++ b/src/components/infinite-loading/core-infinite-loading.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/infinite-loading/infinite-loading.ts b/src/components/infinite-loading/infinite-loading.ts
new file mode 100644
index 000000000..7c7b3b4d6
--- /dev/null
+++ b/src/components/infinite-loading/infinite-loading.ts
@@ -0,0 +1,68 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// 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 { Component, Input, Output, EventEmitter } from '@angular/core';
+import { InfiniteScroll } from 'ionic-angular';
+
+/**
+ * Component to show a infinite loading trigger and spinner while more data is being loaded.
+ *
+ * Usage:
+ *
+ */
+@Component({
+ selector: 'core-infinite-loading',
+ templateUrl: 'core-infinite-loading.html',
+})
+export class CoreInfiniteLoadingComponent {
+ @Input() enabled: boolean;
+ @Input() position = 'bottom';
+ @Output() action: EventEmitter<() => void>; // Will emit an event when triggered.
+
+ loadingMore = false; // Hide button and avoid loading more.
+
+ protected infiniteScroll: InfiniteScroll;
+
+ constructor() {
+ this.action = new EventEmitter();
+ }
+
+ /**
+ * Load More items calling the action provided.
+ *
+ * @param {InfiniteScroll} [infiniteScroll] Infinite scroll object only if triggered from the scroll.
+ */
+ loadMore(infiniteScroll?: InfiniteScroll): void {
+ if (this.loadingMore) {
+ return;
+ }
+
+ if (infiniteScroll) {
+ this.infiniteScroll = infiniteScroll;
+ }
+ this.loadingMore = true;
+
+ this.action.emit(this.complete.bind(this));
+ }
+
+ /**
+ * Complete loading.
+ */
+ complete(): void {
+ this.loadingMore = false;
+ this.infiniteScroll && this.infiniteScroll.complete();
+ this.infiniteScroll = undefined;
+ }
+
+}
diff --git a/src/core/course/components/format/core-course-format.html b/src/core/course/components/format/core-course-format.html
index 56eedc8d8..4b244729d 100644
--- a/src/core/course/components/format/core-course-format.html
+++ b/src/core/course/components/format/core-course-format.html
@@ -44,10 +44,14 @@
-
-
+
+
+
+
+
+
diff --git a/src/core/course/components/format/format.ts b/src/core/course/components/format/format.ts
index cd9a0bd00..37b239a6e 100644
--- a/src/core/course/components/format/format.ts
+++ b/src/core/course/components/format/format.ts
@@ -41,6 +41,8 @@ import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-comp
templateUrl: 'core-course-format.html'
})
export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
+ static LOAD_MORE_ACTIVITIES = 20; // How many activities should load each time showMoreActivities is called.
+
@Input() course: any; // The course to render.
@Input() sections: any[]; // List of course sections.
@Input() downloadEnabled?: boolean; // Whether the download of sections and modules is enabled.
@@ -57,6 +59,8 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
sectionSelectorComponent: any;
singleSectionComponent: any;
allSectionsComponent: any;
+ canLoadMore = false;
+ showSectionId = 0;
// Data to pass to the components.
data: any = {};
@@ -273,6 +277,9 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
} else {
this.previousSection = null;
this.nextSection = null;
+ this.canLoadMore = false;
+ this.showSectionId = 0;
+ this.showMoreActivities();
}
if (this.moduleId && typeof previousValue == 'undefined') {
@@ -363,6 +370,46 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
return Promise.all(promises);
}
+ /**
+ * Show more activities (only used when showing all the sections at the same time).
+ *
+ * @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
+ */
+ showMoreActivities(infiniteComplete?: any): void {
+ this.canLoadMore = false;
+
+ let modulesLoaded = 0,
+ i;
+ for (i = this.showSectionId + 1; i < this.sections.length; i++) {
+ if (this.sections[i].hasContent && this.sections[i].modules) {
+ modulesLoaded += this.sections[i].modules.reduce((total, module) => {
+ return module.visibleoncoursepage !== 0 ? total + 1 : total;
+ }, 0);
+
+ if (modulesLoaded >= CoreCourseFormatComponent.LOAD_MORE_ACTIVITIES) {
+ this.showSectionId = i;
+ break;
+ }
+ }
+ }
+
+ this.canLoadMore = i < this.sections.length;
+
+ if (this.canLoadMore) {
+ // Check if any of the following sections have any content.
+ let thereAreMore = false;
+ for (i++; i < this.sections.length; i++) {
+ if (this.sections[i].hasContent && this.sections[i].modules && this.sections[i].modules.length > 0) {
+ thereAreMore = true;
+ break;
+ }
+ }
+ this.canLoadMore = thereAreMore;
+ }
+
+ infiniteComplete && infiniteComplete();
+ }
+
/**
* Component destroyed.
*/
diff --git a/src/core/course/formats/weeks/providers/handler.ts b/src/core/course/formats/weeks/providers/handler.ts
index 675e343b1..ccaef9d44 100644
--- a/src/core/course/formats/weeks/providers/handler.ts
+++ b/src/core/course/formats/weeks/providers/handler.ts
@@ -47,8 +47,8 @@ export class CoreCourseFormatWeeksHandler implements CoreCourseFormatHandler {
const now = this.timeUtils.timestamp();
if (now < course.startdate || (course.enddate && now > course.enddate)) {
- // Course hasn't started yet or it has ended already. Return the first section.
- return sections[1];
+ // Course hasn't started yet or it has ended already. Return all sections.
+ return sections[0];
}
for (let i = 0; i < sections.length; i++) {
@@ -63,8 +63,8 @@ export class CoreCourseFormatWeeksHandler implements CoreCourseFormatHandler {
}
}
- // The section wasn't found, return the first section.
- return sections[1];
+ // The section wasn't found, return all sections.
+ return sections[0];
}
/**
diff --git a/src/core/course/providers/default-format.ts b/src/core/course/providers/default-format.ts
index 45bcfe551..50ae2701c 100644
--- a/src/core/course/providers/default-format.ts
+++ b/src/core/course/providers/default-format.ts
@@ -16,7 +16,6 @@ import { Injectable } from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreCourseFormatHandler } from './format-delegate';
-import { CoreCourseProvider } from './course';
/**
* Default handler used when the course format doesn't have a specific implementation.
@@ -98,38 +97,28 @@ export class CoreCourseFormatDefaultHandler implements CoreCourseFormatHandler {
*/
getCurrentSection(course: any, sections: any[]): any | Promise {
if (!this.coursesProvider.isGetCoursesByFieldAvailable()) {
- // Cannot get the current section, return the first one.
- if (sections[0].id != CoreCourseProvider.ALL_SECTIONS_ID) {
- return sections[0];
- }
-
- return sections[1];
+ // Cannot get the current section, return all of them.
+ return sections[0];
}
// We need the "marker" to determine the current section.
return this.coursesProvider.getCoursesByField('id', course.id).catch(() => {
// Ignore errors.
}).then((courses) => {
- if (courses && courses[0]) {
+ if (courses && courses[0] && courses[0].marker > 0) {
// Find the marked section.
- const course = courses[0];
- for (let i = 0; i < sections.length; i++) {
- const section = sections[i];
- if (section.section == course.marker) {
- return section;
- }
- }
- }
+ const course = courses[0],
+ section = sections.find((sect) => {
+ return sect.section == course.marker;
+ });
- // Marked section not found or we couldn't retrieve the marker. Return the first section.
- for (let i = 0; i < sections.length; i++) {
- const section = sections[i];
- if (section.id != CoreCourseProvider.ALL_SECTIONS_ID) {
+ if (section) {
return section;
}
}
- return Promise.reject(null);
+ // Marked section not found or we couldn't retrieve the marker. Return all sections.
+ return sections[0];
});
}
diff --git a/src/core/course/providers/format-delegate.ts b/src/core/course/providers/format-delegate.ts
index 4a2b476c4..40a2668d4 100644
--- a/src/core/course/providers/format-delegate.ts
+++ b/src/core/course/providers/format-delegate.ts
@@ -17,7 +17,6 @@ import { NavController } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events';
import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites';
-import { CoreCourseProvider } from './course';
import { CoreCourseFormatDefaultHandler } from './default-format';
import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate';
@@ -285,14 +284,11 @@ export class CoreCourseFormatDelegate extends CoreDelegate {
* @return {Promise} Promise resolved with current section.
*/
getCurrentSection(course: any, sections: any[]): Promise {
+
// Convert the result to a Promise if it isn't.
return Promise.resolve(this.executeFunctionOnEnabled(course.format, 'getCurrentSection', [course, sections])).catch(() => {
- // This function should never fail. Just return the first section.
- if (sections[0].id != CoreCourseProvider.ALL_SECTIONS_ID) {
- return sections[0];
- }
-
- return sections[1];
+ // This function should never fail. Just return all the sections.
+ return sections[0];
});
}
diff --git a/src/core/courses/pages/search/search.html b/src/core/courses/pages/search/search.html
index 875eb16fb..0174eb683 100644
--- a/src/core/courses/pages/search/search.html
+++ b/src/core/courses/pages/search/search.html
@@ -10,9 +10,7 @@
{{ 'core.courses.totalcoursesearchresults' | translate:{$a: total} }}
-
-
-
+
diff --git a/src/core/courses/pages/search/search.ts b/src/core/courses/pages/search/search.ts
index 43c988d3d..38607e129 100644
--- a/src/core/courses/pages/search/search.ts
+++ b/src/core/courses/pages/search/search.ts
@@ -54,11 +54,11 @@ export class CoreCoursesSearchPage {
/**
* Load more results.
*
- * @param {any} infiniteScroll The infinit scroll instance.
+ * @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
*/
- loadMoreResults(infiniteScroll: any): void {
+ loadMoreResults(infiniteComplete?: any): void {
this.searchCourses().finally(() => {
- infiniteScroll.complete();
+ infiniteComplete && infiniteComplete();
});
}
diff --git a/src/core/courses/providers/courses.ts b/src/core/courses/providers/courses.ts
index b1adb7cb6..bf5345fb1 100644
--- a/src/core/courses/providers/courses.ts
+++ b/src/core/courses/providers/courses.ts
@@ -390,6 +390,7 @@ export class CoreCoursesProvider {
* @param {any} [value] The value to match.
* @param {string} [siteId] Site ID. If not defined, use current site.
* @return {Promise} Promise resolved with the courses.
+ * @since 3.2
*/
getCoursesByField(field?: string, value?: any, siteId?: string): Promise {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
@@ -473,6 +474,7 @@ export class CoreCoursesProvider {
* Check if get courses by field WS is available.
*
* @return {boolean} Whether get courses by field is available.
+ * @since 3.2
*/
isGetCoursesByFieldAvailable(): boolean {
return this.sitesProvider.wsAvailableInCurrentSite('core_course_get_courses_by_field');
diff --git a/src/core/user/components/participants/core-user-participants.html b/src/core/user/components/participants/core-user-participants.html
index 266a79210..287c76baa 100644
--- a/src/core/user/components/participants/core-user-participants.html
+++ b/src/core/user/components/participants/core-user-participants.html
@@ -16,10 +16,7 @@