diff --git a/src/core/courses/pages/available-courses/available-courses.html b/src/core/courses/pages/available-courses/available-courses.html new file mode 100644 index 000000000..91579ff3f --- /dev/null +++ b/src/core/courses/pages/available-courses/available-courses.html @@ -0,0 +1,16 @@ + + + {{ 'core.courses.availablecourses' | translate }} + + + + + + + +
+ +
+ +
+
diff --git a/src/core/courses/pages/available-courses/available-courses.module.ts b/src/core/courses/pages/available-courses/available-courses.module.ts new file mode 100644 index 000000000..5fb00ab0a --- /dev/null +++ b/src/core/courses/pages/available-courses/available-courses.module.ts @@ -0,0 +1,33 @@ +// (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 { NgModule } from '@angular/core'; +import { IonicPageModule } from 'ionic-angular'; +import { TranslateModule } from '@ngx-translate/core'; +import { CoreCoursesAvailableCoursesPage } from './available-courses'; +import { CoreComponentsModule } from '../../../../components/components.module'; +import { CoreCoursesComponentsModule } from '../../components/components.module'; + +@NgModule({ + declarations: [ + CoreCoursesAvailableCoursesPage, + ], + imports: [ + CoreComponentsModule, + CoreCoursesComponentsModule, + IonicPageModule.forChild(CoreCoursesAvailableCoursesPage), + TranslateModule.forChild() + ], +}) +export class CoreCoursesAvailableCoursesPageModule {} diff --git a/src/core/courses/pages/available-courses/available-courses.ts b/src/core/courses/pages/available-courses/available-courses.ts new file mode 100644 index 000000000..47d71babf --- /dev/null +++ b/src/core/courses/pages/available-courses/available-courses.ts @@ -0,0 +1,76 @@ +// (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 } from '@angular/core'; +import { IonicPage } from 'ionic-angular'; +import { CoreSitesProvider } from '../../../../providers/sites'; +import { CoreDomUtilsProvider } from '../../../../providers/utils/dom'; +import { CoreCoursesProvider } from '../../providers/courses'; + +/** + * Page that displays available courses in current site. + */ +@IonicPage() +@Component({ + selector: 'page-core-courses-available-courses', + templateUrl: 'available-courses.html', +}) +export class CoreCoursesAvailableCoursesPage { + courses: any[] = []; + coursesLoaded: boolean; + + constructor(private coursesProvider: CoreCoursesProvider, private domUtils: CoreDomUtilsProvider, + private sitesProvider: CoreSitesProvider) {} + + /** + * View loaded. + */ + ionViewDidLoad() { + this.loadCourses().finally(() => { + this.coursesLoaded = true; + }); + } + + /** + * Load the courses. + */ + protected loadCourses() { + const frontpageCourseId = this.sitesProvider.getCurrentSite().getSiteHomeId(); + return this.coursesProvider.getCoursesByField().then((courses) => { + this.courses = courses.filter((course) => { + return course.id != frontpageCourseId; + }); + }).catch((error) => { + this.domUtils.showErrorModalDefault(error, 'core.courses.errorloadcourses', true); + }); + } + + /** + * Refresh the courses. + * + * @param {any} refresher Refresher. + */ + refreshCourses(refresher: any) { + let promises = []; + + promises.push(this.coursesProvider.invalidateUserCourses()); + promises.push(this.coursesProvider.invalidateCoursesByField()); + + Promise.all(promises).finally(() => { + this.loadCourses().finally(() => { + refresher.complete(); + }); + }); + }; +} diff --git a/src/core/courses/pages/categories/categories.html b/src/core/courses/pages/categories/categories.html new file mode 100644 index 000000000..c22dfe194 --- /dev/null +++ b/src/core/courses/pages/categories/categories.html @@ -0,0 +1,39 @@ + + + + + + + + + + + + +

+
+ + + + +
+ {{ 'core.courses.categories' | translate }} +
+ + +

+ {{category.coursecount}} + +
+
+
+ +
+ {{ 'core.courses.courses' | translate }} + +
+ +

{{ 'core.courses.searchcoursesadvice' | translate }}

