diff --git a/scripts/langindex.json b/scripts/langindex.json
index 7381c6fc8..5abbddcb4 100644
--- a/scripts/langindex.json
+++ b/scripts/langindex.json
@@ -1231,6 +1231,7 @@
"core.answered": "quiz",
"core.areyousure": "moodle",
"core.back": "moodle",
+ "core.block.blocks": "moodle",
"core.cancel": "moodle",
"core.cannotconnect": "local_moodlemobileapp",
"core.cannotdownloadfiles": "local_moodlemobileapp",
diff --git a/src/assets/lang/en.json b/src/assets/lang/en.json
index 7ed0d4812..7608fe277 100644
--- a/src/assets/lang/en.json
+++ b/src/assets/lang/en.json
@@ -1231,6 +1231,7 @@
"core.answered": "Answered",
"core.areyousure": "Are you sure?",
"core.back": "Back",
+ "core.block.blocks": "Blocks",
"core.cancel": "Cancel",
"core.cannotconnect": "Cannot connect: Verify that you have correctly typed the URL and that your site uses Moodle 2.4 or later.",
"core.cannotdownloadfiles": "File downloading is disabled. Please contact your site administrator.",
diff --git a/src/core/block/block.module.ts b/src/core/block/block.module.ts
index 2448c6e1d..764d27fb9 100644
--- a/src/core/block/block.module.ts
+++ b/src/core/block/block.module.ts
@@ -15,6 +15,9 @@
import { NgModule } from '@angular/core';
import { CoreBlockDelegate } from './providers/delegate';
import { CoreBlockDefaultHandler } from './providers/default-block-handler';
+import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
+import { CoreBlockCourseBlocksCourseOptionHandler } from './providers/course-option-handler';
+import { CoreBlockComponentsModule } from './components/components.module';
// List of providers (without handlers).
export const CORE_BLOCK_PROVIDERS: any[] = [
@@ -24,11 +27,18 @@ export const CORE_BLOCK_PROVIDERS: any[] = [
@NgModule({
declarations: [],
imports: [
+ CoreBlockComponentsModule
],
providers: [
CoreBlockDelegate,
- CoreBlockDefaultHandler
+ CoreBlockDefaultHandler,
+ CoreBlockCourseBlocksCourseOptionHandler
],
exports: []
})
-export class CoreBlockModule {}
+export class CoreBlockModule {
+ constructor(courseOptionHandler: CoreBlockCourseBlocksCourseOptionHandler,
+ courseOptionsDelegate: CoreCourseOptionsDelegate) {
+ courseOptionsDelegate.registerHandler(courseOptionHandler);
+ }
+}
diff --git a/src/core/block/components/components.module.ts b/src/core/block/components/components.module.ts
index 896804473..33c80abcf 100644
--- a/src/core/block/components/components.module.ts
+++ b/src/core/block/components/components.module.ts
@@ -19,12 +19,14 @@ import { TranslateModule } from '@ngx-translate/core';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CoreBlockComponent } from './block/block';
import { CoreBlockOnlyTitleComponent } from './only-title-block/only-title-block';
+import { CoreBlockCourseBlocksComponent } from './course-blocks/course-blocks';
import { CoreComponentsModule } from '@components/components.module';
@NgModule({
declarations: [
CoreBlockComponent,
- CoreBlockOnlyTitleComponent
+ CoreBlockOnlyTitleComponent,
+ CoreBlockCourseBlocksComponent
],
imports: [
CommonModule,
@@ -37,10 +39,12 @@ import { CoreComponentsModule } from '@components/components.module';
],
exports: [
CoreBlockComponent,
- CoreBlockOnlyTitleComponent
+ CoreBlockOnlyTitleComponent,
+ CoreBlockCourseBlocksComponent
],
entryComponents: [
- CoreBlockOnlyTitleComponent
+ CoreBlockOnlyTitleComponent,
+ CoreBlockCourseBlocksComponent
]
})
export class CoreBlockComponentsModule {}
diff --git a/src/core/block/components/course-blocks/core-block-course-blocks.html b/src/core/block/components/course-blocks/core-block-course-blocks.html
new file mode 100644
index 000000000..cf9457d58
--- /dev/null
+++ b/src/core/block/components/course-blocks/core-block-course-blocks.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/core/block/components/course-blocks/course-blocks.ts b/src/core/block/components/course-blocks/course-blocks.ts
new file mode 100644
index 000000000..8adbb5e4e
--- /dev/null
+++ b/src/core/block/components/course-blocks/course-blocks.ts
@@ -0,0 +1,100 @@
+// (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, ViewChildren, Input, OnInit, QueryList } from '@angular/core';
+import { CoreDomUtilsProvider } from '@providers/utils/dom';
+import { CoreBlockComponent } from '../block/block';
+import { CoreBlockDelegate } from '../../providers/delegate';
+import { CoreCourseProvider } from '@core/course/providers/course';
+
+/**
+ * Component that displays the list of course blocks.
+ */
+@Component({
+ selector: 'core-block-course-blocks',
+ templateUrl: 'core-block-course-blocks.html',
+})
+export class CoreBlockCourseBlocksComponent implements OnInit {
+
+ @Input() courseId: number;
+
+ @ViewChildren(CoreBlockComponent) blocksComponents: QueryList;
+
+ dataLoaded = false;
+ hasContent: boolean;
+ hasSupportedBlock: boolean;
+ blocks = [];
+
+ constructor(private domUtils: CoreDomUtilsProvider, private courseProvider: CoreCourseProvider,
+ private blockDelegate: CoreBlockDelegate) {
+ }
+
+ /**
+ * Component being initialized.
+ */
+ ngOnInit(): void {
+ this.loadContent().finally(() => {
+ this.dataLoaded = true;
+ });
+ }
+
+ /**
+ * Refresh the data.
+ *
+ * @param {any} refresher Refresher.
+ */
+ doRefresh(refresher: any): void {
+ const promises = [];
+
+ if (this.courseProvider.canGetCourseBlocks()) {
+ promises.push(this.courseProvider.invalidateCourseBlocks(this.courseId));
+ }
+
+ // Invalidate the blocks.
+ this.blocksComponents.forEach((blockComponent) => {
+ promises.push(blockComponent.invalidate().catch(() => {
+ // Ignore errors.
+ }));
+ });
+
+ Promise.all(promises).finally(() => {
+ this.loadContent().finally(() => {
+ refresher.complete();
+ });
+ });
+ }
+
+ /**
+ * Convenience function to fetch the data.
+ *
+ * @return {Promise} Promise resolved when done.
+ */
+ protected loadContent(): Promise {
+ // Get site home blocks.
+ const canGetBlocks = this.courseProvider.canGetCourseBlocks(),
+ promise = canGetBlocks ? this.courseProvider.getCourseBlocks(this.courseId) : Promise.reject(null);
+
+ return promise.then((blocks) => {
+ this.blocks = blocks;
+ this.hasSupportedBlock = this.blockDelegate.hasSupportedBlock(blocks);
+
+ }).catch((error) => {
+ if (canGetBlocks) {
+ this.domUtils.showErrorModal(error);
+ }
+ this.blocks = [];
+ });
+
+ }
+}
diff --git a/src/core/block/lang/en.json b/src/core/block/lang/en.json
new file mode 100644
index 000000000..9b136b8ee
--- /dev/null
+++ b/src/core/block/lang/en.json
@@ -0,0 +1,3 @@
+{
+ "blocks": "Blocks"
+}
\ No newline at end of file
diff --git a/src/core/block/providers/course-option-handler.ts b/src/core/block/providers/course-option-handler.ts
new file mode 100644
index 000000000..c7e298c9c
--- /dev/null
+++ b/src/core/block/providers/course-option-handler.ts
@@ -0,0 +1,88 @@
+// (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 { Injectable, Injector } from '@angular/core';
+import { CoreCourseOptionsHandler, CoreCourseOptionsHandlerData } from '@core/course/providers/options-delegate';
+import { CoreCourseProvider } from '@core/course/providers/course';
+import { CoreBlockCourseBlocksComponent } from '../components/course-blocks/course-blocks';
+
+/**
+ * Course nav handler.
+ */
+@Injectable()
+export class CoreBlockCourseBlocksCourseOptionHandler implements CoreCourseOptionsHandler {
+ name = 'CoreCourseBlocks';
+ priority = 700;
+
+ constructor(private courseProvider: CoreCourseProvider) {}
+
+ /**
+ * Should invalidate the data to determine if the handler is enabled for a certain course.
+ *
+ * @param {number} courseId The course ID.
+ * @param {any} [navOptions] Course navigation options for current user. See CoreCoursesProvider.getUserNavigationOptions.
+ * @param {any} [admOptions] Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions.
+ * @return {Promise} Promise resolved when done.
+ */
+ invalidateEnabledForCourse(courseId: number, navOptions?: any, admOptions?: any): Promise {
+ return this.courseProvider.invalidateCourseBlocks(courseId);
+ }
+
+ /**
+ * Check if the handler is enabled on a site level.
+ *
+ * @return {boolean} Whether or not the handler is enabled on a site level.
+ */
+ isEnabled(): boolean | Promise {
+ return this.courseProvider.canGetCourseBlocks();
+ }
+
+ /**
+ * Whether or not the handler is enabled for a certain course.
+ *
+ * @param {number} courseId The course ID.
+ * @param {any} accessData Access type and data. Default, guest, ...
+ * @param {any} [navOptions] Course navigation options for current user. See CoreCoursesProvider.getUserNavigationOptions.
+ * @param {any} [admOptions] Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions.
+ * @return {boolean|Promise} True or promise resolved with true if enabled.
+ */
+ isEnabledForCourse(courseId: number, accessData: any, navOptions?: any, admOptions?: any): boolean | Promise {
+ return true;
+ }
+
+ /**
+ * Returns the data needed to render the handler.
+ *
+ * @param {Injector} injector Injector.
+ * @param {number} courseId The course ID.
+ * @return {CoreCourseOptionsHandlerData|Promise} Data or promise resolved with the data.
+ */
+ getDisplayData(injector: Injector, courseId: number): CoreCourseOptionsHandlerData | Promise {
+ return {
+ title: 'core.block.blocks',
+ class: 'core-course-blocks-handler',
+ component: CoreBlockCourseBlocksComponent
+ };
+ }
+
+ /**
+ * Called when a course is downloaded. It should prefetch all the data to be able to see the addon in offline.
+ *
+ * @param {any} course The course.
+ * @return {Promise} Promise resolved when done.
+ */
+ prefetch(course: any): Promise {
+ return this.courseProvider.getCourseBlocks(course.id);
+ }
+}