+
+
+
diff --git a/src/core/courses/pages/categories/categories.module.ts b/src/core/courses/pages/categories/categories.module.ts new file mode 100644 index 000000000..3033dc219 --- /dev/null +++ b/src/core/courses/pages/categories/categories.module.ts @@ -0,0 +1,35 @@ +// (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 { NgModule } from '@angular/core'; +import { IonicPageModule } from 'ionic-angular'; +import { TranslateModule } from '@ngx-translate/core'; +import { CoreCoursesCategoriesPage } from './categories'; +import { CoreComponentsModule } from '../../../../components/components.module'; +import { CoreDirectivesModule } from '../../../../directives/directives.module'; +import { CoreCoursesComponentsModule } from '../../components/components.module'; + +@NgModule({ + declarations: [ + CoreCoursesCategoriesPage, + ], + imports: [ + CoreComponentsModule, + CoreCoursesComponentsModule, + CoreDirectivesModule, + IonicPageModule.forChild(CoreCoursesCategoriesPage), + TranslateModule.forChild() + ], +}) +export class CoreCoursesCategoriesPageModule {} diff --git a/src/core/courses/pages/categories/categories.ts b/src/core/courses/pages/categories/categories.ts new file mode 100644 index 000000000..2253fc17a --- /dev/null +++ b/src/core/courses/pages/categories/categories.ts @@ -0,0 +1,122 @@ +// (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 } from '@angular/core'; +import { IonicPage, NavController, NavParams } from 'ionic-angular'; +import { TranslateService } from '@ngx-translate/core'; +import { CoreSitesProvider } from '../../../../providers/sites'; +import { CoreDomUtilsProvider } from '../../../../providers/utils/dom'; +import { CoreUtilsProvider } from '../../../../providers/utils/utils'; +import { CoreCoursesProvider } from '../../providers/courses'; + +/** + * Page that displays a list of categories and the courses in the current category if any. + */ +@IonicPage() +@Component({ + selector: 'page-core-courses-categories', + templateUrl: 'categories.html', +}) +export class CoreCoursesCategoriesPage { + title: string; + currentCategory: any; + categories: any[] = []; + courses: any[] = []; + categoriesLoaded: boolean; + + protected categoryId: number; + + constructor(private navCtrl: NavController, navParams: NavParams, private coursesProvider: CoreCoursesProvider, + private domUtils: CoreDomUtilsProvider, private utils: CoreUtilsProvider, translate: TranslateService, + private sitesProvider: CoreSitesProvider) { + this.categoryId = navParams.get('categoryId') || 0; + this.title = translate.instant('core.courses.categories'); + } + + /** + * View loaded. + */ + ionViewDidLoad() { + this.fetchCategories().finally(() => { + this.categoriesLoaded = true; + }); + } + + /** + * Fetch the categories. + */ + protected fetchCategories() { + return this.coursesProvider.getCategories(this.categoryId, true).then((cats) => { + this.currentCategory = undefined; + + cats.forEach((cat, index) => { + if (cat.id == this.categoryId) { + this.currentCategory = cat; + // Delete current Category to avoid problems with the formatTree. + delete cats[index]; + } + }); + + // Sort by depth and sortorder to avoid problems formatting Tree. + cats.sort((a,b) => { + if (a.depth == b.depth) { + return (a.sortorder > b.sortorder) ? 1 : ((b.sortorder > a.sortorder) ? -1 : 0); + } + return a.depth > b.depth ? 1 : -1; + }); + + this.categories = this.utils.formatTree(cats, 'parent', 'id', this.categoryId); + + if (this.currentCategory) { + this.title = this.currentCategory.name; + + return this.coursesProvider.getCoursesByField('category', this.categoryId).then((courses) => { + this.courses = courses; + }).catch((error) => { + this.domUtils.showErrorModalDefault(error, 'core.courses.errorloadcourses', true); + }); + } + }).catch((error) => { + this.domUtils.showErrorModalDefault(error, 'core.courses.errorloadcategories', true); + }); + } + + /** + * Refresh the categories. + * + * @param {any} refresher Refresher. + */ + refreshCategories(refresher: any) { + let promises = []; + + promises.push(this.coursesProvider.invalidateUserCourses()); + promises.push(this.coursesProvider.invalidateCategories(this.categoryId, true)); + promises.push(this.coursesProvider.invalidateCoursesByField('category', this.categoryId)); + promises.push(this.sitesProvider.getCurrentSite().invalidateConfig()); + + Promise.all(promises).finally(() => { + this.fetchCategories().finally(() => { + refresher.complete(); + }); + }); + } + /** + * Open a category. + * + * @param {number} categoryId The category ID. + */ + openCategory(categoryId: number) { + this.navCtrl.push('CoreCoursesCategoriesPage', {categoryId: categoryId}); + } +} diff --git a/src/directives/format-text.ts b/src/directives/format-text.ts index 96097e12f..2d1dd2c12 100644 --- a/src/directives/format-text.ts +++ b/src/directives/format-text.ts @@ -151,6 +151,7 @@ export class CoreFormatTextDirective implements OnChanges { */ protected formatAndRenderContents() : void { if (!this.text) { + this.element.innerHTML = ''; // Remove current contents. this.finishRender(); return; } @@ -158,6 +159,8 @@ export class CoreFormatTextDirective implements OnChanges { this.text = this.text.trim(); this.formatContents().then((div: HTMLElement) => { + this.element.innerHTML = ''; // Remove current contents. + if (this.maxHeight && div.innerHTML != "") { // Move the children to the current element to be able to calculate the height. // @todo: Display the element?