diff --git a/scripts/langindex.json b/scripts/langindex.json index 16b3340f6..85fab7159 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -10,6 +10,7 @@ "addon.badges.issuername": "badges", "addon.badges.nobadges": "badges", "addon.badges.recipientdetails": "badges", + "addon.block_activitymodules.pluginname": "block_activity_modules", "addon.block_myoverview.all": "block_myoverview", "addon.block_myoverview.future": "block_myoverview", "addon.block_myoverview.inprogress": "block_myoverview", @@ -20,6 +21,7 @@ "addon.block_myoverview.nocoursespast": "block_myoverview", "addon.block_myoverview.past": "block_myoverview", "addon.block_myoverview.title": "block_myoverview", + "addon.block_sitemainmenu.pluginname": "block_site_main_menu", "addon.block_timeline.duedate": "block_timeline", "addon.block_timeline.next30days": "block_timeline", "addon.block_timeline.next3months": "block_timeline", @@ -202,6 +204,7 @@ "addon.mod_assign.markingworkflowstatereadyforrelease": "assign", "addon.mod_assign.markingworkflowstatereadyforreview": "assign", "addon.mod_assign.markingworkflowstatereleased": "assign", + "addon.mod_assign.modulenameplural": "assign", "addon.mod_assign.multipleteams": "assign", "addon.mod_assign.multipleteams_desc": "assign", "addon.mod_assign.noattempt": "assign", @@ -256,6 +259,7 @@ "addon.mod_assign_submission_file.pluginname": "assignsubmission_file", "addon.mod_assign_submission_onlinetext.pluginname": "assignsubmission_onlinetext", "addon.mod_book.errorchapter": "book", + "addon.mod_book.modulenameplural": "book", "addon.mod_chat.beep": "chat", "addon.mod_chat.currentusers": "chat", "addon.mod_chat.enterchat": "chat", @@ -268,6 +272,7 @@ "addon.mod_chat.messagebeepsyou": "chat", "addon.mod_chat.messageenter": "chat", "addon.mod_chat.messageexit": "chat", + "addon.mod_chat.modulenameplural": "chat", "addon.mod_chat.mustbeonlinetosendmessages": "local_moodlemobileapp", "addon.mod_chat.nomessages": "chat", "addon.mod_chat.send": "chat", @@ -278,6 +283,7 @@ "addon.mod_choice.errorgetchoice": "local_moodlemobileapp", "addon.mod_choice.expired": "choice", "addon.mod_choice.full": "choice", + "addon.mod_choice.modulenameplural": "choice", "addon.mod_choice.noresultsviewable": "choice", "addon.mod_choice.notopenyet": "choice", "addon.mod_choice.numberofuser": "choice", @@ -317,6 +323,7 @@ "addon.mod_data.fields": "data", "addon.mod_data.latlongboth": "data", "addon.mod_data.menuchoose": "data", + "addon.mod_data.modulenameplural": "data", "addon.mod_data.more": "data", "addon.mod_data.nomatch": "data", "addon.mod_data.norecords": "data", @@ -348,6 +355,7 @@ "addon.mod_feedback.feedbackopen": "feedback", "addon.mod_feedback.mapcourses": "feedback", "addon.mod_feedback.mode": "feedback", + "addon.mod_feedback.modulenameplural": "feedback", "addon.mod_feedback.next_page": "feedback", "addon.mod_feedback.non_anonymous": "feedback", "addon.mod_feedback.non_anonymous_entries": "feedback", @@ -368,6 +376,7 @@ "addon.mod_feedback.started": "feedback", "addon.mod_feedback.this_feedback_is_already_submitted": "feedback", "addon.mod_folder.emptyfilelist": "local_moodlemobileapp", + "addon.mod_folder.modulenameplural": "folder", "addon.mod_forum.addanewdiscussion": "forum", "addon.mod_forum.addanewquestion": "forum", "addon.mod_forum.addanewtopic": "forum", @@ -390,6 +399,7 @@ "addon.mod_forum.modeflatnewestfirst": "forum", "addon.mod_forum.modeflatoldestfirst": "forum", "addon.mod_forum.modenested": "forum", + "addon.mod_forum.modulenameplural": "forum", "addon.mod_forum.numdiscussions": "local_moodlemobileapp", "addon.mod_forum.numreplies": "local_moodlemobileapp", "addon.mod_forum.posttoforum": "forum", @@ -425,9 +435,11 @@ "addon.mod_glossary.fillfields": "glossary", "addon.mod_glossary.fullmatch": "glossary", "addon.mod_glossary.linking": "glossary", + "addon.mod_glossary.modulenameplural": "glossary", "addon.mod_glossary.noentriesfound": "local_moodlemobileapp", "addon.mod_glossary.searchquery": "local_moodlemobileapp", "addon.mod_imscp.deploymenterror": "imscp", + "addon.mod_imscp.modulenameplural": "imscp", "addon.mod_imscp.showmoduledescription": "local_moodlemobileapp", "addon.mod_lesson.answer": "lesson", "addon.mod_lesson.attempt": "lesson", @@ -471,6 +483,7 @@ "addon.mod_lesson.lowtime": "lesson", "addon.mod_lesson.maximumnumberofattemptsreached": "lesson", "addon.mod_lesson.modattemptsnoteacher": "lesson", + "addon.mod_lesson.modulenameplural": "lesson", "addon.mod_lesson.noanswer": "lesson", "addon.mod_lesson.nolessonattempts": "lesson", "addon.mod_lesson.nolessonattemptsgroup": "lesson", @@ -515,7 +528,9 @@ "addon.mod_lti.errorgetlti": "local_moodlemobileapp", "addon.mod_lti.errorinvalidlaunchurl": "local_moodlemobileapp", "addon.mod_lti.launchactivity": "local_moodlemobileapp", + "addon.mod_lti.modulenameplural": "lti", "addon.mod_page.errorwhileloadingthepage": "local_moodlemobileapp", + "addon.mod_page.modulenameplural": "page", "addon.mod_quiz.attemptfirst": "quiz", "addon.mod_quiz.attemptlast": "quiz", "addon.mod_quiz.attemptnumber": "quiz", @@ -550,6 +565,7 @@ "addon.mod_quiz.grademethod": "quiz", "addon.mod_quiz.gradesofar": "quiz", "addon.mod_quiz.marks": "quiz", + "addon.mod_quiz.modulenameplural": "quiz", "addon.mod_quiz.mustbesubmittedby": "quiz", "addon.mod_quiz.noquestions": "quiz", "addon.mod_quiz.noreviewattempt": "quiz", @@ -594,6 +610,7 @@ "addon.mod_quiz.yourfinalgradeis": "quiz", "addon.mod_resource.errorwhileloadingthecontent": "local_moodlemobileapp", "addon.mod_resource.modifieddate": "resource", + "addon.mod_resource.modulenameplural": "resource", "addon.mod_resource.openthefile": "local_moodlemobileapp", "addon.mod_resource.uploadeddate": "resource", "addon.mod_scorm.asset": "scorm", @@ -630,6 +647,7 @@ "addon.mod_scorm.incomplete": "scorm", "addon.mod_scorm.lastattempt": "scorm", "addon.mod_scorm.mode": "scorm", + "addon.mod_scorm.modulenameplural": "scorm", "addon.mod_scorm.newattempt": "scorm", "addon.mod_scorm.noattemptsallowed": "scorm", "addon.mod_scorm.noattemptsmade": "scorm", @@ -649,10 +667,12 @@ "addon.mod_survey.errorgetsurvey": "local_moodlemobileapp", "addon.mod_survey.ifoundthat": "survey", "addon.mod_survey.ipreferthat": "survey", + "addon.mod_survey.modulenameplural": "survey", "addon.mod_survey.responses": "survey", "addon.mod_survey.results": "local_moodlemobileapp", "addon.mod_survey.surveycompletednograph": "survey", "addon.mod_url.accessurl": "local_moodlemobileapp", + "addon.mod_url.modulenameplural": "url", "addon.mod_url.pointingtourl": "local_moodlemobileapp", "addon.mod_wiki.cannoteditpage": "wiki", "addon.mod_wiki.createpage": "wiki", @@ -661,6 +681,7 @@ "addon.mod_wiki.errornowikiavailable": "local_moodlemobileapp", "addon.mod_wiki.gowikihome": "local_moodlemobileapp", "addon.mod_wiki.map": "wiki", + "addon.mod_wiki.modulenameplural": "wiki", "addon.mod_wiki.newpagehdr": "wiki", "addon.mod_wiki.newpagetitle": "wiki", "addon.mod_wiki.nocontent": "wiki", @@ -699,6 +720,7 @@ "addon.mod_workshop.gradinggradecalculated": "workshop", "addon.mod_workshop.gradinggradeof": "workshop", "addon.mod_workshop.gradinggradeover": "workshop", + "addon.mod_workshop.modulenameplural": "workshop", "addon.mod_workshop.nogradeyet": "workshop", "addon.mod_workshop.notassessed": "workshop", "addon.mod_workshop.notoverridden": "workshop", @@ -1467,6 +1489,7 @@ "core.refresh": "moodle", "core.required": "moodle", "core.requireduserdatamissing": "local_moodlemobileapp", + "core.resources": "moodle", "core.restore": "moodle", "core.retry": "local_moodlemobileapp", "core.save": "moodle", diff --git a/src/addon/block/activitymodules/activitymodules.module.ts b/src/addon/block/activitymodules/activitymodules.module.ts new file mode 100644 index 000000000..88fbb6e06 --- /dev/null +++ b/src/addon/block/activitymodules/activitymodules.module.ts @@ -0,0 +1,44 @@ +// (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 { IonicModule } from 'ionic-angular'; +import { TranslateModule } from '@ngx-translate/core'; +import { CoreComponentsModule } from '@components/components.module'; +import { CoreDirectivesModule } from '@directives/directives.module'; +import { AddonBlockActivityModulesComponentsModule } from './components/components.module'; +import { CoreBlockDelegate } from '@core/block/providers/delegate'; +import { AddonBlockActivityModulesHandler } from './providers/block-handler'; + +@NgModule({ + declarations: [ + ], + imports: [ + IonicModule, + CoreComponentsModule, + CoreDirectivesModule, + AddonBlockActivityModulesComponentsModule, + TranslateModule.forChild() + ], + exports: [ + ], + providers: [ + AddonBlockActivityModulesHandler + ] +}) +export class AddonBlockActivityModulesModule { + constructor(blockDelegate: CoreBlockDelegate, blockHandler: AddonBlockActivityModulesHandler) { + blockDelegate.registerHandler(blockHandler); + } +} diff --git a/src/addon/block/activitymodules/components/activitymodules/activitymodules.scss b/src/addon/block/activitymodules/components/activitymodules/activitymodules.scss new file mode 100644 index 000000000..cc70ceb22 --- /dev/null +++ b/src/addon/block/activitymodules/components/activitymodules/activitymodules.scss @@ -0,0 +1,26 @@ +ion-app.app-root.md addon-block-activitymodules { + .core-module-icon { + margin-top: $label-md-margin-top; + margin-bottom: $label-md-margin-bottom; + width: 24px; + height: 24px; + } +} + +ion-app.app-root.ios addon-block-activitymodules { + .core-module-icon { + margin-top: $label-ios-margin-top; + margin-bottom: $label-ios-margin-bottom; + width: 24px; + height: 24px; + } +} + +ion-app.app-root.wp addon-block-activitymodules { + .core-module-icon { + margin-top: $item-wp-padding-top; + margin-bottom: $item-wp-padding-bottom; + width: 24px; + height: 24px; + } +} diff --git a/src/addon/block/activitymodules/components/activitymodules/activitymodules.ts b/src/addon/block/activitymodules/components/activitymodules/activitymodules.ts new file mode 100644 index 000000000..9e5519b4a --- /dev/null +++ b/src/addon/block/activitymodules/components/activitymodules/activitymodules.ts @@ -0,0 +1,124 @@ +// (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, OnInit, Injector, Input } from '@angular/core'; +import { CoreUtilsProvider } from '@providers/utils/utils'; +import { CoreCourseProvider } from '@core/course/providers/course'; +import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate'; +import { CoreBlockBaseComponent } from '@core/block/classes/base-block-component'; +import { CoreConstants } from '@core/constants'; +import { TranslateService } from '@ngx-translate/core'; + +/** + * Component to render an "activity modules" block. + */ +@Component({ + selector: 'addon-block-activitymodules', + templateUrl: 'addon-block-activitymodules.html' +}) +export class AddonBlockActivityModulesComponent extends CoreBlockBaseComponent implements OnInit { + @Input() block: any; // The block to render. + @Input() contextLevel: string; // The context where the block will be used. + @Input() instanceId: number; // The instance ID associated with the context level. + + entries: any[] = []; + + protected fetchContentDefaultError = 'Error getting activity modules data.'; + + constructor(injector: Injector, protected utils: CoreUtilsProvider, protected courseProvider: CoreCourseProvider, + protected translate: TranslateService, protected moduleDelegate: CoreCourseModuleDelegate) { + + super(injector, 'AddonBlockActivityModulesComponent'); + } + + /** + * Component being initialized. + */ + ngOnInit(): void { + super.ngOnInit(); + } + + /** + * Perform the invalidate content function. + * + * @return {Promise} Resolved when done. + */ + protected invalidateContent(): Promise { + return this.courseProvider.invalidateSections(this.instanceId); + } + + /** + * Fetch the data to render the block. + * + * @return {Promise} Promise resolved when done. + */ + protected fetchContent(): Promise { + return this.courseProvider.getSections(this.instanceId, false, true).then((sections) => { + + this.entries = []; + + const archetypes = {}; + let modFullNames = {}; + + sections.forEach((section) => { + if (!section.modules) { + return; + } + + section.modules.forEach((mod) => { + if (mod.uservisible === false || !this.courseProvider.moduleHasView(mod) || + typeof modFullNames[mod.modname] != 'undefined') { + // Ignore this module. + return; + } + + // Get the archetype of the module type. + if (typeof archetypes[mod.modname] == 'undefined') { + archetypes[mod.modname] = this.moduleDelegate.supportsFeature(mod.modname, + CoreConstants.FEATURE_MOD_ARCHETYPE, CoreConstants.MOD_ARCHETYPE_OTHER); + } + + // Get the full name of the module type. + if (archetypes[mod.modname] == CoreConstants.MOD_ARCHETYPE_RESOURCE) { + // All resources are gathered in a single "Resources" option. + if (!modFullNames['resources']) { + modFullNames['resources'] = this.translate.instant('core.resources'); + } + } else { + modFullNames[mod.modname] = mod.modplural; + } + }); + }); + + // Sort the modnames alphabetically. + modFullNames = this.utils.sortValues(modFullNames); + + for (const modName in modFullNames) { + let icon; + + if (modName === 'resources') { + icon = this.courseProvider.getModuleIconSrc('page'); + } else { + icon = this.moduleDelegate.getModuleIconSrc(modName); + } + + this.entries.push({ + icon: icon, + name: modFullNames[modName], + modName: modName + }); + } + }); + } +} diff --git a/src/addon/block/activitymodules/components/activitymodules/addon-block-activitymodules.html b/src/addon/block/activitymodules/components/activitymodules/addon-block-activitymodules.html new file mode 100644 index 000000000..1692ba8d2 --- /dev/null +++ b/src/addon/block/activitymodules/components/activitymodules/addon-block-activitymodules.html @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/addon/block/activitymodules/components/components.module.ts b/src/addon/block/activitymodules/components/components.module.ts new file mode 100644 index 000000000..5cbc4cfd4 --- /dev/null +++ b/src/addon/block/activitymodules/components/components.module.ts @@ -0,0 +1,45 @@ +// (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 { CommonModule } from '@angular/common'; +import { IonicModule } from 'ionic-angular'; +import { TranslateModule } from '@ngx-translate/core'; +import { AddonBlockActivityModulesComponent } from './activitymodules/activitymodules'; +import { CoreComponentsModule } from '@components/components.module'; +import { CoreDirectivesModule } from '@directives/directives.module'; +import { CoreCourseComponentsModule } from '@core/course/components/components.module'; + +@NgModule({ + declarations: [ + AddonBlockActivityModulesComponent + ], + imports: [ + CommonModule, + IonicModule, + TranslateModule.forChild(), + CoreComponentsModule, + CoreDirectivesModule, + CoreCourseComponentsModule + ], + providers: [ + ], + exports: [ + AddonBlockActivityModulesComponent + ], + entryComponents: [ + AddonBlockActivityModulesComponent + ] +}) +export class AddonBlockActivityModulesComponentsModule {} diff --git a/src/addon/block/activitymodules/lang/en.json b/src/addon/block/activitymodules/lang/en.json new file mode 100644 index 000000000..7f1c7ab21 --- /dev/null +++ b/src/addon/block/activitymodules/lang/en.json @@ -0,0 +1,3 @@ +{ + "pluginname": "Activities" +} diff --git a/src/addon/block/activitymodules/providers/block-handler.ts b/src/addon/block/activitymodules/providers/block-handler.ts new file mode 100644 index 000000000..df211ecec --- /dev/null +++ b/src/addon/block/activitymodules/providers/block-handler.ts @@ -0,0 +1,58 @@ +// (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 { CoreBlockHandler, CoreBlockHandlerData } from '@core/block/providers/delegate'; +import { AddonBlockActivityModulesComponent } from '../components/activitymodules/activitymodules'; + +/** + * Course nav handler. + */ +@Injectable() +export class AddonBlockActivityModulesHandler implements CoreBlockHandler { + name = 'AddonBlockActivityModulesHandler'; + blockName = 'activity_modules'; + + constructor() { + // Nothing to do. + } + + /** + * 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 true; + } + + /** + * Returns the data needed to render the block. + * + * @param {Injector} injector Injector. + * @param {any} block The block to render. + * @param {string} contextLevel The context where the block will be used. + * @param {number} instanceId The instance ID associated with the context level. + * @return {CoreBlockHandlerData|Promise} Data or promise resolved with the data. + */ + getDisplayData?(injector: Injector, block: any, contextLevel: string, instanceId: number) + : CoreBlockHandlerData | Promise { + + return { + title: 'addon.block_activitymodules.pluginname', + class: 'addon-block-activitymodules', + component: AddonBlockActivityModulesComponent + }; + } +} diff --git a/src/addon/block/myoverview/component/myoverview.ts b/src/addon/block/myoverview/component/myoverview.ts index 554b31107..244a72117 100644 --- a/src/addon/block/myoverview/component/myoverview.ts +++ b/src/addon/block/myoverview/component/myoverview.ts @@ -23,7 +23,7 @@ import { CoreCoursesHelperProvider } from '@core/courses/providers/helper'; import { CoreCourseHelperProvider } from '@core/course/providers/helper'; import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate'; import { AddonCourseCompletionProvider } from '@addon/coursecompletion/providers/coursecompletion'; -import { AddonBlockComponent } from '../../classes/block-component'; +import { CoreBlockBaseComponent } from '@core/block/classes/base-block-component'; /** * Component to render a my overview block. @@ -32,7 +32,7 @@ import { AddonBlockComponent } from '../../classes/block-component'; selector: 'addon-block-myoverview', templateUrl: 'addon-block-myoverview.html' }) -export class AddonBlockMyOverviewComponent extends AddonBlockComponent implements OnInit, OnDestroy { +export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implements OnInit, OnDestroy { @ViewChild('searchbar') searchbar: Searchbar; courses = { diff --git a/src/addon/block/sitemainmenu/components/components.module.ts b/src/addon/block/sitemainmenu/components/components.module.ts new file mode 100644 index 000000000..a121183a5 --- /dev/null +++ b/src/addon/block/sitemainmenu/components/components.module.ts @@ -0,0 +1,45 @@ +// (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 { CommonModule } from '@angular/common'; +import { IonicModule } from 'ionic-angular'; +import { TranslateModule } from '@ngx-translate/core'; +import { AddonBlockSiteMainMenuComponent } from './sitemainmenu/sitemainmenu'; +import { CoreComponentsModule } from '@components/components.module'; +import { CoreDirectivesModule } from '@directives/directives.module'; +import { CoreCourseComponentsModule } from '@core/course/components/components.module'; + +@NgModule({ + declarations: [ + AddonBlockSiteMainMenuComponent + ], + imports: [ + CommonModule, + IonicModule, + TranslateModule.forChild(), + CoreComponentsModule, + CoreDirectivesModule, + CoreCourseComponentsModule + ], + providers: [ + ], + exports: [ + AddonBlockSiteMainMenuComponent + ], + entryComponents: [ + AddonBlockSiteMainMenuComponent + ] +}) +export class AddonBlockSiteMainMenuComponentsModule {} diff --git a/src/addon/block/sitemainmenu/components/sitemainmenu/addon-block-sitemainmenu.html b/src/addon/block/sitemainmenu/components/sitemainmenu/addon-block-sitemainmenu.html new file mode 100644 index 000000000..5941df804 --- /dev/null +++ b/src/addon/block/sitemainmenu/components/sitemainmenu/addon-block-sitemainmenu.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/addon/block/sitemainmenu/components/sitemainmenu/sitemainmenu.ts b/src/addon/block/sitemainmenu/components/sitemainmenu/sitemainmenu.ts new file mode 100644 index 000000000..02c044771 --- /dev/null +++ b/src/addon/block/sitemainmenu/components/sitemainmenu/sitemainmenu.ts @@ -0,0 +1,114 @@ +// (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, OnInit, Injector } from '@angular/core'; +import { CoreSitesProvider } from '@providers/sites'; +import { CoreCourseProvider } from '@core/course/providers/course'; +import { CoreCourseHelperProvider } from '@core/course/providers/helper'; +import { CoreSiteHomeProvider } from '@core/sitehome/providers/sitehome'; +import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate'; +import { CoreBlockBaseComponent } from '@core/block/classes/base-block-component'; + +/** + * Component to render a site main menu block. + */ +@Component({ + selector: 'addon-block-sitemainmenu', + templateUrl: 'addon-block-sitemainmenu.html' +}) +export class AddonBlockSiteMainMenuComponent extends CoreBlockBaseComponent implements OnInit { + block: any; + siteHomeId: number; + + protected fetchContentDefaultError = 'Error getting main menu data.'; + + constructor(injector: Injector, protected sitesProvider: CoreSitesProvider, protected courseProvider: CoreCourseProvider, + protected courseHelper: CoreCourseHelperProvider, protected siteHomeProvider: CoreSiteHomeProvider, + protected prefetchDelegate: CoreCourseModulePrefetchDelegate) { + + super(injector, 'AddonBlockSiteMainMenuComponent'); + + this.siteHomeId = sitesProvider.getCurrentSite().getSiteHomeId(); + } + + /** + * Component being initialized. + */ + ngOnInit(): void { + super.ngOnInit(); + } + + /** + * Perform the invalidate content function. + * + * @return {Promise} Resolved when done. + */ + protected invalidateContent(): Promise { + const promises = []; + + promises.push(this.courseProvider.invalidateSections(this.siteHomeId)); + promises.push(this.siteHomeProvider.invalidateNewsForum(this.siteHomeId)); + + if (this.block && this.block.modules) { + // Invalidate modules prefetch data. + promises.push(this.prefetchDelegate.invalidateModules(this.block.modules, this.siteHomeId)); + } + + return Promise.all(promises); + } + + /** + * Fetch the data to render the block. + * + * @return {Promise} Promise resolved when done. + */ + protected fetchContent(): Promise { + return this.courseProvider.getSections(this.siteHomeId, false, true).then((sections) => { + this.block = sections[0]; + + if (this.block) { + this.block.hasContent = this.courseHelper.sectionHasContent(this.block); + this.courseHelper.addHandlerDataForModules([this.block], this.siteHomeId); + + // Check if Site Home displays announcements. If so, remove it from the main menu block. + const currentSite = this.sitesProvider.getCurrentSite(), + config = currentSite ? currentSite.getStoredConfig() || {} : {}; + let hasNewsItem = false; + + if (config.frontpageloggedin) { + const items = config.frontpageloggedin.split(','); + + hasNewsItem = items.find((item) => { return item == '0'; }); + } + + if (hasNewsItem && this.block.modules) { + // Remove forum activity (news one only) from the main menu block to prevent duplicates. + return this.siteHomeProvider.getNewsForum(this.siteHomeId).then((forum) => { + // Search the module that belongs to site news. + for (let i = 0; i < this.block.modules.length; i++) { + const module = this.block.modules[i]; + + if (module.modname == 'forum' && module.instance == forum.id) { + this.block.modules.splice(i, 1); + break; + } + } + }).catch(() => { + // Ignore errors. + }); + } + } + }); + } +} diff --git a/src/addon/block/sitemainmenu/lang/en.json b/src/addon/block/sitemainmenu/lang/en.json new file mode 100644 index 000000000..0f3aca2ff --- /dev/null +++ b/src/addon/block/sitemainmenu/lang/en.json @@ -0,0 +1,3 @@ +{ + "pluginname": "Main menu" +} diff --git a/src/addon/block/sitemainmenu/providers/block-handler.ts b/src/addon/block/sitemainmenu/providers/block-handler.ts new file mode 100644 index 000000000..09a94796d --- /dev/null +++ b/src/addon/block/sitemainmenu/providers/block-handler.ts @@ -0,0 +1,58 @@ +// (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 { CoreBlockHandler, CoreBlockHandlerData } from '@core/block/providers/delegate'; +import { AddonBlockSiteMainMenuComponent } from '../components/sitemainmenu/sitemainmenu'; + +/** + * Course nav handler. + */ +@Injectable() +export class AddonBlockSiteMainMenuHandler implements CoreBlockHandler { + name = 'AddonBlockSiteMainMenuHandler'; + blockName = 'site_main_menu'; + + constructor() { + // Nothing to do. + } + + /** + * 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 true; + } + + /** + * Returns the data needed to render the block. + * + * @param {Injector} injector Injector. + * @param {any} block The block to render. + * @param {string} contextLevel The context where the block will be used. + * @param {number} instanceId The instance ID associated with the context level. + * @return {CoreBlockHandlerData|Promise} Data or promise resolved with the data. + */ + getDisplayData?(injector: Injector, block: any, contextLevel: string, instanceId: number) + : CoreBlockHandlerData | Promise { + + return { + title: 'addon.block_sitemainmenu.pluginname', + class: 'addon-block-sitemainmenu', + component: AddonBlockSiteMainMenuComponent + }; + } +} diff --git a/src/addon/block/sitemainmenu/sitemainmenu.module.ts b/src/addon/block/sitemainmenu/sitemainmenu.module.ts new file mode 100644 index 000000000..ace9f339e --- /dev/null +++ b/src/addon/block/sitemainmenu/sitemainmenu.module.ts @@ -0,0 +1,44 @@ +// (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 { IonicModule } from 'ionic-angular'; +import { TranslateModule } from '@ngx-translate/core'; +import { CoreComponentsModule } from '@components/components.module'; +import { CoreDirectivesModule } from '@directives/directives.module'; +import { AddonBlockSiteMainMenuComponentsModule } from './components/components.module'; +import { CoreBlockDelegate } from '@core/block/providers/delegate'; +import { AddonBlockSiteMainMenuHandler } from './providers/block-handler'; + +@NgModule({ + declarations: [ + ], + imports: [ + IonicModule, + CoreComponentsModule, + CoreDirectivesModule, + AddonBlockSiteMainMenuComponentsModule, + TranslateModule.forChild() + ], + exports: [ + ], + providers: [ + AddonBlockSiteMainMenuHandler + ] +}) +export class AddonBlockSiteMainMenuModule { + constructor(blockDelegate: CoreBlockDelegate, blockHandler: AddonBlockSiteMainMenuHandler) { + blockDelegate.registerHandler(blockHandler); + } +} diff --git a/src/addon/block/timeline/components/timeline/timeline.ts b/src/addon/block/timeline/components/timeline/timeline.ts index 4aadf42cd..f58a5aa9d 100644 --- a/src/addon/block/timeline/components/timeline/timeline.ts +++ b/src/addon/block/timeline/components/timeline/timeline.ts @@ -19,7 +19,7 @@ import { CoreSitesProvider } from '@providers/sites'; import { CoreCoursesProvider } from '@core/courses/providers/courses'; import { CoreCoursesHelperProvider } from '@core/courses/providers/helper'; import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate'; -import { AddonBlockComponent } from '../../../classes/block-component'; +import { CoreBlockBaseComponent } from '@core/block/classes/base-block-component'; import { AddonBlockTimelineProvider } from '../../providers/timeline'; /** @@ -29,7 +29,7 @@ import { AddonBlockTimelineProvider } from '../../providers/timeline'; selector: 'addon-block-timeline', templateUrl: 'addon-block-timeline.html' }) -export class AddonBlockTimelineComponent extends AddonBlockComponent implements OnInit { +export class AddonBlockTimelineComponent extends CoreBlockBaseComponent implements OnInit { sort = 'sortbydates'; filter = 'next30days'; currentSite: any; diff --git a/src/addon/mod/assign/assign.module.ts b/src/addon/mod/assign/assign.module.ts index aa4a60739..39a87ad9d 100644 --- a/src/addon/mod/assign/assign.module.ts +++ b/src/addon/mod/assign/assign.module.ts @@ -29,6 +29,7 @@ import { AddonModAssignModuleHandler } from './providers/module-handler'; import { AddonModAssignPrefetchHandler } from './providers/prefetch-handler'; import { AddonModAssignSyncCronHandler } from './providers/sync-cron-handler'; import { AddonModAssignIndexLinkHandler } from './providers/index-link-handler'; +import { AddonModAssignListLinkHandler } from './providers/list-link-handler'; import { AddonModAssignSubmissionModule } from './submission/submission.module'; import { AddonModAssignFeedbackModule } from './feedback/feedback.module'; import { CoreUpdateManagerProvider } from '@providers/update-manager'; @@ -62,18 +63,22 @@ export const ADDON_MOD_ASSIGN_PROVIDERS: any[] = [ AddonModAssignModuleHandler, AddonModAssignPrefetchHandler, AddonModAssignSyncCronHandler, - AddonModAssignIndexLinkHandler + AddonModAssignIndexLinkHandler, + AddonModAssignListLinkHandler ] }) export class AddonModAssignModule { constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModAssignModuleHandler, prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModAssignPrefetchHandler, cronDelegate: CoreCronDelegate, syncHandler: AddonModAssignSyncCronHandler, updateManager: CoreUpdateManagerProvider, - contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModAssignIndexLinkHandler) { + contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModAssignIndexLinkHandler, + listLinkHandler: AddonModAssignListLinkHandler) { + moduleDelegate.registerHandler(moduleHandler); prefetchDelegate.registerHandler(prefetchHandler); cronDelegate.register(syncHandler); contentLinksDelegate.registerHandler(linkHandler); + contentLinksDelegate.registerHandler(listLinkHandler); // Allow migrating the tables from the old app to the new schema. updateManager.registerSiteTablesMigration([ diff --git a/src/addon/mod/assign/lang/en.json b/src/addon/mod/assign/lang/en.json index 606bc2ff8..fbbe9f662 100644 --- a/src/addon/mod/assign/lang/en.json +++ b/src/addon/mod/assign/lang/en.json @@ -50,6 +50,7 @@ "markingworkflowstatereadyforreview": "Marking completed", "markingworkflowstatereadyforrelease": "Ready for release", "markingworkflowstatereleased": "Released", + "modulenameplural": "Assignments", "multipleteams": "Member of more than one group", "multipleteams_desc": "The assignment requires submission in groups. You are a member of more than one group. To be able to submit you must be a member of only one group. Please contact your teacher to change your group membership.", "noattempt": "No attempt", diff --git a/src/addon/mod/assign/providers/assign.ts b/src/addon/mod/assign/providers/assign.ts index a1e3a329a..14568639c 100644 --- a/src/addon/mod/assign/providers/assign.ts +++ b/src/addon/mod/assign/providers/assign.ts @@ -136,13 +136,20 @@ export class AddonModAssignProvider { protected getAssignmentByField(courseId: number, key: string, value: any, siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { const params = { - courseids: [courseId] + courseids: [courseId], + includenotenrolledcourses: 1 }, preSets = { cacheKey: this.getAssignmentCacheKey(courseId) }; - return site.read('mod_assign_get_assignments', params, preSets).then((response) => { + return site.read('mod_assign_get_assignments', params, preSets).catch(() => { + // In 3.6 we added a new parameter includenotenrolledcourses that could cause offline data not to be found. + // Retry again without the param to check if the request is already cached. + delete params.includenotenrolledcourses; + + return site.read('mod_assign_get_assignments', params, preSets); + }).then((response) => { // Search the assignment to return. if (response.courses && response.courses.length) { const assignments = response.courses[0].assignments; diff --git a/src/addon/mod/assign/providers/list-link-handler.ts b/src/addon/mod/assign/providers/list-link-handler.ts new file mode 100644 index 000000000..9e5315d04 --- /dev/null +++ b/src/addon/mod/assign/providers/list-link-handler.ts @@ -0,0 +1,41 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; +import { AddonModAssignProvider } from './assign'; + +/** + * Handler to treat links to assign list page. + */ +@Injectable() +export class AddonModAssignListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModAssignListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService, + protected assignProvider: AddonModAssignProvider) { + super(linkHelper, translate, 'AddonModAssign', 'assign'); + } + + /** + * 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 { + return this.assignProvider.isPluginEnabled(); + } +} diff --git a/src/addon/mod/assign/providers/module-handler.ts b/src/addon/mod/assign/providers/module-handler.ts index 4de424c27..5cd335bff 100644 --- a/src/addon/mod/assign/providers/module-handler.ts +++ b/src/addon/mod/assign/providers/module-handler.ts @@ -18,6 +18,7 @@ import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/cour import { CoreCourseProvider } from '@core/course/providers/course'; import { AddonModAssignProvider } from './assign'; import { AddonModAssignIndexComponent } from '../components/index/index'; +import { CoreConstants } from '@core/constants'; /** * Handler to support assign modules. @@ -27,6 +28,21 @@ export class AddonModAssignModuleHandler implements CoreCourseModuleHandler { name = 'AddonModAssign'; modName = 'assign'; + supportedFeatures = { + [CoreConstants.FEATURE_GROUPS]: true, + [CoreConstants.FEATURE_GROUPINGS]: true, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_COMPLETION_HAS_RULES]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: true, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: true, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true, + [CoreConstants.FEATURE_ADVANCED_GRADING]: true, + [CoreConstants.FEATURE_PLAGIARISM]: true, + [CoreConstants.FEATURE_COMMENT]: true + }; + constructor(private courseProvider: CoreCourseProvider, private assignProvider: AddonModAssignProvider) { } /** diff --git a/src/addon/mod/book/book.module.ts b/src/addon/mod/book/book.module.ts index 8fd036e53..cc06e008d 100644 --- a/src/addon/mod/book/book.module.ts +++ b/src/addon/mod/book/book.module.ts @@ -17,6 +17,7 @@ import { AddonModBookComponentsModule } from './components/components.module'; import { AddonModBookProvider } from './providers/book'; import { AddonModBookModuleHandler } from './providers/module-handler'; import { AddonModBookLinkHandler } from './providers/link-handler'; +import { AddonModBookListLinkHandler } from './providers/list-link-handler'; import { AddonModBookPrefetchHandler } from './providers/prefetch-handler'; import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate'; import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate'; @@ -37,15 +38,19 @@ export const ADDON_MOD_BOOK_PROVIDERS: any[] = [ AddonModBookProvider, AddonModBookModuleHandler, AddonModBookLinkHandler, + AddonModBookListLinkHandler, AddonModBookPrefetchHandler ] }) export class AddonModBookModule { constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModBookModuleHandler, contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModBookLinkHandler, - prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModBookPrefetchHandler) { + prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModBookPrefetchHandler, + listLinkHandler: AddonModBookListLinkHandler) { + moduleDelegate.registerHandler(moduleHandler); contentLinksDelegate.registerHandler(linkHandler); + contentLinksDelegate.registerHandler(listLinkHandler); prefetchDelegate.registerHandler(prefetchHandler); } } diff --git a/src/addon/mod/book/lang/en.json b/src/addon/mod/book/lang/en.json index 5ea91c840..bf58bf921 100644 --- a/src/addon/mod/book/lang/en.json +++ b/src/addon/mod/book/lang/en.json @@ -1,3 +1,4 @@ { - "errorchapter": "Error reading chapter of book." + "errorchapter": "Error reading chapter of book.", + "modulenameplural": "Books" } \ No newline at end of file diff --git a/src/addon/mod/book/providers/list-link-handler.ts b/src/addon/mod/book/providers/list-link-handler.ts new file mode 100644 index 000000000..5351a9ae4 --- /dev/null +++ b/src/addon/mod/book/providers/list-link-handler.ts @@ -0,0 +1,46 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; +import { AddonModBookProvider } from './book'; + +/** + * Handler to treat links to book list page. + */ +@Injectable() +export class AddonModBookListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModBookListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService, + protected bookProvider: AddonModBookProvider) { + super(linkHelper, translate, 'AddonModBook', 'book'); + } + + /** + * Check if the handler is enabled for a certain site (site + user) and a URL. + * If not defined, defaults to true. + * + * @param {string} siteId The site ID. + * @param {string} url The URL to treat. + * @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1} + * @param {number} [courseId] Course ID related to the URL. Optional but recommended. + * @return {boolean|Promise} Whether the handler is enabled for the URL and site. + */ + isEnabled(siteId: string, url: string, params: any, courseId?: number): boolean | Promise { + return this.bookProvider.isPluginEnabled(); + } +} diff --git a/src/addon/mod/book/providers/module-handler.ts b/src/addon/mod/book/providers/module-handler.ts index 7cae479c6..bffbf8038 100644 --- a/src/addon/mod/book/providers/module-handler.ts +++ b/src/addon/mod/book/providers/module-handler.ts @@ -18,6 +18,7 @@ import { AddonModBookProvider } from './book'; import { AddonModBookIndexComponent } from '../components/index/index'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreCourseProvider } from '@core/course/providers/course'; +import { CoreConstants } from '@core/constants'; /** * Handler to support book modules. @@ -27,6 +28,18 @@ export class AddonModBookModuleHandler implements CoreCourseModuleHandler { name = 'AddonModBook'; modName = 'book'; + supportedFeatures = { + [CoreConstants.FEATURE_MOD_ARCHETYPE]: CoreConstants.MOD_ARCHETYPE_RESOURCE, + [CoreConstants.FEATURE_GROUPS]: false, + [CoreConstants.FEATURE_GROUPINGS]: false, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: false, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: false, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true + }; + constructor(protected bookProvider: AddonModBookProvider, private courseProvider: CoreCourseProvider) { } /** diff --git a/src/addon/mod/chat/chat.module.ts b/src/addon/mod/chat/chat.module.ts index bcda38f20..62ce5d80b 100644 --- a/src/addon/mod/chat/chat.module.ts +++ b/src/addon/mod/chat/chat.module.ts @@ -18,6 +18,7 @@ import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate import { AddonModChatComponentsModule } from './components/components.module'; import { AddonModChatProvider } from './providers/chat'; import { AddonModChatLinkHandler } from './providers/link-handler'; +import { AddonModChatListLinkHandler } from './providers/list-link-handler'; import { AddonModChatModuleHandler } from './providers/module-handler'; // List of providers (without handlers). @@ -34,13 +35,17 @@ export const ADDON_MOD_CHAT_PROVIDERS: any[] = [ providers: [ AddonModChatProvider, AddonModChatLinkHandler, + AddonModChatListLinkHandler, AddonModChatModuleHandler, ] }) export class AddonModChatModule { constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModChatModuleHandler, - contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModChatLinkHandler) { + contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModChatLinkHandler, + listLinkHandler: AddonModChatListLinkHandler) { + moduleDelegate.registerHandler(moduleHandler); contentLinksDelegate.registerHandler(linkHandler); + contentLinksDelegate.registerHandler(listLinkHandler); } } diff --git a/src/addon/mod/chat/lang/en.json b/src/addon/mod/chat/lang/en.json index 7fc12c00c..30f9613ca 100644 --- a/src/addon/mod/chat/lang/en.json +++ b/src/addon/mod/chat/lang/en.json @@ -11,6 +11,7 @@ "messagebeepsyou": "{{$a}} has just beeped you!", "messageenter": "{{$a}} has just entered this chat", "messageexit": "{{$a}} has left this chat", + "modulenameplural": "Chats", "mustbeonlinetosendmessages": "You must be online to send messages.", "nomessages": "No messages yet", "send": "Send", diff --git a/src/addon/mod/chat/providers/list-link-handler.ts b/src/addon/mod/chat/providers/list-link-handler.ts new file mode 100644 index 000000000..19a32ed04 --- /dev/null +++ b/src/addon/mod/chat/providers/list-link-handler.ts @@ -0,0 +1,30 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; + +/** + * Handler to treat links to chat list page. + */ +@Injectable() +export class AddonModChatListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModChatListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService) { + super(linkHelper, translate, 'AddonModChat', 'chat'); + } +} diff --git a/src/addon/mod/chat/providers/module-handler.ts b/src/addon/mod/chat/providers/module-handler.ts index 848ed156e..9b29145c0 100644 --- a/src/addon/mod/chat/providers/module-handler.ts +++ b/src/addon/mod/chat/providers/module-handler.ts @@ -17,6 +17,7 @@ import { NavController, NavOptions } from 'ionic-angular'; import { AddonModChatIndexComponent } from '../components/index/index'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreCourseProvider } from '@core/course/providers/course'; +import { CoreConstants } from '@core/constants'; /** * Handler to support chat modules. @@ -26,6 +27,17 @@ export class AddonModChatModuleHandler implements CoreCourseModuleHandler { name = 'AddonModChat'; modName = 'chat'; + supportedFeatures = { + [CoreConstants.FEATURE_GROUPS]: true, + [CoreConstants.FEATURE_GROUPINGS]: true, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: false, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: true, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true + }; + constructor(private courseProvider: CoreCourseProvider) { } /** diff --git a/src/addon/mod/choice/choice.module.ts b/src/addon/mod/choice/choice.module.ts index 501f10bfa..7b08793fb 100644 --- a/src/addon/mod/choice/choice.module.ts +++ b/src/addon/mod/choice/choice.module.ts @@ -21,6 +21,7 @@ import { AddonModChoiceComponentsModule } from './components/components.module'; import { AddonModChoiceModuleHandler } from './providers/module-handler'; import { AddonModChoiceProvider } from './providers/choice'; import { AddonModChoiceLinkHandler } from './providers/link-handler'; +import { AddonModChoiceListLinkHandler } from './providers/list-link-handler'; import { AddonModChoicePrefetchHandler } from './providers/prefetch-handler'; import { AddonModChoiceSyncProvider } from './providers/sync'; import { AddonModChoiceSyncCronHandler } from './providers/sync-cron-handler'; @@ -47,6 +48,7 @@ export const ADDON_MOD_CHOICE_PROVIDERS: any[] = [ AddonModChoiceModuleHandler, AddonModChoicePrefetchHandler, AddonModChoiceLinkHandler, + AddonModChoiceListLinkHandler, AddonModChoiceSyncCronHandler ] }) @@ -54,10 +56,13 @@ export class AddonModChoiceModule { constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModChoiceModuleHandler, prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModChoicePrefetchHandler, contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModChoiceLinkHandler, - cronDelegate: CoreCronDelegate, syncHandler: AddonModChoiceSyncCronHandler, updateManager: CoreUpdateManagerProvider) { + cronDelegate: CoreCronDelegate, syncHandler: AddonModChoiceSyncCronHandler, updateManager: CoreUpdateManagerProvider, + listLinkHandler: AddonModChoiceListLinkHandler) { + moduleDelegate.registerHandler(moduleHandler); prefetchDelegate.registerHandler(prefetchHandler); contentLinksDelegate.registerHandler(linkHandler); + contentLinksDelegate.registerHandler(listLinkHandler); cronDelegate.register(syncHandler); // Allow migrating the tables from the old app to the new schema. diff --git a/src/addon/mod/choice/lang/en.json b/src/addon/mod/choice/lang/en.json index 7a8a95ea6..a0714b34a 100644 --- a/src/addon/mod/choice/lang/en.json +++ b/src/addon/mod/choice/lang/en.json @@ -4,6 +4,7 @@ "errorgetchoice": "Error getting choice data.", "expired": "Sorry, this activity closed on {{$a}} and is no longer available", "full": "(Full)", + "modulenameplural": "Choices", "noresultsviewable": "The results are not currently viewable.", "notopenyet": "Sorry, this activity is not available until {{$a}}", "numberofuser": "Number of responses", diff --git a/src/addon/mod/choice/providers/list-link-handler.ts b/src/addon/mod/choice/providers/list-link-handler.ts new file mode 100644 index 000000000..ad4aec0f6 --- /dev/null +++ b/src/addon/mod/choice/providers/list-link-handler.ts @@ -0,0 +1,30 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; + +/** + * Handler to treat links to choice list page. + */ +@Injectable() +export class AddonModChoiceListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModChoiceListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService) { + super(linkHelper, translate, 'AddonModChoice', 'choice'); + } +} diff --git a/src/addon/mod/choice/providers/module-handler.ts b/src/addon/mod/choice/providers/module-handler.ts index 402f5555f..f9a26b2b9 100644 --- a/src/addon/mod/choice/providers/module-handler.ts +++ b/src/addon/mod/choice/providers/module-handler.ts @@ -17,6 +17,7 @@ import { NavController, NavOptions } from 'ionic-angular'; import { AddonModChoiceIndexComponent } from '../components/index/index'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreCourseProvider } from '@core/course/providers/course'; +import { CoreConstants } from '@core/constants'; /** * Handler to support choice modules. @@ -26,6 +27,18 @@ export class AddonModChoiceModuleHandler implements CoreCourseModuleHandler { name = 'AddonModChoice'; modName = 'choice'; + supportedFeatures = { + [CoreConstants.FEATURE_GROUPS]: true, + [CoreConstants.FEATURE_GROUPINGS]: true, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_COMPLETION_HAS_RULES]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: false, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: false, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true + }; + constructor(private courseProvider: CoreCourseProvider) { } /** diff --git a/src/addon/mod/data/data.module.ts b/src/addon/mod/data/data.module.ts index 6ddb96d55..9babfa364 100644 --- a/src/addon/mod/data/data.module.ts +++ b/src/addon/mod/data/data.module.ts @@ -25,6 +25,7 @@ import { AddonModDataApproveLinkHandler } from './providers/approve-link-handler import { AddonModDataDeleteLinkHandler } from './providers/delete-link-handler'; import { AddonModDataShowLinkHandler } from './providers/show-link-handler'; import { AddonModDataEditLinkHandler } from './providers/edit-link-handler'; +import { AddonModDataListLinkHandler } from './providers/list-link-handler'; import { AddonModDataHelperProvider } from './providers/helper'; import { AddonModDataPrefetchHandler } from './providers/prefetch-handler'; import { AddonModDataSyncProvider } from './providers/sync'; @@ -64,6 +65,7 @@ export const ADDON_MOD_DATA_PROVIDERS: any[] = [ AddonModDataDeleteLinkHandler, AddonModDataShowLinkHandler, AddonModDataEditLinkHandler, + AddonModDataListLinkHandler, AddonModDataSyncCronHandler, AddonModDataDefaultFieldHandler ] @@ -74,7 +76,9 @@ export class AddonModDataModule { contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModDataLinkHandler, cronDelegate: CoreCronDelegate, syncHandler: AddonModDataSyncCronHandler, updateManager: CoreUpdateManagerProvider, approveLinkHandler: AddonModDataApproveLinkHandler, deleteLinkHandler: AddonModDataDeleteLinkHandler, - showLinkHandler: AddonModDataShowLinkHandler, editLinkHandler: AddonModDataEditLinkHandler) { + showLinkHandler: AddonModDataShowLinkHandler, editLinkHandler: AddonModDataEditLinkHandler, + listLinkHandler: AddonModDataListLinkHandler) { + moduleDelegate.registerHandler(moduleHandler); prefetchDelegate.registerHandler(prefetchHandler); contentLinksDelegate.registerHandler(linkHandler); @@ -82,6 +86,7 @@ export class AddonModDataModule { contentLinksDelegate.registerHandler(deleteLinkHandler); contentLinksDelegate.registerHandler(showLinkHandler); contentLinksDelegate.registerHandler(editLinkHandler); + contentLinksDelegate.registerHandler(listLinkHandler); cronDelegate.register(syncHandler); // Allow migrating the tables from the old app to the new schema. diff --git a/src/addon/mod/data/lang/en.json b/src/addon/mod/data/lang/en.json index fdd3f402a..0f38a537f 100644 --- a/src/addon/mod/data/lang/en.json +++ b/src/addon/mod/data/lang/en.json @@ -20,6 +20,7 @@ "fields": "Fields", "latlongboth": "Both latitude and longitude are required.", "menuchoose": "Choose...", + "modulenameplural": "Databases", "more": "More", "nomatch": "No matching entries found!", "norecords": "No entries in database", diff --git a/src/addon/mod/data/providers/list-link-handler.ts b/src/addon/mod/data/providers/list-link-handler.ts new file mode 100644 index 000000000..6ca26006a --- /dev/null +++ b/src/addon/mod/data/providers/list-link-handler.ts @@ -0,0 +1,41 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; +import { AddonModDataProvider } from './data'; + +/** + * Handler to treat links to data list page. + */ +@Injectable() +export class AddonModDataListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModDataListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService, + protected dataProvider: AddonModDataProvider) { + super(linkHelper, translate, 'AddonModData', 'data'); + } + + /** + * Check if the handler is enabled on a site level. + * + * @return {Promise} Whether or not the handler is enabled on a site level. + */ + isEnabled(): Promise { + return this.dataProvider.isPluginEnabled(); + } +} diff --git a/src/addon/mod/data/providers/module-handler.ts b/src/addon/mod/data/providers/module-handler.ts index b741ec975..3fb8f5c7e 100644 --- a/src/addon/mod/data/providers/module-handler.ts +++ b/src/addon/mod/data/providers/module-handler.ts @@ -18,6 +18,7 @@ import { AddonModDataIndexComponent } from '../components/index/index'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreCourseProvider } from '@core/course/providers/course'; import { AddonModDataProvider } from './data'; +import { CoreConstants } from '@core/constants'; /** * Handler to support data modules. @@ -27,6 +28,20 @@ export class AddonModDataModuleHandler implements CoreCourseModuleHandler { name = 'AddonModData'; modName = 'data'; + supportedFeatures = { + [CoreConstants.FEATURE_GROUPS]: true, + [CoreConstants.FEATURE_GROUPINGS]: true, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_COMPLETION_HAS_RULES]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: true, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: true, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true, + [CoreConstants.FEATURE_RATE]: true, + [CoreConstants.FEATURE_COMMENT]: true + }; + constructor(private courseProvider: CoreCourseProvider, private dataProvider: AddonModDataProvider) { } /** diff --git a/src/addon/mod/feedback/feedback.module.ts b/src/addon/mod/feedback/feedback.module.ts index ce5673747..ded66de7e 100644 --- a/src/addon/mod/feedback/feedback.module.ts +++ b/src/addon/mod/feedback/feedback.module.ts @@ -26,6 +26,7 @@ import { AddonModFeedbackShowEntriesLinkHandler } from './providers/show-entries import { AddonModFeedbackShowNonRespondentsLinkHandler } from './providers/show-non-respondents-link-handler'; import { AddonModFeedbackCompleteLinkHandler } from './providers/complete-link-handler'; import { AddonModFeedbackPrintLinkHandler } from './providers/print-link-handler'; +import { AddonModFeedbackListLinkHandler } from './providers/list-link-handler'; import { AddonModFeedbackHelperProvider } from './providers/helper'; import { AddonModFeedbackPrefetchHandler } from './providers/prefetch-handler'; import { AddonModFeedbackSyncProvider } from './providers/sync'; @@ -60,6 +61,7 @@ export const ADDON_MOD_FEEDBACK_PROVIDERS: any[] = [ AddonModFeedbackShowNonRespondentsLinkHandler, AddonModFeedbackCompleteLinkHandler, AddonModFeedbackPrintLinkHandler, + AddonModFeedbackListLinkHandler, AddonModFeedbackSyncCronHandler ] }) @@ -72,7 +74,8 @@ export class AddonModFeedbackModule { showEntriesLinkHandler: AddonModFeedbackShowEntriesLinkHandler, showNonRespondentsLinkHandler: AddonModFeedbackShowNonRespondentsLinkHandler, completeLinkHandler: AddonModFeedbackCompleteLinkHandler, - printLinkHandler: AddonModFeedbackPrintLinkHandler) { + printLinkHandler: AddonModFeedbackPrintLinkHandler, listLinkHandler: AddonModFeedbackListLinkHandler) { + moduleDelegate.registerHandler(moduleHandler); prefetchDelegate.registerHandler(prefetchHandler); contentLinksDelegate.registerHandler(linkHandler); @@ -81,6 +84,7 @@ export class AddonModFeedbackModule { contentLinksDelegate.registerHandler(showNonRespondentsLinkHandler); contentLinksDelegate.registerHandler(completeLinkHandler); contentLinksDelegate.registerHandler(printLinkHandler); + contentLinksDelegate.registerHandler(listLinkHandler); cronDelegate.register(syncHandler); // Allow migrating the tables from the old app to the new schema. diff --git a/src/addon/mod/feedback/lang/en.json b/src/addon/mod/feedback/lang/en.json index 3dab96d98..01eec2c06 100644 --- a/src/addon/mod/feedback/lang/en.json +++ b/src/addon/mod/feedback/lang/en.json @@ -13,6 +13,7 @@ "feedback_submitted_offline": "This feedback has been saved to be submitted later.", "mapcourses": "Map feedback to courses", "mode": "Mode", + "modulenameplural": "Feedback", "next_page": "Next page", "non_anonymous": "User's name will be logged and shown with answers", "non_anonymous_entries": "Non anonymous entries ({{$a}})", diff --git a/src/addon/mod/feedback/providers/list-link-handler.ts b/src/addon/mod/feedback/providers/list-link-handler.ts new file mode 100644 index 000000000..8d6750e0b --- /dev/null +++ b/src/addon/mod/feedback/providers/list-link-handler.ts @@ -0,0 +1,41 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; +import { AddonModFeedbackProvider } from './feedback'; + +/** + * Handler to treat links to feedback list page. + */ +@Injectable() +export class AddonModFeedbackListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModFeedbackListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService, + protected feedbackProvider: AddonModFeedbackProvider) { + super(linkHelper, translate, 'AddonModFeedback', 'feedback'); + } + + /** + * Check if the handler is enabled on a site level. + * + * @return {Promise} Whether or not the handler is enabled on a site level. + */ + isEnabled(): Promise { + return this.feedbackProvider.isPluginEnabled(); + } +} diff --git a/src/addon/mod/feedback/providers/module-handler.ts b/src/addon/mod/feedback/providers/module-handler.ts index 59dbbdd67..26cc80e11 100644 --- a/src/addon/mod/feedback/providers/module-handler.ts +++ b/src/addon/mod/feedback/providers/module-handler.ts @@ -18,6 +18,7 @@ import { AddonModFeedbackIndexComponent } from '../components/index/index'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreCourseProvider } from '@core/course/providers/course'; import { AddonModFeedbackProvider } from './feedback'; +import { CoreConstants } from '@core/constants'; /** * Handler to support feedback modules. @@ -27,6 +28,18 @@ export class AddonModFeedbackModuleHandler implements CoreCourseModuleHandler { name = 'AddonModFeedback'; modName = 'feedback'; + supportedFeatures = { + [CoreConstants.FEATURE_GROUPS]: true, + [CoreConstants.FEATURE_GROUPINGS]: true, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_COMPLETION_HAS_RULES]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: false, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: false, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true + }; + constructor(private courseProvider: CoreCourseProvider, private feedbackProvider: AddonModFeedbackProvider) { } /** diff --git a/src/addon/mod/folder/folder.module.ts b/src/addon/mod/folder/folder.module.ts index d597318f9..72f29d68c 100644 --- a/src/addon/mod/folder/folder.module.ts +++ b/src/addon/mod/folder/folder.module.ts @@ -20,6 +20,7 @@ import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate import { AddonModFolderComponentsModule } from './components/components.module'; import { AddonModFolderPrefetchHandler } from './providers/prefetch-handler'; import { AddonModFolderLinkHandler } from './providers/link-handler'; +import { AddonModFolderListLinkHandler } from './providers/list-link-handler'; import { AddonModFolderPluginFileHandler } from './providers/pluginfile-handler'; import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate'; import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate'; @@ -43,6 +44,7 @@ export const ADDON_MOD_FOLDER_PROVIDERS: any[] = [ AddonModFolderModuleHandler, AddonModFolderPrefetchHandler, AddonModFolderLinkHandler, + AddonModFolderListLinkHandler, AddonModFolderPluginFileHandler ] }) @@ -50,10 +52,13 @@ export class AddonModFolderModule { constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModFolderModuleHandler, prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModFolderPrefetchHandler, contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModFolderLinkHandler, - pluginfileDelegate: CorePluginFileDelegate, pluginfileHandler: AddonModFolderPluginFileHandler) { + pluginfileDelegate: CorePluginFileDelegate, pluginfileHandler: AddonModFolderPluginFileHandler, + listLinkHandler: AddonModFolderListLinkHandler) { + moduleDelegate.registerHandler(moduleHandler); prefetchDelegate.registerHandler(prefetchHandler); contentLinksDelegate.registerHandler(linkHandler); + contentLinksDelegate.registerHandler(listLinkHandler); pluginfileDelegate.registerHandler(pluginfileHandler); } } diff --git a/src/addon/mod/folder/lang/en.json b/src/addon/mod/folder/lang/en.json index 7b622c58b..40bcdb36a 100644 --- a/src/addon/mod/folder/lang/en.json +++ b/src/addon/mod/folder/lang/en.json @@ -1,3 +1,4 @@ { - "emptyfilelist": "There are no files to show." + "emptyfilelist": "There are no files to show.", + "modulenameplural": "Folders" } \ No newline at end of file diff --git a/src/addon/mod/folder/providers/list-link-handler.ts b/src/addon/mod/folder/providers/list-link-handler.ts new file mode 100644 index 000000000..5f3fe1c82 --- /dev/null +++ b/src/addon/mod/folder/providers/list-link-handler.ts @@ -0,0 +1,30 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; + +/** + * Handler to treat links to folder list page. + */ +@Injectable() +export class AddonModFolderListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModFolderListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService) { + super(linkHelper, translate, 'AddonModFolder', 'folder'); + } +} diff --git a/src/addon/mod/folder/providers/module-handler.ts b/src/addon/mod/folder/providers/module-handler.ts index 54899cb35..125cf11b9 100644 --- a/src/addon/mod/folder/providers/module-handler.ts +++ b/src/addon/mod/folder/providers/module-handler.ts @@ -17,6 +17,7 @@ import { NavController, NavOptions } from 'ionic-angular'; import { AddonModFolderIndexComponent } from '../components/index/index'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreCourseProvider } from '@core/course/providers/course'; +import { CoreConstants } from '@core/constants'; /** * Handler to support folder modules. @@ -26,6 +27,18 @@ export class AddonModFolderModuleHandler implements CoreCourseModuleHandler { name = 'AddonModFolder'; modName = 'folder'; + supportedFeatures = { + [CoreConstants.FEATURE_MOD_ARCHETYPE]: CoreConstants.MOD_ARCHETYPE_RESOURCE, + [CoreConstants.FEATURE_GROUPS]: false, + [CoreConstants.FEATURE_GROUPINGS]: false, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: false, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: false, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true + }; + constructor(private courseProvider: CoreCourseProvider) { } /** diff --git a/src/addon/mod/forum/forum.module.ts b/src/addon/mod/forum/forum.module.ts index c0455cefd..b925af0b4 100644 --- a/src/addon/mod/forum/forum.module.ts +++ b/src/addon/mod/forum/forum.module.ts @@ -26,6 +26,7 @@ import { AddonModForumPrefetchHandler } from './providers/prefetch-handler'; import { AddonModForumSyncCronHandler } from './providers/sync-cron-handler'; import { AddonModForumIndexLinkHandler } from './providers/index-link-handler'; import { AddonModForumDiscussionLinkHandler } from './providers/discussion-link-handler'; +import { AddonModForumListLinkHandler } from './providers/list-link-handler'; import { AddonModForumComponentsModule } from './components/components.module'; import { CoreUpdateManagerProvider } from '@providers/update-manager'; @@ -52,6 +53,7 @@ export const ADDON_MOD_FORUM_PROVIDERS: any[] = [ AddonModForumPrefetchHandler, AddonModForumSyncCronHandler, AddonModForumIndexLinkHandler, + AddonModForumListLinkHandler, AddonModForumDiscussionLinkHandler ] }) @@ -60,13 +62,14 @@ export class AddonModForumModule { prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModForumPrefetchHandler, cronDelegate: CoreCronDelegate, syncHandler: AddonModForumSyncCronHandler, linksDelegate: CoreContentLinksDelegate, indexHandler: AddonModForumIndexLinkHandler, discussionHandler: AddonModForumDiscussionLinkHandler, - updateManager: CoreUpdateManagerProvider) { + updateManager: CoreUpdateManagerProvider, listLinkHandler: AddonModForumListLinkHandler) { moduleDelegate.registerHandler(moduleHandler); prefetchDelegate.registerHandler(prefetchHandler); cronDelegate.register(syncHandler); linksDelegate.registerHandler(indexHandler); linksDelegate.registerHandler(discussionHandler); + linksDelegate.registerHandler(listLinkHandler); // Allow migrating the tables from the old app to the new schema. updateManager.registerSiteTablesMigration([ diff --git a/src/addon/mod/forum/lang/en.json b/src/addon/mod/forum/lang/en.json index 5a461dcfd..214e828d0 100644 --- a/src/addon/mod/forum/lang/en.json +++ b/src/addon/mod/forum/lang/en.json @@ -21,6 +21,7 @@ "modeflatnewestfirst": "Display replies flat, with newest first", "modeflatoldestfirst": "Display replies flat, with oldest first", "modenested": "Display replies in nested form", + "modulenameplural": "Forums", "numdiscussions": "{{numdiscussions}} discussions", "numreplies": "{{numreplies}} replies", "posttoforum": "Post to forum", diff --git a/src/addon/mod/forum/providers/list-link-handler.ts b/src/addon/mod/forum/providers/list-link-handler.ts new file mode 100644 index 000000000..49923c89b --- /dev/null +++ b/src/addon/mod/forum/providers/list-link-handler.ts @@ -0,0 +1,30 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; + +/** + * Handler to treat links to forum list page. + */ +@Injectable() +export class AddonModForumListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModForumListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService) { + super(linkHelper, translate, 'AddonModForum', 'forum'); + } +} diff --git a/src/addon/mod/forum/providers/module-handler.ts b/src/addon/mod/forum/providers/module-handler.ts index fef8ce605..a44a05c3a 100644 --- a/src/addon/mod/forum/providers/module-handler.ts +++ b/src/addon/mod/forum/providers/module-handler.ts @@ -21,6 +21,7 @@ import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/cour import { CoreCourseProvider } from '@core/course/providers/course'; import { AddonModForumProvider } from './forum'; import { AddonModForumIndexComponent } from '../components/index/index'; +import { CoreConstants } from '@core/constants'; /** * Handler to support forum modules. @@ -30,6 +31,20 @@ export class AddonModForumModuleHandler implements CoreCourseModuleHandler { name = 'AddonModForum'; modName = 'forum'; + supportedFeatures = { + [CoreConstants.FEATURE_GROUPS]: true, + [CoreConstants.FEATURE_GROUPINGS]: true, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_COMPLETION_HAS_RULES]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: true, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: true, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true, + [CoreConstants.FEATURE_RATE]: true, + [CoreConstants.FEATURE_PLAGIARISM]: true + }; + constructor(private courseProvider: CoreCourseProvider, private forumProvider: AddonModForumProvider, private translate: TranslateService, private eventsProvider: CoreEventsProvider, private sitesProvider: CoreSitesProvider) {} diff --git a/src/addon/mod/glossary/glossary.module.ts b/src/addon/mod/glossary/glossary.module.ts index 78da46557..ab114c54b 100644 --- a/src/addon/mod/glossary/glossary.module.ts +++ b/src/addon/mod/glossary/glossary.module.ts @@ -26,6 +26,7 @@ import { AddonModGlossaryPrefetchHandler } from './providers/prefetch-handler'; import { AddonModGlossarySyncCronHandler } from './providers/sync-cron-handler'; import { AddonModGlossaryIndexLinkHandler } from './providers/index-link-handler'; import { AddonModGlossaryEntryLinkHandler } from './providers/entry-link-handler'; +import { AddonModGlossaryListLinkHandler } from './providers/list-link-handler'; import { AddonModGlossaryComponentsModule } from './components/components.module'; import { CoreUpdateManagerProvider } from '@providers/update-manager'; @@ -53,6 +54,7 @@ export const ADDON_MOD_GLOSSARY_PROVIDERS: any[] = [ AddonModGlossarySyncCronHandler, AddonModGlossaryIndexLinkHandler, AddonModGlossaryEntryLinkHandler, + AddonModGlossaryListLinkHandler ] }) export class AddonModGlossaryModule { @@ -60,13 +62,14 @@ export class AddonModGlossaryModule { prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModGlossaryPrefetchHandler, cronDelegate: CoreCronDelegate, syncHandler: AddonModGlossarySyncCronHandler, linksDelegate: CoreContentLinksDelegate, indexHandler: AddonModGlossaryIndexLinkHandler, discussionHandler: AddonModGlossaryEntryLinkHandler, - updateManager: CoreUpdateManagerProvider) { + updateManager: CoreUpdateManagerProvider, listLinkHandler: AddonModGlossaryListLinkHandler) { moduleDelegate.registerHandler(moduleHandler); prefetchDelegate.registerHandler(prefetchHandler); cronDelegate.register(syncHandler); linksDelegate.registerHandler(indexHandler); linksDelegate.registerHandler(discussionHandler); + linksDelegate.registerHandler(listLinkHandler); // Allow migrating the tables from the old app to the new schema. updateManager.registerSiteTableMigration({ diff --git a/src/addon/mod/glossary/lang/en.json b/src/addon/mod/glossary/lang/en.json index 28a0078f5..18e5ff7bc 100644 --- a/src/addon/mod/glossary/lang/en.json +++ b/src/addon/mod/glossary/lang/en.json @@ -24,6 +24,7 @@ "fillfields": "Concept and definition are mandatory fields.", "fullmatch": "Match whole words only", "linking": "Auto-linking", + "modulenameplural": "Glossaries", "noentriesfound": "No entries were found.", "searchquery": "Search query" } diff --git a/src/addon/mod/glossary/providers/list-link-handler.ts b/src/addon/mod/glossary/providers/list-link-handler.ts new file mode 100644 index 000000000..51c6057f6 --- /dev/null +++ b/src/addon/mod/glossary/providers/list-link-handler.ts @@ -0,0 +1,30 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; + +/** + * Handler to treat links to glossary list page. + */ +@Injectable() +export class AddonModGlossaryListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModGlossaryListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService) { + super(linkHelper, translate, 'AddonModGlossary', 'glossary'); + } +} diff --git a/src/addon/mod/glossary/providers/module-handler.ts b/src/addon/mod/glossary/providers/module-handler.ts index ce81f445b..99f3b3a33 100644 --- a/src/addon/mod/glossary/providers/module-handler.ts +++ b/src/addon/mod/glossary/providers/module-handler.ts @@ -17,6 +17,7 @@ import { NavController, NavOptions } from 'ionic-angular'; import { AddonModGlossaryIndexComponent } from '../components/index/index'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreCourseProvider } from '@core/course/providers/course'; +import { CoreConstants } from '@core/constants'; /** * Handler to support glossary modules. @@ -26,6 +27,20 @@ export class AddonModGlossaryModuleHandler implements CoreCourseModuleHandler { name = 'AddonModGlossary'; modName = 'glossary'; + supportedFeatures = { + [CoreConstants.FEATURE_GROUPS]: false, + [CoreConstants.FEATURE_GROUPINGS]: false, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_COMPLETION_HAS_RULES]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: true, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: true, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true, + [CoreConstants.FEATURE_RATE]: true, + [CoreConstants.FEATURE_PLAGIARISM]: true + }; + constructor(private courseProvider: CoreCourseProvider) { } /** diff --git a/src/addon/mod/imscp/imscp.module.ts b/src/addon/mod/imscp/imscp.module.ts index 68ac3865c..825af274f 100644 --- a/src/addon/mod/imscp/imscp.module.ts +++ b/src/addon/mod/imscp/imscp.module.ts @@ -18,6 +18,7 @@ import { AddonModImscpModuleHandler } from './providers/module-handler'; import { AddonModImscpProvider } from './providers/imscp'; import { AddonModImscpPrefetchHandler } from './providers/prefetch-handler'; import { AddonModImscpLinkHandler } from './providers/link-handler'; +import { AddonModImscpListLinkHandler } from './providers/list-link-handler'; import { AddonModImscpPluginFileHandler } from './providers/pluginfile-handler'; import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate'; import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate'; @@ -40,6 +41,7 @@ export const ADDON_MOD_IMSCP_PROVIDERS: any[] = [ AddonModImscpModuleHandler, AddonModImscpPrefetchHandler, AddonModImscpLinkHandler, + AddonModImscpListLinkHandler, AddonModImscpPluginFileHandler ] }) @@ -47,10 +49,13 @@ export class AddonModImscpModule { constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModImscpModuleHandler, prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModImscpPrefetchHandler, contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModImscpLinkHandler, - pluginfileDelegate: CorePluginFileDelegate, pluginfileHandler: AddonModImscpPluginFileHandler) { + pluginfileDelegate: CorePluginFileDelegate, pluginfileHandler: AddonModImscpPluginFileHandler, + listLinkHandler: AddonModImscpListLinkHandler) { + moduleDelegate.registerHandler(moduleHandler); prefetchDelegate.registerHandler(prefetchHandler); contentLinksDelegate.registerHandler(linkHandler); + contentLinksDelegate.registerHandler(listLinkHandler); pluginfileDelegate.registerHandler(pluginfileHandler); } } diff --git a/src/addon/mod/imscp/lang/en.json b/src/addon/mod/imscp/lang/en.json index f2c9c32bd..4abb95089 100644 --- a/src/addon/mod/imscp/lang/en.json +++ b/src/addon/mod/imscp/lang/en.json @@ -1,4 +1,5 @@ { "deploymenterror": "Content package error!", + "modulenameplural": "IMS content packages", "showmoduledescription": "Show description" } \ No newline at end of file diff --git a/src/addon/mod/imscp/providers/list-link-handler.ts b/src/addon/mod/imscp/providers/list-link-handler.ts new file mode 100644 index 000000000..21bb3dbc4 --- /dev/null +++ b/src/addon/mod/imscp/providers/list-link-handler.ts @@ -0,0 +1,41 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; +import { AddonModImscpProvider } from './imscp'; + +/** + * Handler to treat links to IMSCP list page. + */ +@Injectable() +export class AddonModImscpListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModImscpListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService, + protected imscpProvider: AddonModImscpProvider) { + super(linkHelper, translate, 'AddonModImscp', 'imscp'); + } + + /** + * Check if the handler is enabled on a site level. + * + * @return {boolean|Promise} Whether or not the handler is enabled on a site level. + */ + isEnabled(): boolean | Promise { + return this.imscpProvider.isPluginEnabled(); + } +} diff --git a/src/addon/mod/imscp/providers/module-handler.ts b/src/addon/mod/imscp/providers/module-handler.ts index 70cc43b6b..6f581bdc1 100644 --- a/src/addon/mod/imscp/providers/module-handler.ts +++ b/src/addon/mod/imscp/providers/module-handler.ts @@ -18,6 +18,7 @@ import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/cour import { CoreCourseProvider } from '@core/course/providers/course'; import { AddonModImscpIndexComponent } from '../components/index/index'; import { AddonModImscpProvider } from './imscp'; +import { CoreConstants } from '@core/constants'; /** * Handler to support IMSCP modules. @@ -27,6 +28,18 @@ export class AddonModImscpModuleHandler implements CoreCourseModuleHandler { name = 'AddonModImscp'; modName = 'imscp'; + supportedFeatures = { + [CoreConstants.FEATURE_MOD_ARCHETYPE]: CoreConstants.MOD_ARCHETYPE_RESOURCE, + [CoreConstants.FEATURE_GROUPS]: false, + [CoreConstants.FEATURE_GROUPINGS]: false, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: false, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: false, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true + }; + constructor(private courseProvider: CoreCourseProvider, protected imscpProvider: AddonModImscpProvider) { } /** diff --git a/src/addon/mod/label/providers/module-handler.ts b/src/addon/mod/label/providers/module-handler.ts index f54871597..0e72fac14 100644 --- a/src/addon/mod/label/providers/module-handler.ts +++ b/src/addon/mod/label/providers/module-handler.ts @@ -14,6 +14,7 @@ import { Injectable, Injector } from '@angular/core'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; +import { CoreConstants } from '@core/constants'; /** * Handler to support label modules. @@ -23,6 +24,19 @@ export class AddonModLabelModuleHandler implements CoreCourseModuleHandler { name = 'AddonModLabel'; modName = 'label'; + supportedFeatures = { + [CoreConstants.FEATURE_MOD_ARCHETYPE]: CoreConstants.MOD_ARCHETYPE_RESOURCE, + [CoreConstants.FEATURE_IDNUMBER]: true, + [CoreConstants.FEATURE_GROUPS]: false, + [CoreConstants.FEATURE_GROUPINGS]: false, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: false, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: false, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: false, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true + }; + constructor() { // Nothing to do. } diff --git a/src/addon/mod/lesson/lang/en.json b/src/addon/mod/lesson/lang/en.json index c28b5d952..7a23484cb 100644 --- a/src/addon/mod/lesson/lang/en.json +++ b/src/addon/mod/lesson/lang/en.json @@ -41,6 +41,7 @@ "lowtime": "Low time", "maximumnumberofattemptsreached": "Maximum number of attempts reached - Moving to next page", "modattemptsnoteacher": "Student review only works for students.", + "modulenameplural": "Lessons", "noanswer": "One or more questions have no answer given. Please go back and submit an answer.", "nolessonattempts": "No attempts have been made on this lesson.", "nolessonattemptsgroup": "No attempts have been made by {{$a}} group members on this lesson.", diff --git a/src/addon/mod/lesson/lesson.module.ts b/src/addon/mod/lesson/lesson.module.ts index be991cc50..caad60d06 100644 --- a/src/addon/mod/lesson/lesson.module.ts +++ b/src/addon/mod/lesson/lesson.module.ts @@ -28,6 +28,7 @@ import { AddonModLessonSyncCronHandler } from './providers/sync-cron-handler'; import { AddonModLessonIndexLinkHandler } from './providers/index-link-handler'; import { AddonModLessonGradeLinkHandler } from './providers/grade-link-handler'; import { AddonModLessonReportLinkHandler } from './providers/report-link-handler'; +import { AddonModLessonListLinkHandler } from './providers/list-link-handler'; import { CoreUpdateManagerProvider } from '@providers/update-manager'; // List of providers (without handlers). @@ -54,7 +55,8 @@ export const ADDON_MOD_LESSON_PROVIDERS: any[] = [ AddonModLessonSyncCronHandler, AddonModLessonIndexLinkHandler, AddonModLessonGradeLinkHandler, - AddonModLessonReportLinkHandler + AddonModLessonReportLinkHandler, + AddonModLessonListLinkHandler ] }) export class AddonModLessonModule { @@ -62,7 +64,8 @@ export class AddonModLessonModule { prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModLessonPrefetchHandler, cronDelegate: CoreCronDelegate, syncHandler: AddonModLessonSyncCronHandler, linksDelegate: CoreContentLinksDelegate, indexHandler: AddonModLessonIndexLinkHandler, gradeHandler: AddonModLessonGradeLinkHandler, - reportHandler: AddonModLessonReportLinkHandler, updateManager: CoreUpdateManagerProvider) { + reportHandler: AddonModLessonReportLinkHandler, updateManager: CoreUpdateManagerProvider, + listLinkHandler: AddonModLessonListLinkHandler) { moduleDelegate.registerHandler(moduleHandler); prefetchDelegate.registerHandler(prefetchHandler); @@ -70,6 +73,7 @@ export class AddonModLessonModule { linksDelegate.registerHandler(indexHandler); linksDelegate.registerHandler(gradeHandler); linksDelegate.registerHandler(reportHandler); + linksDelegate.registerHandler(listLinkHandler); // Allow migrating the tables from the old app to the new schema. updateManager.registerSiteTablesMigration([ diff --git a/src/addon/mod/lesson/providers/list-link-handler.ts b/src/addon/mod/lesson/providers/list-link-handler.ts new file mode 100644 index 000000000..d208a3bba --- /dev/null +++ b/src/addon/mod/lesson/providers/list-link-handler.ts @@ -0,0 +1,41 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; +import { AddonModLessonProvider } from './lesson'; + +/** + * Handler to treat links to lesson list page. + */ +@Injectable() +export class AddonModLessonListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModLessonListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService, + protected lessonProvider: AddonModLessonProvider) { + super(linkHelper, translate, 'AddonModLesson', 'lesson'); + } + + /** + * Check if the handler is enabled on a site level. + * + * @return {Promise} Promise resolved with boolean: whether or not the handler is enabled on a site level. + */ + isEnabled(): Promise { + return this.lessonProvider.isPluginEnabled(); + } +} diff --git a/src/addon/mod/lesson/providers/module-handler.ts b/src/addon/mod/lesson/providers/module-handler.ts index 6ff5f57f2..db384d8bf 100644 --- a/src/addon/mod/lesson/providers/module-handler.ts +++ b/src/addon/mod/lesson/providers/module-handler.ts @@ -18,6 +18,7 @@ import { AddonModLessonIndexComponent } from '../components/index/index'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreCourseProvider } from '@core/course/providers/course'; import { AddonModLessonProvider } from './lesson'; +import { CoreConstants } from '@core/constants'; /** * Handler to support quiz modules. @@ -27,6 +28,18 @@ export class AddonModLessonModuleHandler implements CoreCourseModuleHandler { name = 'AddonModLesson'; modName = 'lesson'; + supportedFeatures = { + [CoreConstants.FEATURE_GROUPS]: true, + [CoreConstants.FEATURE_GROUPINGS]: true, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_COMPLETION_HAS_RULES]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: true, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: true, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true + }; + constructor(private courseProvider: CoreCourseProvider, private lessonProvider: AddonModLessonProvider) { } /** diff --git a/src/addon/mod/lti/lang/en.json b/src/addon/mod/lti/lang/en.json index 3dc7ad1a5..7a70ea4e7 100644 --- a/src/addon/mod/lti/lang/en.json +++ b/src/addon/mod/lti/lang/en.json @@ -1,5 +1,6 @@ { "errorgetlti": "Error getting module data.", "errorinvalidlaunchurl": "The launch URL is not valid.", - "launchactivity": "Launch the activity" + "launchactivity": "Launch the activity", + "modulenameplural": "External tools" } \ No newline at end of file diff --git a/src/addon/mod/lti/lti.module.ts b/src/addon/mod/lti/lti.module.ts index 52a5487b5..442a7f7f0 100644 --- a/src/addon/mod/lti/lti.module.ts +++ b/src/addon/mod/lti/lti.module.ts @@ -17,6 +17,7 @@ import { AddonModLtiComponentsModule } from './components/components.module'; import { AddonModLtiModuleHandler } from './providers/module-handler'; import { AddonModLtiProvider } from './providers/lti'; import { AddonModLtiLinkHandler } from './providers/link-handler'; +import { AddonModLtiListLinkHandler } from './providers/list-link-handler'; import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate'; import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate'; @@ -34,13 +35,17 @@ export const ADDON_MOD_LTI_PROVIDERS: any[] = [ providers: [ AddonModLtiProvider, AddonModLtiModuleHandler, - AddonModLtiLinkHandler + AddonModLtiLinkHandler, + AddonModLtiListLinkHandler ] }) export class AddonModLtiModule { constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModLtiModuleHandler, - contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModLtiLinkHandler) { + contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModLtiLinkHandler, + listLinkHandler: AddonModLtiListLinkHandler) { + moduleDelegate.registerHandler(moduleHandler); contentLinksDelegate.registerHandler(linkHandler); + contentLinksDelegate.registerHandler(listLinkHandler); } } diff --git a/src/addon/mod/lti/providers/list-link-handler.ts b/src/addon/mod/lti/providers/list-link-handler.ts new file mode 100644 index 000000000..1915f8430 --- /dev/null +++ b/src/addon/mod/lti/providers/list-link-handler.ts @@ -0,0 +1,30 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; + +/** + * Handler to treat links to LTI list page. + */ +@Injectable() +export class AddonModLtiListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModLtiListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService) { + super(linkHelper, translate, 'AddonModLti', 'lti'); + } +} diff --git a/src/addon/mod/lti/providers/module-handler.ts b/src/addon/mod/lti/providers/module-handler.ts index dfd0b38b4..b8525572c 100644 --- a/src/addon/mod/lti/providers/module-handler.ts +++ b/src/addon/mod/lti/providers/module-handler.ts @@ -23,6 +23,7 @@ import { CoreFilepoolProvider } from '@providers/filepool'; import { CoreSitesProvider } from '@providers/sites'; import { AddonModLtiIndexComponent } from '../components/index/index'; import { AddonModLtiProvider } from './lti'; +import { CoreConstants } from '@core/constants'; /** * Handler to support LTI modules. @@ -32,6 +33,17 @@ export class AddonModLtiModuleHandler implements CoreCourseModuleHandler { name = 'AddonModLti'; modName = 'lti'; + supportedFeatures = { + [CoreConstants.FEATURE_GROUPS]: false, + [CoreConstants.FEATURE_GROUPINGS]: false, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: true, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: true, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true + }; + constructor(private appProvider: CoreAppProvider, private courseProvider: CoreCourseProvider, private domUtils: CoreDomUtilsProvider, diff --git a/src/addon/mod/page/lang/en.json b/src/addon/mod/page/lang/en.json index 4dd39dc19..34bd9817d 100644 --- a/src/addon/mod/page/lang/en.json +++ b/src/addon/mod/page/lang/en.json @@ -1,3 +1,4 @@ { - "errorwhileloadingthepage": "Error while loading the page content." + "errorwhileloadingthepage": "Error while loading the page content.", + "modulenameplural": "Pages" } \ No newline at end of file diff --git a/src/addon/mod/page/page.module.ts b/src/addon/mod/page/page.module.ts index abdb0889c..5725b0266 100644 --- a/src/addon/mod/page/page.module.ts +++ b/src/addon/mod/page/page.module.ts @@ -18,6 +18,7 @@ import { AddonModPageModuleHandler } from './providers/module-handler'; import { AddonModPageProvider } from './providers/page'; import { AddonModPagePrefetchHandler } from './providers/prefetch-handler'; import { AddonModPageLinkHandler } from './providers/link-handler'; +import { AddonModPageListLinkHandler } from './providers/list-link-handler'; import { AddonModPagePluginFileHandler } from './providers/pluginfile-handler'; import { AddonModPageHelperProvider } from './providers/helper'; import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate'; @@ -43,6 +44,7 @@ export const ADDON_MOD_PAGE_PROVIDERS: any[] = [ AddonModPageModuleHandler, AddonModPagePrefetchHandler, AddonModPageLinkHandler, + AddonModPageListLinkHandler, AddonModPagePluginFileHandler ] }) @@ -50,10 +52,13 @@ export class AddonModPageModule { constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModPageModuleHandler, prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModPagePrefetchHandler, contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModPageLinkHandler, - pluginfileDelegate: CorePluginFileDelegate, pluginfileHandler: AddonModPagePluginFileHandler) { + pluginfileDelegate: CorePluginFileDelegate, pluginfileHandler: AddonModPagePluginFileHandler, + listLinkHandler: AddonModPageListLinkHandler) { + moduleDelegate.registerHandler(moduleHandler); prefetchDelegate.registerHandler(prefetchHandler); contentLinksDelegate.registerHandler(linkHandler); + contentLinksDelegate.registerHandler(listLinkHandler); pluginfileDelegate.registerHandler(pluginfileHandler); } } diff --git a/src/addon/mod/page/providers/list-link-handler.ts b/src/addon/mod/page/providers/list-link-handler.ts new file mode 100644 index 000000000..67358bb95 --- /dev/null +++ b/src/addon/mod/page/providers/list-link-handler.ts @@ -0,0 +1,41 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; +import { AddonModPageProvider } from './page'; + +/** + * Handler to treat links to page list page. + */ +@Injectable() +export class AddonModPageListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModPageListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService, + protected pageProvider: AddonModPageProvider) { + super(linkHelper, translate, 'AddonModPage', 'page'); + } + + /** + * Check if the handler is enabled on a site level. + * + * @return {boolean|Promise} Whether or not the handler is enabled on a site level. + */ + isEnabled(): boolean | Promise { + return this.pageProvider.isPluginEnabled(); + } +} diff --git a/src/addon/mod/page/providers/module-handler.ts b/src/addon/mod/page/providers/module-handler.ts index 69e04dd5d..dc5dd21ff 100644 --- a/src/addon/mod/page/providers/module-handler.ts +++ b/src/addon/mod/page/providers/module-handler.ts @@ -18,6 +18,7 @@ import { AddonModPageProvider } from './page'; import { AddonModPageIndexComponent } from '../components/index/index'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreCourseProvider } from '@core/course/providers/course'; +import { CoreConstants } from '@core/constants'; /** * Handler to support page modules. @@ -27,6 +28,18 @@ export class AddonModPageModuleHandler implements CoreCourseModuleHandler { name = 'AddonModPage'; modName = 'page'; + supportedFeatures = { + [CoreConstants.FEATURE_MOD_ARCHETYPE]: CoreConstants.MOD_ARCHETYPE_RESOURCE, + [CoreConstants.FEATURE_GROUPS]: false, + [CoreConstants.FEATURE_GROUPINGS]: false, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: false, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: false, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true + }; + constructor(private courseProvider: CoreCourseProvider, protected pageProvider: AddonModPageProvider) { } /** diff --git a/src/addon/mod/quiz/lang/en.json b/src/addon/mod/quiz/lang/en.json index 3ed3286f9..99887b291 100644 --- a/src/addon/mod/quiz/lang/en.json +++ b/src/addon/mod/quiz/lang/en.json @@ -33,6 +33,7 @@ "grademethod": "Grading method", "gradesofar": "{{$a.method}}: {{$a.mygrade}} / {{$a.quizgrade}}.", "marks": "Marks", + "modulenameplural": "Quizzes", "mustbesubmittedby": "This attempt must be submitted by {{$a}}.", "noquestions": "No questions have been added yet", "noreviewattempt": "You are not allowed to review this attempt.", diff --git a/src/addon/mod/quiz/providers/list-link-handler.ts b/src/addon/mod/quiz/providers/list-link-handler.ts new file mode 100644 index 000000000..1a19d89e2 --- /dev/null +++ b/src/addon/mod/quiz/providers/list-link-handler.ts @@ -0,0 +1,30 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; + +/** + * Handler to treat links to quiz list page. + */ +@Injectable() +export class AddonModQuizListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModQuizListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService) { + super(linkHelper, translate, 'AddonModQuiz', 'quiz'); + } +} diff --git a/src/addon/mod/quiz/providers/module-handler.ts b/src/addon/mod/quiz/providers/module-handler.ts index de7e2af28..3c4f27c60 100644 --- a/src/addon/mod/quiz/providers/module-handler.ts +++ b/src/addon/mod/quiz/providers/module-handler.ts @@ -17,6 +17,7 @@ import { NavController, NavOptions } from 'ionic-angular'; import { AddonModQuizIndexComponent } from '../components/index/index'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreCourseProvider } from '@core/course/providers/course'; +import { CoreConstants } from '@core/constants'; /** * Handler to support quiz modules. @@ -26,6 +27,20 @@ export class AddonModQuizModuleHandler implements CoreCourseModuleHandler { name = 'AddonModQuiz'; modName = 'quiz'; + supportedFeatures = { + [CoreConstants.FEATURE_GROUPS]: true, + [CoreConstants.FEATURE_GROUPINGS]: true, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_COMPLETION_HAS_RULES]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: true, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: true, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true, + [CoreConstants.FEATURE_CONTROLS_GRADE_VISIBILITY]: true, + [CoreConstants.FEATURE_USES_QUESTIONS]: true + }; + constructor(private courseProvider: CoreCourseProvider) { } /** diff --git a/src/addon/mod/quiz/quiz.module.ts b/src/addon/mod/quiz/quiz.module.ts index e1b652c7e..5f10410cb 100644 --- a/src/addon/mod/quiz/quiz.module.ts +++ b/src/addon/mod/quiz/quiz.module.ts @@ -28,6 +28,7 @@ import { AddonModQuizSyncCronHandler } from './providers/sync-cron-handler'; import { AddonModQuizIndexLinkHandler } from './providers/index-link-handler'; import { AddonModQuizGradeLinkHandler } from './providers/grade-link-handler'; import { AddonModQuizReviewLinkHandler } from './providers/review-link-handler'; +import { AddonModQuizListLinkHandler } from './providers/list-link-handler'; import { AddonModQuizComponentsModule } from './components/components.module'; import { CoreUpdateManagerProvider } from '@providers/update-manager'; @@ -77,7 +78,8 @@ export const ADDON_MOD_QUIZ_PROVIDERS: any[] = [ AddonModQuizSyncCronHandler, AddonModQuizIndexLinkHandler, AddonModQuizGradeLinkHandler, - AddonModQuizReviewLinkHandler + AddonModQuizReviewLinkHandler, + AddonModQuizListLinkHandler ] }) export class AddonModQuizModule { @@ -85,7 +87,8 @@ export class AddonModQuizModule { prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModQuizPrefetchHandler, cronDelegate: CoreCronDelegate, syncHandler: AddonModQuizSyncCronHandler, linksDelegate: CoreContentLinksDelegate, indexHandler: AddonModQuizIndexLinkHandler, gradeHandler: AddonModQuizGradeLinkHandler, - reviewHandler: AddonModQuizReviewLinkHandler, updateManager: CoreUpdateManagerProvider) { + reviewHandler: AddonModQuizReviewLinkHandler, updateManager: CoreUpdateManagerProvider, + listLinkHandler: AddonModQuizListLinkHandler) { moduleDelegate.registerHandler(moduleHandler); prefetchDelegate.registerHandler(prefetchHandler); @@ -93,6 +96,7 @@ export class AddonModQuizModule { linksDelegate.registerHandler(indexHandler); linksDelegate.registerHandler(gradeHandler); linksDelegate.registerHandler(reviewHandler); + linksDelegate.registerHandler(listLinkHandler); // Allow migrating the tables from the old app to the new schema. updateManager.registerSiteTableMigration({ diff --git a/src/addon/mod/resource/lang/en.json b/src/addon/mod/resource/lang/en.json index 54d284bf5..bd7e9cefb 100644 --- a/src/addon/mod/resource/lang/en.json +++ b/src/addon/mod/resource/lang/en.json @@ -1,6 +1,7 @@ { "errorwhileloadingthecontent": "Error while loading the content.", "modifieddate": "Modified {{$a}}", + "modulenameplural": "Files", "openthefile": "Open the file", "uploadeddate": "Uploaded {{$a}}" } \ No newline at end of file diff --git a/src/addon/mod/resource/providers/list-link-handler.ts b/src/addon/mod/resource/providers/list-link-handler.ts new file mode 100644 index 000000000..8acc2d435 --- /dev/null +++ b/src/addon/mod/resource/providers/list-link-handler.ts @@ -0,0 +1,41 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; +import { AddonModResourceProvider } from './resource'; + +/** + * Handler to treat links to resource list page. + */ +@Injectable() +export class AddonModResourceListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModResourceListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService, + protected resourceProvider: AddonModResourceProvider) { + super(linkHelper, translate, 'AddonModResource', 'resource'); + } + + /** + * Check if the handler is enabled on a site level. + * + * @return {boolean|Promise} Whether or not the handler is enabled on a site level. + */ + isEnabled(): boolean | Promise { + return this.resourceProvider.isPluginEnabled(); + } +} diff --git a/src/addon/mod/resource/providers/module-handler.ts b/src/addon/mod/resource/providers/module-handler.ts index 8976ba2cf..a03592261 100644 --- a/src/addon/mod/resource/providers/module-handler.ts +++ b/src/addon/mod/resource/providers/module-handler.ts @@ -34,6 +34,18 @@ export class AddonModResourceModuleHandler implements CoreCourseModuleHandler { name = 'AddonModResource'; modName = 'resource'; + supportedFeatures = { + [CoreConstants.FEATURE_MOD_ARCHETYPE]: CoreConstants.MOD_ARCHETYPE_RESOURCE, + [CoreConstants.FEATURE_GROUPS]: false, + [CoreConstants.FEATURE_GROUPINGS]: false, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: false, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: false, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true + }; + protected statusObserver; constructor(protected resourceProvider: AddonModResourceProvider, private courseProvider: CoreCourseProvider, diff --git a/src/addon/mod/resource/resource.module.ts b/src/addon/mod/resource/resource.module.ts index 528e383e7..7d0726dca 100644 --- a/src/addon/mod/resource/resource.module.ts +++ b/src/addon/mod/resource/resource.module.ts @@ -18,6 +18,7 @@ import { AddonModResourceModuleHandler } from './providers/module-handler'; import { AddonModResourceProvider } from './providers/resource'; import { AddonModResourcePrefetchHandler } from './providers/prefetch-handler'; import { AddonModResourceLinkHandler } from './providers/link-handler'; +import { AddonModResourceListLinkHandler } from './providers/list-link-handler'; import { AddonModResourcePluginFileHandler } from './providers/pluginfile-handler'; import { AddonModResourceHelperProvider } from './providers/helper'; import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate'; @@ -42,6 +43,7 @@ export const ADDON_MOD_RESOURCE_PROVIDERS: any[] = [ AddonModResourceHelperProvider, AddonModResourcePrefetchHandler, AddonModResourceLinkHandler, + AddonModResourceListLinkHandler, AddonModResourcePluginFileHandler ] }) @@ -49,10 +51,13 @@ export class AddonModResourceModule { constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModResourceModuleHandler, prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModResourcePrefetchHandler, contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModResourceLinkHandler, - pluginfileDelegate: CorePluginFileDelegate, pluginfileHandler: AddonModResourcePluginFileHandler) { + pluginfileDelegate: CorePluginFileDelegate, pluginfileHandler: AddonModResourcePluginFileHandler, + listLinkHandler: AddonModResourceListLinkHandler) { + moduleDelegate.registerHandler(moduleHandler); prefetchDelegate.registerHandler(prefetchHandler); contentLinksDelegate.registerHandler(linkHandler); + contentLinksDelegate.registerHandler(listLinkHandler); pluginfileDelegate.registerHandler(pluginfileHandler); } } diff --git a/src/addon/mod/scorm/lang/en.json b/src/addon/mod/scorm/lang/en.json index 038f4b33a..cef1c9efe 100644 --- a/src/addon/mod/scorm/lang/en.json +++ b/src/addon/mod/scorm/lang/en.json @@ -33,6 +33,7 @@ "incomplete": "Incomplete", "lastattempt": "Last completed attempt", "mode": "Mode", + "modulenameplural": "SCORM packages", "newattempt": "Start a new attempt", "noattemptsallowed": "Number of attempts allowed", "noattemptsmade": "Number of attempts you have made", diff --git a/src/addon/mod/scorm/providers/list-link-handler.ts b/src/addon/mod/scorm/providers/list-link-handler.ts new file mode 100644 index 000000000..ab366a609 --- /dev/null +++ b/src/addon/mod/scorm/providers/list-link-handler.ts @@ -0,0 +1,30 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; + +/** + * Handler to treat links to SCORM list page. + */ +@Injectable() +export class AddonModScormListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModScormListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService) { + super(linkHelper, translate, 'AddonModScorm', 'scorm'); + } +} diff --git a/src/addon/mod/scorm/providers/module-handler.ts b/src/addon/mod/scorm/providers/module-handler.ts index 217c0c432..f5d2a649b 100644 --- a/src/addon/mod/scorm/providers/module-handler.ts +++ b/src/addon/mod/scorm/providers/module-handler.ts @@ -17,6 +17,7 @@ import { NavController, NavOptions } from 'ionic-angular'; import { AddonModScormIndexComponent } from '../components/index/index'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreCourseProvider } from '@core/course/providers/course'; +import { CoreConstants } from '@core/constants'; /** * Handler to support SCORM modules. @@ -26,6 +27,18 @@ export class AddonModScormModuleHandler implements CoreCourseModuleHandler { name = 'AddonModScorm'; modName = 'scorm'; + supportedFeatures = { + [CoreConstants.FEATURE_GROUPS]: true, + [CoreConstants.FEATURE_GROUPINGS]: true, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_COMPLETION_HAS_RULES]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: true, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: true, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true + }; + constructor(private courseProvider: CoreCourseProvider) { } /** diff --git a/src/addon/mod/scorm/scorm.module.ts b/src/addon/mod/scorm/scorm.module.ts index eae867ecb..95961aad6 100644 --- a/src/addon/mod/scorm/scorm.module.ts +++ b/src/addon/mod/scorm/scorm.module.ts @@ -25,6 +25,7 @@ import { AddonModScormPrefetchHandler } from './providers/prefetch-handler'; import { AddonModScormSyncCronHandler } from './providers/sync-cron-handler'; import { AddonModScormIndexLinkHandler } from './providers/index-link-handler'; import { AddonModScormGradeLinkHandler } from './providers/grade-link-handler'; +import { AddonModScormListLinkHandler } from './providers/list-link-handler'; import { AddonModScormSyncProvider } from './providers/scorm-sync'; import { AddonModScormComponentsModule } from './components/components.module'; import { CoreUpdateManagerProvider } from '@providers/update-manager'; @@ -52,7 +53,8 @@ export const ADDON_MOD_SCORM_PROVIDERS: any[] = [ AddonModScormPrefetchHandler, AddonModScormSyncCronHandler, AddonModScormIndexLinkHandler, - AddonModScormGradeLinkHandler + AddonModScormGradeLinkHandler, + AddonModScormListLinkHandler ] }) export class AddonModScormModule { @@ -60,13 +62,14 @@ export class AddonModScormModule { prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModScormPrefetchHandler, cronDelegate: CoreCronDelegate, syncHandler: AddonModScormSyncCronHandler, linksDelegate: CoreContentLinksDelegate, indexHandler: AddonModScormIndexLinkHandler, gradeHandler: AddonModScormGradeLinkHandler, - updateManager: CoreUpdateManagerProvider) { + updateManager: CoreUpdateManagerProvider, listLinkHandler: AddonModScormListLinkHandler) { moduleDelegate.registerHandler(moduleHandler); prefetchDelegate.registerHandler(prefetchHandler); cronDelegate.register(syncHandler); linksDelegate.registerHandler(indexHandler); linksDelegate.registerHandler(gradeHandler); + linksDelegate.registerHandler(listLinkHandler); // Allow migrating the tables from the old app to the new schema. updateManager.registerSiteTablesMigration([ diff --git a/src/addon/mod/survey/lang/en.json b/src/addon/mod/survey/lang/en.json index a8769f7cb..9ccaff870 100644 --- a/src/addon/mod/survey/lang/en.json +++ b/src/addon/mod/survey/lang/en.json @@ -3,6 +3,7 @@ "errorgetsurvey": "Error getting survey data.", "ifoundthat": "I found that", "ipreferthat": "I prefer that", + "modulenameplural": "Surveys", "responses": "Responses", "results": "Results", "surveycompletednograph": "You have completed this survey." diff --git a/src/addon/mod/survey/providers/list-link-handler.ts b/src/addon/mod/survey/providers/list-link-handler.ts new file mode 100644 index 000000000..5d856a4c0 --- /dev/null +++ b/src/addon/mod/survey/providers/list-link-handler.ts @@ -0,0 +1,30 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; + +/** + * Handler to treat links to survey list page. + */ +@Injectable() +export class AddonModSurveyListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModSurveyListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService) { + super(linkHelper, translate, 'AddonModSurvey', 'survey'); + } +} diff --git a/src/addon/mod/survey/providers/module-handler.ts b/src/addon/mod/survey/providers/module-handler.ts index 01a526702..cc84664c7 100644 --- a/src/addon/mod/survey/providers/module-handler.ts +++ b/src/addon/mod/survey/providers/module-handler.ts @@ -17,6 +17,7 @@ import { NavController, NavOptions } from 'ionic-angular'; import { AddonModSurveyIndexComponent } from '../components/index/index'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreCourseProvider } from '@core/course/providers/course'; +import { CoreConstants } from '@core/constants'; /** * Handler to support survey modules. @@ -26,6 +27,18 @@ export class AddonModSurveyModuleHandler implements CoreCourseModuleHandler { name = 'AddonModSurvey'; modName = 'survey'; + supportedFeatures = { + [CoreConstants.FEATURE_GROUPS]: true, + [CoreConstants.FEATURE_GROUPINGS]: true, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_COMPLETION_HAS_RULES]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: false, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: false, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true + }; + constructor(private courseProvider: CoreCourseProvider) { } /** diff --git a/src/addon/mod/survey/survey.module.ts b/src/addon/mod/survey/survey.module.ts index eba73d4a0..7a53a63a8 100644 --- a/src/addon/mod/survey/survey.module.ts +++ b/src/addon/mod/survey/survey.module.ts @@ -21,6 +21,7 @@ import { AddonModSurveyComponentsModule } from './components/components.module'; import { AddonModSurveyModuleHandler } from './providers/module-handler'; import { AddonModSurveyProvider } from './providers/survey'; import { AddonModSurveyLinkHandler } from './providers/link-handler'; +import { AddonModSurveyListLinkHandler } from './providers/list-link-handler'; import { AddonModSurveyHelperProvider } from './providers/helper'; import { AddonModSurveyPrefetchHandler } from './providers/prefetch-handler'; import { AddonModSurveySyncProvider } from './providers/sync'; @@ -50,6 +51,7 @@ export const ADDON_MOD_SURVEY_PROVIDERS: any[] = [ AddonModSurveyModuleHandler, AddonModSurveyPrefetchHandler, AddonModSurveyLinkHandler, + AddonModSurveyListLinkHandler, AddonModSurveySyncCronHandler ] }) @@ -57,11 +59,13 @@ export class AddonModSurveyModule { constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModSurveyModuleHandler, prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModSurveyPrefetchHandler, contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModSurveyLinkHandler, - cronDelegate: CoreCronDelegate, syncHandler: AddonModSurveySyncCronHandler, updateManager: CoreUpdateManagerProvider) { + cronDelegate: CoreCronDelegate, syncHandler: AddonModSurveySyncCronHandler, updateManager: CoreUpdateManagerProvider, + listLinkHandler: AddonModSurveyListLinkHandler) { moduleDelegate.registerHandler(moduleHandler); prefetchDelegate.registerHandler(prefetchHandler); contentLinksDelegate.registerHandler(linkHandler); + contentLinksDelegate.registerHandler(listLinkHandler); cronDelegate.register(syncHandler); // Allow migrating the tables from the old app to the new schema. diff --git a/src/addon/mod/url/lang/en.json b/src/addon/mod/url/lang/en.json index 7d905f0cf..18eff8be5 100644 --- a/src/addon/mod/url/lang/en.json +++ b/src/addon/mod/url/lang/en.json @@ -1,4 +1,5 @@ { "accessurl": "Access the URL", + "modulenameplural": "URLs", "pointingtourl": "URL that the resource points to." } \ No newline at end of file diff --git a/src/addon/mod/url/providers/list-link-handler.ts b/src/addon/mod/url/providers/list-link-handler.ts new file mode 100644 index 000000000..857bb08fb --- /dev/null +++ b/src/addon/mod/url/providers/list-link-handler.ts @@ -0,0 +1,30 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; + +/** + * Handler to treat links to URL list page. + */ +@Injectable() +export class AddonModUrlListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModUrlListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService) { + super(linkHelper, translate, 'AddonModUrl', 'url'); + } +} diff --git a/src/addon/mod/url/providers/module-handler.ts b/src/addon/mod/url/providers/module-handler.ts index e182343fb..7043c23e1 100644 --- a/src/addon/mod/url/providers/module-handler.ts +++ b/src/addon/mod/url/providers/module-handler.ts @@ -31,6 +31,18 @@ export class AddonModUrlModuleHandler implements CoreCourseModuleHandler { name = 'AddonModUrl'; modName = 'url'; + supportedFeatures = { + [CoreConstants.FEATURE_MOD_ARCHETYPE]: CoreConstants.MOD_ARCHETYPE_RESOURCE, + [CoreConstants.FEATURE_GROUPS]: false, + [CoreConstants.FEATURE_GROUPINGS]: false, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: false, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: false, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true + }; + constructor(private courseProvider: CoreCourseProvider, private urlProvider: AddonModUrlProvider, private urlHelper: AddonModUrlHelperProvider, private domUtils: CoreDomUtilsProvider, private contentLinksHelper: CoreContentLinksHelperProvider) { } diff --git a/src/addon/mod/url/url.module.ts b/src/addon/mod/url/url.module.ts index 967025119..868a87d75 100644 --- a/src/addon/mod/url/url.module.ts +++ b/src/addon/mod/url/url.module.ts @@ -17,6 +17,7 @@ import { AddonModUrlComponentsModule } from './components/components.module'; import { AddonModUrlModuleHandler } from './providers/module-handler'; import { AddonModUrlProvider } from './providers/url'; import { AddonModUrlLinkHandler } from './providers/link-handler'; +import { AddonModUrlListLinkHandler } from './providers/list-link-handler'; import { AddonModUrlHelperProvider } from './providers/helper'; import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate'; import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate'; @@ -37,13 +38,17 @@ export const ADDON_MOD_URL_PROVIDERS: any[] = [ AddonModUrlProvider, AddonModUrlHelperProvider, AddonModUrlModuleHandler, - AddonModUrlLinkHandler + AddonModUrlLinkHandler, + AddonModUrlListLinkHandler ] }) export class AddonModUrlModule { constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModUrlModuleHandler, - contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModUrlLinkHandler) { + contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModUrlLinkHandler, + listLinkHandler: AddonModUrlListLinkHandler) { + moduleDelegate.registerHandler(moduleHandler); contentLinksDelegate.registerHandler(linkHandler); + contentLinksDelegate.registerHandler(listLinkHandler); } } diff --git a/src/addon/mod/wiki/lang/en.json b/src/addon/mod/wiki/lang/en.json index e8d9a0d78..29ed054ce 100644 --- a/src/addon/mod/wiki/lang/en.json +++ b/src/addon/mod/wiki/lang/en.json @@ -6,6 +6,7 @@ "errornowikiavailable": "This wiki does not have any content yet.", "gowikihome": "Go to the wiki first page", "map": "Map", + "modulenameplural": "Wikis", "newpagehdr": "New page", "newpagetitle": "New page title", "nocontent": "There is no content for this page", diff --git a/src/addon/mod/wiki/providers/list-link-handler.ts b/src/addon/mod/wiki/providers/list-link-handler.ts new file mode 100644 index 000000000..1be40c6ea --- /dev/null +++ b/src/addon/mod/wiki/providers/list-link-handler.ts @@ -0,0 +1,30 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; + +/** + * Handler to treat links to wiki list page. + */ +@Injectable() +export class AddonModWikiListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModWikiListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService) { + super(linkHelper, translate, 'AddonModWiki', 'wiki'); + } +} diff --git a/src/addon/mod/wiki/providers/module-handler.ts b/src/addon/mod/wiki/providers/module-handler.ts index 80a514580..f36fc1bbb 100644 --- a/src/addon/mod/wiki/providers/module-handler.ts +++ b/src/addon/mod/wiki/providers/module-handler.ts @@ -17,6 +17,7 @@ import { NavController, NavOptions } from 'ionic-angular'; import { AddonModWikiIndexComponent } from '../components/index/index'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreCourseProvider } from '@core/course/providers/course'; +import { CoreConstants } from '@core/constants'; /** * Handler to support wiki modules. @@ -26,6 +27,19 @@ export class AddonModWikiModuleHandler implements CoreCourseModuleHandler { name = 'AddonModWiki'; modName = 'wiki'; + supportedFeatures = { + [CoreConstants.FEATURE_GROUPS]: true, + [CoreConstants.FEATURE_GROUPINGS]: true, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: false, + [CoreConstants.FEATURE_GRADE_OUTCOMES]: false, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true, + [CoreConstants.FEATURE_RATE]: false, + [CoreConstants.FEATURE_COMMENT]: true + }; + constructor(private courseProvider: CoreCourseProvider) { } /** diff --git a/src/addon/mod/wiki/wiki.module.ts b/src/addon/mod/wiki/wiki.module.ts index e8a8582c1..539b962dd 100644 --- a/src/addon/mod/wiki/wiki.module.ts +++ b/src/addon/mod/wiki/wiki.module.ts @@ -28,6 +28,7 @@ import { AddonModWikiIndexLinkHandler } from './providers/index-link-handler'; import { AddonModWikiPageOrMapLinkHandler } from './providers/page-or-map-link-handler'; import { AddonModWikiCreateLinkHandler } from './providers/create-link-handler'; import { AddonModWikiEditLinkHandler } from './providers/edit-link-handler'; +import { AddonModWikiListLinkHandler } from './providers/list-link-handler'; import { CoreUpdateManagerProvider } from '@providers/update-manager'; // List of providers (without handlers). @@ -53,7 +54,8 @@ export const ADDON_MOD_WIKI_PROVIDERS: any[] = [ AddonModWikiIndexLinkHandler, AddonModWikiPageOrMapLinkHandler, AddonModWikiCreateLinkHandler, - AddonModWikiEditLinkHandler + AddonModWikiEditLinkHandler, + AddonModWikiListLinkHandler ] }) export class AddonModWikiModule { @@ -62,7 +64,7 @@ export class AddonModWikiModule { cronDelegate: CoreCronDelegate, syncHandler: AddonModWikiSyncCronHandler, linksDelegate: CoreContentLinksDelegate, indexHandler: AddonModWikiIndexLinkHandler, pageOrMapHandler: AddonModWikiPageOrMapLinkHandler, createHandler: AddonModWikiCreateLinkHandler, editHandler: AddonModWikiEditLinkHandler, - updateManager: CoreUpdateManagerProvider) { + updateManager: CoreUpdateManagerProvider, listLinkHandler: AddonModWikiListLinkHandler) { moduleDelegate.registerHandler(moduleHandler); prefetchDelegate.registerHandler(prefetchHandler); @@ -71,6 +73,7 @@ export class AddonModWikiModule { linksDelegate.registerHandler(pageOrMapHandler); linksDelegate.registerHandler(createHandler); linksDelegate.registerHandler(editHandler); + linksDelegate.registerHandler(listLinkHandler); // Allow migrating the tables from the old app to the new schema. updateManager.registerSiteTableMigration({ diff --git a/src/addon/mod/workshop/lang/en.json b/src/addon/mod/workshop/lang/en.json index 4a2056785..72d1d6a0d 100644 --- a/src/addon/mod/workshop/lang/en.json +++ b/src/addon/mod/workshop/lang/en.json @@ -26,6 +26,7 @@ "gradinggradecalculated": "Calculated grade for assessment", "gradinggradeof": "Grade for assessment (of {{$a}})", "gradinggradeover": "Override grade for assessment", + "modulenameplural": "Workshops", "nogradeyet": "No grade yet", "notassessed": "Not assessed yet", "notoverridden": "Not overridden", diff --git a/src/addon/mod/workshop/providers/list-link-handler.ts b/src/addon/mod/workshop/providers/list-link-handler.ts new file mode 100644 index 000000000..db2bfb9cc --- /dev/null +++ b/src/addon/mod/workshop/providers/list-link-handler.ts @@ -0,0 +1,41 @@ +// (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 } from '@angular/core'; +import { CoreContentLinksModuleListHandler } from '@core/contentlinks/classes/module-list-handler'; +import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; +import { TranslateService } from '@ngx-translate/core'; +import { AddonModWorkshopProvider } from './workshop'; + +/** + * Handler to treat links to workshop list page. + */ +@Injectable() +export class AddonModWorkshopListLinkHandler extends CoreContentLinksModuleListHandler { + name = 'AddonModWorkshopListLinkHandler'; + + constructor(linkHelper: CoreContentLinksHelperProvider, translate: TranslateService, + protected workshopProvider: AddonModWorkshopProvider) { + super(linkHelper, translate, 'AddonModWorkshop', 'workshop'); + } + + /** + * Check if the handler is enabled on a site level. + * + * @return {Promise} Whether or not the handler is enabled on a site level. + */ + isEnabled(): Promise { + return this.workshopProvider.isPluginEnabled(); + } +} diff --git a/src/addon/mod/workshop/providers/module-handler.ts b/src/addon/mod/workshop/providers/module-handler.ts index bb275e5d9..56ed78ded 100644 --- a/src/addon/mod/workshop/providers/module-handler.ts +++ b/src/addon/mod/workshop/providers/module-handler.ts @@ -18,6 +18,7 @@ import { AddonModWorkshopIndexComponent } from '../components/index/index'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreCourseProvider } from '@core/course/providers/course'; import { AddonModWorkshopProvider } from './workshop'; +import { CoreConstants } from '@core/constants'; /** * Handler to support workshop modules. @@ -27,6 +28,17 @@ export class AddonModWorkshopModuleHandler implements CoreCourseModuleHandler { name = 'AddonModWorkshop'; modName = 'workshop'; + supportedFeatures = { + [CoreConstants.FEATURE_GROUPS]: true, + [CoreConstants.FEATURE_GROUPINGS]: true, + [CoreConstants.FEATURE_MOD_INTRO]: true, + [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true, + [CoreConstants.FEATURE_GRADE_HAS_GRADE]: true, + [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, + [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true, + [CoreConstants.FEATURE_PLAGIARISM]: true + }; + constructor(private courseProvider: CoreCourseProvider, private workshopProvider: AddonModWorkshopProvider) { } /** diff --git a/src/addon/mod/workshop/workshop.module.ts b/src/addon/mod/workshop/workshop.module.ts index cff6c9151..3e52d8654 100644 --- a/src/addon/mod/workshop/workshop.module.ts +++ b/src/addon/mod/workshop/workshop.module.ts @@ -22,6 +22,7 @@ import { AddonModWorkshopComponentsModule } from './components/components.module import { AddonModWorkshopModuleHandler } from './providers/module-handler'; import { AddonModWorkshopProvider } from './providers/workshop'; import { AddonModWorkshopLinkHandler } from './providers/link-handler'; +import { AddonModWorkshopListLinkHandler } from './providers/list-link-handler'; import { AddonModWorkshopOfflineProvider } from './providers/offline'; import { AddonModWorkshopSyncProvider } from './providers/sync'; import { AddonModWorkshopHelperProvider } from './providers/helper'; @@ -50,6 +51,7 @@ export const ADDON_MOD_WORKSHOP_PROVIDERS: any[] = [ AddonModWorkshopProvider, AddonModWorkshopModuleHandler, AddonModWorkshopLinkHandler, + AddonModWorkshopListLinkHandler, AddonModWorkshopOfflineProvider, AddonModWorkshopSyncProvider, AddonModWorkshopHelperProvider, @@ -63,10 +65,11 @@ export class AddonModWorkshopModule { contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModWorkshopLinkHandler, prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModWorkshopPrefetchHandler, cronDelegate: CoreCronDelegate, syncHandler: AddonModWorkshopSyncCronHandler, - updateManager: CoreUpdateManagerProvider) { + updateManager: CoreUpdateManagerProvider, listLinkHandler: AddonModWorkshopListLinkHandler) { moduleDelegate.registerHandler(moduleHandler); contentLinksDelegate.registerHandler(linkHandler); + contentLinksDelegate.registerHandler(listLinkHandler); prefetchDelegate.registerHandler(prefetchHandler); cronDelegate.register(syncHandler); diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 6fe4d4970..04988829d 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -75,6 +75,7 @@ import { CoreSitePluginsModule } from '@core/siteplugins/siteplugins.module'; import { CoreCompileModule } from '@core/compile/compile.module'; import { CoreQuestionModule } from '@core/question/question.module'; import { CoreCommentsModule } from '@core/comments/comments.module'; +import { CoreBlockModule } from '@core/block/block.module'; // Addon modules. import { AddonBadgesModule } from '@addon/badges/badges.module'; @@ -83,7 +84,9 @@ import { AddonCompetencyModule } from '@addon/competency/competency.module'; import { AddonCourseCompletionModule } from '@addon/coursecompletion/coursecompletion.module'; import { AddonUserProfileFieldModule } from '@addon/userprofilefield/userprofilefield.module'; import { AddonFilesModule } from '@addon/files/files.module'; +import { AddonBlockActivityModulesModule } from '@addon/block/activitymodules/activitymodules.module'; import { AddonBlockMyOverviewModule } from '@addon/block/myoverview/myoverview.module'; +import { AddonBlockSiteMainMenuModule } from '@addon/block/sitemainmenu/sitemainmenu.module'; import { AddonBlockTimelineModule } from '@addon/block/timeline/timeline.module'; import { AddonModAssignModule } from '@addon/mod/assign/assign.module'; import { AddonModBookModule } from '@addon/mod/book/book.module'; @@ -188,13 +191,16 @@ export const CORE_PROVIDERS: any[] = [ CoreCompileModule, CoreQuestionModule, CoreCommentsModule, + CoreBlockModule, AddonBadgesModule, AddonCalendarModule, AddonCompetencyModule, AddonCourseCompletionModule, AddonUserProfileFieldModule, AddonFilesModule, + AddonBlockActivityModulesModule, AddonBlockMyOverviewModule, + AddonBlockSiteMainMenuModule, AddonBlockTimelineModule, AddonModAssignModule, AddonModBookModule, diff --git a/src/assets/lang/en.json b/src/assets/lang/en.json index caa2d624c..5cd0e4be3 100644 --- a/src/assets/lang/en.json +++ b/src/assets/lang/en.json @@ -10,6 +10,7 @@ "addon.badges.issuername": "Issuer name", "addon.badges.nobadges": "There are no badges available.", "addon.badges.recipientdetails": "Recipient details", + "addon.block_activitymodules.pluginname": "Activities", "addon.block_myoverview.all": "All", "addon.block_myoverview.future": "Future", "addon.block_myoverview.inprogress": "In progress", @@ -20,6 +21,7 @@ "addon.block_myoverview.nocoursespast": "No past courses", "addon.block_myoverview.past": "Past", "addon.block_myoverview.title": "Title", + "addon.block_sitemainmenu.pluginname": "Main menu", "addon.block_timeline.duedate": "Due date", "addon.block_timeline.next30days": "Next 30 days", "addon.block_timeline.next3months": "Next 3 months", @@ -202,6 +204,7 @@ "addon.mod_assign.markingworkflowstatereadyforrelease": "Ready for release", "addon.mod_assign.markingworkflowstatereadyforreview": "Marking completed", "addon.mod_assign.markingworkflowstatereleased": "Released", + "addon.mod_assign.modulenameplural": "Assignments", "addon.mod_assign.multipleteams": "Member of more than one group", "addon.mod_assign.multipleteams_desc": "The assignment requires submission in groups. You are a member of more than one group. To be able to submit you must be a member of only one group. Please contact your teacher to change your group membership.", "addon.mod_assign.noattempt": "No attempt", @@ -256,6 +259,7 @@ "addon.mod_assign_submission_file.pluginname": "File submissions", "addon.mod_assign_submission_onlinetext.pluginname": "Online text submissions", "addon.mod_book.errorchapter": "Error reading chapter of book.", + "addon.mod_book.modulenameplural": "Books", "addon.mod_chat.beep": "Beep", "addon.mod_chat.currentusers": "Current users", "addon.mod_chat.enterchat": "Click here to enter the chat now", @@ -268,6 +272,7 @@ "addon.mod_chat.messagebeepsyou": "{{$a}} has just beeped you!", "addon.mod_chat.messageenter": "{{$a}} has just entered this chat", "addon.mod_chat.messageexit": "{{$a}} has left this chat", + "addon.mod_chat.modulenameplural": "Chats", "addon.mod_chat.mustbeonlinetosendmessages": "You must be online to send messages.", "addon.mod_chat.nomessages": "No messages yet", "addon.mod_chat.send": "Send", @@ -278,6 +283,7 @@ "addon.mod_choice.errorgetchoice": "Error getting choice data.", "addon.mod_choice.expired": "Sorry, this activity closed on {{$a}} and is no longer available", "addon.mod_choice.full": "(Full)", + "addon.mod_choice.modulenameplural": "Choices", "addon.mod_choice.noresultsviewable": "The results are not currently viewable.", "addon.mod_choice.notopenyet": "Sorry, this activity is not available until {{$a}}", "addon.mod_choice.numberofuser": "Number of responses", @@ -317,6 +323,7 @@ "addon.mod_data.fields": "Fields", "addon.mod_data.latlongboth": "Both latitude and longitude are required.", "addon.mod_data.menuchoose": "Choose...", + "addon.mod_data.modulenameplural": "Databases", "addon.mod_data.more": "More", "addon.mod_data.nomatch": "No matching entries found!", "addon.mod_data.norecords": "No entries in database", @@ -348,6 +355,7 @@ "addon.mod_feedback.feedbackopen": "Allow answers from", "addon.mod_feedback.mapcourses": "Map feedback to courses", "addon.mod_feedback.mode": "Mode", + "addon.mod_feedback.modulenameplural": "Feedback", "addon.mod_feedback.next_page": "Next page", "addon.mod_feedback.non_anonymous": "User's name will be logged and shown with answers", "addon.mod_feedback.non_anonymous_entries": "Non anonymous entries ({{$a}})", @@ -368,6 +376,7 @@ "addon.mod_feedback.started": "Started", "addon.mod_feedback.this_feedback_is_already_submitted": "You've already completed this activity.", "addon.mod_folder.emptyfilelist": "There are no files to show.", + "addon.mod_folder.modulenameplural": "Folders", "addon.mod_forum.addanewdiscussion": "Add a new discussion topic", "addon.mod_forum.addanewquestion": "Add a new question", "addon.mod_forum.addanewtopic": "Add a new topic", @@ -390,6 +399,7 @@ "addon.mod_forum.modeflatnewestfirst": "Display replies flat, with newest first", "addon.mod_forum.modeflatoldestfirst": "Display replies flat, with oldest first", "addon.mod_forum.modenested": "Display replies in nested form", + "addon.mod_forum.modulenameplural": "Forums", "addon.mod_forum.numdiscussions": "{{numdiscussions}} discussions", "addon.mod_forum.numreplies": "{{numreplies}} replies", "addon.mod_forum.posttoforum": "Post to forum", @@ -425,9 +435,11 @@ "addon.mod_glossary.fillfields": "Concept and definition are mandatory fields.", "addon.mod_glossary.fullmatch": "Match whole words only", "addon.mod_glossary.linking": "Auto-linking", + "addon.mod_glossary.modulenameplural": "Glossaries", "addon.mod_glossary.noentriesfound": "No entries were found.", "addon.mod_glossary.searchquery": "Search query", "addon.mod_imscp.deploymenterror": "Content package error!", + "addon.mod_imscp.modulenameplural": "IMS content packages", "addon.mod_imscp.showmoduledescription": "Show description", "addon.mod_lesson.answer": "Answer", "addon.mod_lesson.attempt": "Attempt: {{$a}}", @@ -471,6 +483,7 @@ "addon.mod_lesson.lowtime": "Low time", "addon.mod_lesson.maximumnumberofattemptsreached": "Maximum number of attempts reached - Moving to next page", "addon.mod_lesson.modattemptsnoteacher": "Student review only works for students.", + "addon.mod_lesson.modulenameplural": "Lessons", "addon.mod_lesson.noanswer": "One or more questions have no answer given. Please go back and submit an answer.", "addon.mod_lesson.nolessonattempts": "No attempts have been made on this lesson.", "addon.mod_lesson.nolessonattemptsgroup": "No attempts have been made by {{$a}} group members on this lesson.", @@ -515,7 +528,9 @@ "addon.mod_lti.errorgetlti": "Error getting module data.", "addon.mod_lti.errorinvalidlaunchurl": "The launch URL is not valid.", "addon.mod_lti.launchactivity": "Launch the activity", + "addon.mod_lti.modulenameplural": "External tools", "addon.mod_page.errorwhileloadingthepage": "Error while loading the page content.", + "addon.mod_page.modulenameplural": "Pages", "addon.mod_quiz.attemptfirst": "First attempt", "addon.mod_quiz.attemptlast": "Last attempt", "addon.mod_quiz.attemptnumber": "Attempt", @@ -550,6 +565,7 @@ "addon.mod_quiz.grademethod": "Grading method", "addon.mod_quiz.gradesofar": "{{$a.method}}: {{$a.mygrade}} / {{$a.quizgrade}}.", "addon.mod_quiz.marks": "Marks", + "addon.mod_quiz.modulenameplural": "Quizzes", "addon.mod_quiz.mustbesubmittedby": "This attempt must be submitted by {{$a}}.", "addon.mod_quiz.noquestions": "No questions have been added yet", "addon.mod_quiz.noreviewattempt": "You are not allowed to review this attempt.", @@ -594,6 +610,7 @@ "addon.mod_quiz.yourfinalgradeis": "Your final grade for this quiz is {{$a}}.", "addon.mod_resource.errorwhileloadingthecontent": "Error while loading the content.", "addon.mod_resource.modifieddate": "Modified {{$a}}", + "addon.mod_resource.modulenameplural": "Files", "addon.mod_resource.openthefile": "Open the file", "addon.mod_resource.uploadeddate": "Uploaded {{$a}}", "addon.mod_scorm.asset": "Asset", @@ -630,6 +647,7 @@ "addon.mod_scorm.incomplete": "Incomplete", "addon.mod_scorm.lastattempt": "Last completed attempt", "addon.mod_scorm.mode": "Mode", + "addon.mod_scorm.modulenameplural": "SCORM packages", "addon.mod_scorm.newattempt": "Start a new attempt", "addon.mod_scorm.noattemptsallowed": "Number of attempts allowed", "addon.mod_scorm.noattemptsmade": "Number of attempts you have made", @@ -649,10 +667,12 @@ "addon.mod_survey.errorgetsurvey": "Error getting survey data.", "addon.mod_survey.ifoundthat": "I found that", "addon.mod_survey.ipreferthat": "I prefer that", + "addon.mod_survey.modulenameplural": "Surveys", "addon.mod_survey.responses": "Responses", "addon.mod_survey.results": "Results", "addon.mod_survey.surveycompletednograph": "You have completed this survey.", "addon.mod_url.accessurl": "Access the URL", + "addon.mod_url.modulenameplural": "URLs", "addon.mod_url.pointingtourl": "URL that the resource points to.", "addon.mod_wiki.cannoteditpage": "You can not edit this page.", "addon.mod_wiki.createpage": "Create page", @@ -661,6 +681,7 @@ "addon.mod_wiki.errornowikiavailable": "This wiki does not have any content yet.", "addon.mod_wiki.gowikihome": "Go to the wiki first page", "addon.mod_wiki.map": "Map", + "addon.mod_wiki.modulenameplural": "Wikis", "addon.mod_wiki.newpagehdr": "New page", "addon.mod_wiki.newpagetitle": "New page title", "addon.mod_wiki.nocontent": "There is no content for this page", @@ -699,6 +720,7 @@ "addon.mod_workshop.gradinggradecalculated": "Calculated grade for assessment", "addon.mod_workshop.gradinggradeof": "Grade for assessment (of {{$a}})", "addon.mod_workshop.gradinggradeover": "Override grade for assessment", + "addon.mod_workshop.modulenameplural": "Workshops", "addon.mod_workshop.nogradeyet": "No grade yet", "addon.mod_workshop.notassessed": "Not assessed yet", "addon.mod_workshop.notoverridden": "Not overridden", @@ -1467,6 +1489,7 @@ "core.refresh": "Refresh", "core.required": "Required", "core.requireduserdatamissing": "This user lacks some required profile data. Please enter the data in your site and try again.
{{$a}}", + "core.resources": "Resources", "core.restore": "Restore", "core.retry": "Retry", "core.save": "Save", diff --git a/src/core/block/block.module.ts b/src/core/block/block.module.ts new file mode 100644 index 000000000..2448c6e1d --- /dev/null +++ b/src/core/block/block.module.ts @@ -0,0 +1,34 @@ +// (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 { CoreBlockDelegate } from './providers/delegate'; +import { CoreBlockDefaultHandler } from './providers/default-block-handler'; + +// List of providers (without handlers). +export const CORE_BLOCK_PROVIDERS: any[] = [ + CoreBlockDelegate +]; + +@NgModule({ + declarations: [], + imports: [ + ], + providers: [ + CoreBlockDelegate, + CoreBlockDefaultHandler + ], + exports: [] +}) +export class CoreBlockModule {} diff --git a/src/addon/block/classes/block-component.ts b/src/core/block/classes/base-block-component.ts similarity index 91% rename from src/addon/block/classes/block-component.ts rename to src/core/block/classes/base-block-component.ts index 3a2282d1c..56cbad4f6 100644 --- a/src/addon/block/classes/block-component.ts +++ b/src/core/block/classes/base-block-component.ts @@ -17,9 +17,9 @@ import { CoreLoggerProvider } from '@providers/logger'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; /** - * Template class to easily create AddonBlockComponent of blocks. + * Template class to easily create components for blocks. */ -export class AddonBlockComponent implements OnInit { +export class CoreBlockBaseComponent implements OnInit { loaded: boolean; // If the component has been loaded. protected fetchContentDefaultError: string; // Default error to show when loading contents. @@ -49,13 +49,9 @@ export class AddonBlockComponent implements OnInit { */ doRefresh(refresher?: any, done?: () => void, showErrors: boolean = false): Promise { if (this.loaded) { - return this.invalidateContent().catch(() => { - // Ignore errors. - }).then(() => { - return this.refreshContent(showErrors).finally(() => { - refresher && refresher.complete(); - done && done(); - }); + return this.refreshContent(showErrors).finally(() => { + refresher && refresher.complete(); + done && done(); }); } diff --git a/src/core/block/classes/base-block-handler.ts b/src/core/block/classes/base-block-handler.ts new file mode 100644 index 000000000..85fe49995 --- /dev/null +++ b/src/core/block/classes/base-block-handler.ts @@ -0,0 +1,56 @@ +// (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 { Injector } from '@angular/core'; +import { CoreBlockHandler, CoreBlockHandlerData } from '../providers/delegate'; + +/** + * Base handler for blocks. + * + * This class is needed because parent classes cannot have @Injectable in Angular v6, so the default handler cannot be a + * parent class. + */ +export class CoreBlockBaseHandler implements CoreBlockHandler { + name = 'CoreBlockBase'; + blockName = 'base'; + + constructor() { + // Nothing to do. + } + + /** + * Whether or not the handler is enabled on a site level. + * + * @return {boolean|Promise} True or promise resolved with true if enabled. + */ + isEnabled(): boolean | Promise { + return true; + } + + /** + * Returns the data needed to render the block. + * + * @param {Injector} injector Injector. + * @param {any} block The block to render. + * @param {string} contextLevel The context where the block will be used. + * @param {number} instanceId The instance ID associated with the context level. + * @return {CoreBlockHandlerData|Promise} Data or promise resolved with the data. + */ + getDisplayData?(injector: Injector, block: any, contextLevel: string, instanceId: number) + : CoreBlockHandlerData | Promise { + + // To be overridden. + return; + } +} diff --git a/src/core/block/components/block/block.ts b/src/core/block/components/block/block.ts new file mode 100644 index 000000000..4d6b67dc0 --- /dev/null +++ b/src/core/block/components/block/block.ts @@ -0,0 +1,104 @@ +// (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, OnInit, Injector, ViewChild } from '@angular/core'; +import { CoreBlockDelegate } from '../../providers/delegate'; +import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-component'; + +/** + * Component to render a block. + */ +@Component({ + selector: 'core-block', + templateUrl: 'core-block.html' +}) +export class CoreBlockComponent implements OnInit { + @ViewChild(CoreDynamicComponent) dynamicComponent: CoreDynamicComponent; + + @Input() block: any; // The block to render. + @Input() contextLevel: string; // The context where the block will be used. + @Input() instanceId: number; // The instance ID associated with the context level. + @Input() extraData: any; // Any extra data to be passed to the block. + + title: string; // The title of the block. + componentClass: any; // The class of the component to render. + data: any = {}; // Data to pass to the component. + class: string; // CSS class to apply to the block. + loaded = false; + + constructor(protected injector: Injector, protected blockDelegate: CoreBlockDelegate) { } + + /** + * Component being initialized. + */ + ngOnInit(): void { + if (!this.block) { + this.loaded = true; + + return; + } + + // Get the data to render the block. + this.blockDelegate.getBlockDisplayData(this.injector, this.block, this.contextLevel, this.instanceId).then((data) => { + if (!data) { + // Block not supported, don't render it. + return; + } + + this.title = data.title; + this.class = data.class; + this.componentClass = data.component; + + // Set up the data needed by the block component. + this.data = Object.assign({ + block: this.block, + contextLevel: this.contextLevel, + instanceId: this.instanceId, + }, this.extraData || {}, data.componentData || {}); + }).catch(() => { + // Ignore errors. + }).finally(() => { + this.loaded = true; + }); + } + + /** + * Refresh the data. + * + * @param {any} [refresher] Refresher. Please pass this only if the refresher should finish when this function finishes. + * @param {Function} [done] Function to call when done. + * @param {boolean} [showErrors=false] If show errors to the user of hide them. + * @return {Promise} Promise resolved when done. + */ + doRefresh(refresher?: any, done?: () => void, showErrors: boolean = false): Promise { + if (this.dynamicComponent) { + return Promise.resolve(this.dynamicComponent.callComponentFunction('doRefresh', [refresher, done, showErrors])); + } + + return Promise.resolve(); + } + + /** + * Invalidate some data. + * + * @return {Promise} Promise resolved when done. + */ + invalidate(): Promise { + if (this.dynamicComponent) { + return Promise.resolve(this.dynamicComponent.callComponentFunction('invalidateContent')); + } + + return Promise.resolve(); + } +} diff --git a/src/core/block/components/block/core-block.html b/src/core/block/components/block/core-block.html new file mode 100644 index 000000000..80ef357de --- /dev/null +++ b/src/core/block/components/block/core-block.html @@ -0,0 +1,6 @@ + +
+ {{ title | translate }} + + +
diff --git a/src/core/block/components/components.module.ts b/src/core/block/components/components.module.ts new file mode 100644 index 000000000..512729b8e --- /dev/null +++ b/src/core/block/components/components.module.ts @@ -0,0 +1,38 @@ +// (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 { CommonModule } from '@angular/common'; +import { IonicModule } from 'ionic-angular'; +import { TranslateModule } from '@ngx-translate/core'; +import { CoreBlockComponent } from './block/block'; +import { CoreComponentsModule } from '@components/components.module'; + +@NgModule({ + declarations: [ + CoreBlockComponent + ], + imports: [ + CommonModule, + IonicModule, + TranslateModule.forChild(), + CoreComponentsModule + ], + providers: [ + ], + exports: [ + CoreBlockComponent + ] +}) +export class CoreBlockComponentsModule {} diff --git a/src/core/block/providers/default-block-handler.ts b/src/core/block/providers/default-block-handler.ts new file mode 100644 index 000000000..c4d04891f --- /dev/null +++ b/src/core/block/providers/default-block-handler.ts @@ -0,0 +1,29 @@ +// (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 } from '@angular/core'; +import { CoreBlockBaseHandler } from '../classes/base-block-handler'; + +/** + * Default handler used when a block type doesn't have a specific implementation. + */ +@Injectable() +export class CoreBlockDefaultHandler extends CoreBlockBaseHandler { + name = 'CoreBlockDefault'; + type = 'default'; + + constructor() { + super(); + } +} diff --git a/src/core/block/providers/delegate.ts b/src/core/block/providers/delegate.ts new file mode 100644 index 000000000..b6d605bfa --- /dev/null +++ b/src/core/block/providers/delegate.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 { Injectable, Injector } from '@angular/core'; +import { CoreLoggerProvider } from '@providers/logger'; +import { CoreEventsProvider } from '@providers/events'; +import { CoreSitesProvider } from '@providers/sites'; +import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; +import { CoreBlockDefaultHandler } from './default-block-handler'; + +/** + * Interface that all blocks must implement. + */ +export interface CoreBlockHandler extends CoreDelegateHandler { + /** + * Name of the block the handler supports. E.g. 'activity_modules'. + * @type {string} + */ + blockName: string; + + /** + * Returns the data needed to render the block. + * + * @param {Injector} injector Injector. + * @param {any} block The block to render. + * @param {string} contextLevel The context where the block will be used. + * @param {number} instanceId The instance ID associated with the context level. + * @return {CoreBlockHandlerData|Promise} Data or promise resolved with the data. + */ + getDisplayData?(injector: Injector, block: any, contextLevel: string, instanceId: number) + : CoreBlockHandlerData | Promise; +} + +/** + * Data needed to render a block. It's returned by the handler. + */ +export interface CoreBlockHandlerData { + /** + * Title to display for the block. + * @type {string} + */ + title: string; + + /** + * Class to add to the displayed block. + * @type {string} + */ + class?: string; + + /** + * The component to render the contents of the block. + * It's recommended to return the class of the component, but you can also return an instance of the component. + * @type {any} + */ + component: any; + + /** + * Data to pass to the component. All the properties in this object will be passed to the component as inputs. + * @type {any} + */ + componentData?: any; +} + +/** + * Delegate to register block handlers. + */ +@Injectable() +export class CoreBlockDelegate extends CoreDelegate { + + protected handlerNameProperty = 'blockName'; + + constructor(logger: CoreLoggerProvider, sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider, + protected defaultHandler: CoreBlockDefaultHandler) { + super('CoreBlockDelegate', logger, sitesProvider, eventsProvider); + } + + /** + * Get the display data for a certain block. + * + * @param {Injector} injector Injector. + * @param {any} block The block to render. + * @param {string} contextLevel The context where the block will be used. + * @param {number} instanceId The instance ID associated with the context level. + * @return {Promise} Promise resolved with the display data. + */ + getBlockDisplayData(injector: Injector, block: any, contextLevel: string, instanceId: number): Promise { + return Promise.resolve(this.executeFunctionOnEnabled(block.name, 'getDisplayData', [injector, block])); + } + + /** + * Check if any of the blocks in a list is supported. + * + * @param {any[]} blocks The list of blocks. + * @return {boolean} Whether any of the blocks is supported. + */ + hasSupportedBlock(blocks: any[]): boolean { + blocks = blocks || []; + + return !!blocks.find((block) => { return this.isBlockSupported(block.name); }); + } + + /** + * Check if a block is supported. + * + * @param {string} name Block "name". E.g. 'activity_modules'. + * @return {boolean} Whether it's supported. + */ + isBlockSupported(name: string): boolean { + return this.hasHandler(name, true); + } +} diff --git a/src/core/compile/providers/compile.ts b/src/core/compile/providers/compile.ts index d49667352..869b5a421 100644 --- a/src/core/compile/providers/compile.ts +++ b/src/core/compile/providers/compile.ts @@ -23,6 +23,7 @@ import { CoreLoggerProvider } from '@providers/logger'; // Import core providers. import { CORE_PROVIDERS } from '@app/app.module'; +import { CORE_BLOCK_PROVIDERS } from '@core/block/block.module'; import { CORE_CONTENTLINKS_PROVIDERS } from '@core/contentlinks/contentlinks.module'; import { CORE_COURSE_PROVIDERS } from '@core/course/course.module'; import { CORE_COURSES_PROVIDERS } from '@core/courses/courses.module'; @@ -70,6 +71,7 @@ import { CoreSitePluginsDirectivesModule } from '@core/siteplugins/directives/di import { CoreSiteHomeComponentsModule } from '@core/sitehome/components/components.module'; import { CoreUserComponentsModule } from '@core/user/components/components.module'; import { CoreQuestionComponentsModule } from '@core/question/components/components.module'; +import { CoreBlockComponentsModule } from '@core/block/components/components.module'; // Import some components listed in entryComponents so they can be injected dynamically. import { CoreCourseUnsupportedModuleComponent } from '@core/course/components/unsupported-module/unsupported-module'; @@ -139,7 +141,7 @@ export class CoreCompileProvider { IonicModule, TranslateModule.forChild(), CoreComponentsModule, CoreDirectivesModule, CorePipesModule, CoreCourseComponentsModule, CoreCoursesComponentsModule, CoreSiteHomeComponentsModule, CoreUserComponentsModule, CoreCourseDirectivesModule, CoreSitePluginsDirectivesModule, CoreQuestionComponentsModule, AddonModAssignComponentsModule, - AddonModWorkshopComponentsModule + AddonModWorkshopComponentsModule, CoreBlockComponentsModule ]; constructor(protected injector: Injector, logger: CoreLoggerProvider, compilerFactory: JitCompilerFactory) { @@ -227,7 +229,7 @@ export class CoreCompileProvider { .concat(ADDON_MOD_QUIZ_PROVIDERS).concat(ADDON_MOD_RESOURCE_PROVIDERS).concat(ADDON_MOD_SCORM_PROVIDERS) .concat(ADDON_MOD_SURVEY_PROVIDERS).concat(ADDON_MOD_URL_PROVIDERS).concat(ADDON_MOD_WIKI_PROVIDERS) .concat(ADDON_MOD_WORKSHOP_PROVIDERS).concat(ADDON_NOTES_PROVIDERS).concat(ADDON_NOTIFICATIONS_PROVIDERS) - .concat(ADDON_PUSHNOTIFICATIONS_PROVIDERS).concat(ADDON_REMOTETHEMES_PROVIDERS); + .concat(ADDON_PUSHNOTIFICATIONS_PROVIDERS).concat(ADDON_REMOTETHEMES_PROVIDERS).concat(CORE_BLOCK_PROVIDERS); // We cannot inject anything to this constructor. Use the Injector to inject all the providers into the instance. for (const i in providers) { diff --git a/src/core/constants.ts b/src/core/constants.ts index 4caf81a4d..79e131672 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -57,4 +57,31 @@ export class CoreConstants { static RESOURCELIB_DISPLAY_DOWNLOAD = 4; // Force download of file instead of display. static RESOURCELIB_DISPLAY_OPEN = 5; // Open directly. static RESOURCELIB_DISPLAY_POPUP = 6; // Open in "emulated" pop-up without navigation. + + // Feature constants. Used to report features that are, or are not, supported by a module. + static FEATURE_GRADE_HAS_GRADE = 'grade_has_grade'; // True if module can provide a grade. + static FEATURE_GRADE_OUTCOMES = 'outcomes'; // True if module supports outcomes. + static FEATURE_ADVANCED_GRADING = 'grade_advanced_grading'; // True if module supports advanced grading methods. + static FEATURE_CONTROLS_GRADE_VISIBILITY = 'controlsgradevisbility'; // True if module controls grade visibility over gradebook. + static FEATURE_PLAGIARISM = 'plagiarism'; // True if module supports plagiarism plugins. + static FEATURE_COMPLETION_TRACKS_VIEWS = 'completion_tracks_views'; // True if module tracks whether somebody viewed it. + static FEATURE_COMPLETION_HAS_RULES = 'completion_has_rules'; // True if module has custom completion rules. + static FEATURE_NO_VIEW_LINK = 'viewlink'; // True if module has no 'view' page (like label). + static FEATURE_IDNUMBER = 'idnumber'; // True if module wants support for setting the ID number for grade calculation purposes. + static FEATURE_GROUPS = 'groups'; // True if module supports groups. + static FEATURE_GROUPINGS = 'groupings'; // True if module supports groupings. + static FEATURE_MOD_ARCHETYPE = 'mod_archetype'; // Type of module. + static FEATURE_MOD_INTRO = 'mod_intro'; // True if module supports intro editor. + static FEATURE_MODEDIT_DEFAULT_COMPLETION = 'modedit_default_completion'; // True if module has default completion. + static FEATURE_COMMENT = 'comment'; + static FEATURE_RATE = 'rate'; + static FEATURE_BACKUP_MOODLE2 = 'backup_moodle2'; // True if module supports backup/restore of moodle2 format. + static FEATURE_SHOW_DESCRIPTION = 'showdescription'; // True if module can show description on course main page. + static FEATURE_USES_QUESTIONS = 'usesquestions'; // True if module uses the question bank. + + // Pssobile archetypes for modules. + static MOD_ARCHETYPE_OTHER = 0; // Unspecified module archetype. + static MOD_ARCHETYPE_RESOURCE = 1; // Resource-like type module. + static MOD_ARCHETYPE_ASSIGNMENT = 2; // Assignment module archetype. + static MOD_ARCHETYPE_SYSTEM = 3; // System (not user-addable) module archetype. } diff --git a/src/core/contentlinks/classes/module-list-handler.ts b/src/core/contentlinks/classes/module-list-handler.ts new file mode 100644 index 000000000..5fa6c41a7 --- /dev/null +++ b/src/core/contentlinks/classes/module-list-handler.ts @@ -0,0 +1,71 @@ +// (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 { CoreContentLinksAction } from '../providers/delegate'; +import { CoreContentLinksHelperProvider } from '../providers/helper'; +import { CoreContentLinksHandlerBase } from './base-handler'; +import { TranslateService } from '@ngx-translate/core'; + +/** + * Handler to handle URLs pointing to a list of a certain type of modules. + */ +export class CoreContentLinksModuleListHandler extends CoreContentLinksHandlerBase { + + /** + * The title to use in the new page. If not defined, the app will try to calculate it. + * @type {string} + */ + protected title: string; + + /** + * Construct the handler. + * + * @param {CoreContentLinksHelperProvider} linkHelper The CoreContentLinksHelperProvider instance. + * @param {TranslateService} translate The TranslateService instance. + * @param {string} addon Name of the addon as it's registered in course delegate. It'll be used to check if it's disabled. + * @param {string} modName Name of the module (assign, book, ...). + */ + constructor(protected linkHelper: CoreContentLinksHelperProvider, protected translate: TranslateService, public addon: string, + public modName: string) { + super(); + + // Match the view.php URL with an id param. + this.pattern = new RegExp('\/mod\/' + modName + '\/index\.php.*([\&\?]id=\\d+)'); + this.featureName = 'CoreCourseModuleDelegate_' + addon; + } + + /** + * Get the list of actions for a link (url). + * + * @param {string[]} siteIds List of sites the URL belongs to. + * @param {string} url The URL to treat. + * @param {any} params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1} + * @return {CoreContentLinksAction[]|Promise} List of (or promise resolved with list of) actions. + */ + getActions(siteIds: string[], url: string, params: any): CoreContentLinksAction[] | Promise { + + return [{ + action: (siteId, navCtrl?): void => { + const stateParams = { + courseId: params.id, + modName: this.modName, + title: this.title || this.translate.instant('addon.mod_' + this.modName + '.modulenameplural') + }; + + // Always use redirect to make it the new history root (to avoid "loops" in history). + this.linkHelper.goInSite(navCtrl, 'CoreCourseListModTypePage', stateParams, siteId); + } + }]; + } +} diff --git a/src/core/course/components/module/module.scss b/src/core/course/components/module/module.scss index 41fabe184..fd7ec52e7 100644 --- a/src/core/course/components/module/module.scss +++ b/src/core/course/components/module/module.scss @@ -94,6 +94,8 @@ ion-app.app-root.ios core-course-module { a.core-course-module-handler .core-module-icon { margin-top: $label-ios-margin-top; margin-bottom: $label-ios-margin-bottom; + width: 24px; + height: 24px; } .core-module-title core-format-text { @@ -119,6 +121,8 @@ ion-app.app-root.wp core-course-module { a.core-course-module-handler .core-module-icon { margin-top: $item-wp-padding-top; margin-bottom: $item-wp-padding-bottom; + width: 24px; + height: 24px; } .core-module-title core-format-text { diff --git a/src/core/course/pages/list-mod-type/list-mod-type.html b/src/core/course/pages/list-mod-type/list-mod-type.html new file mode 100644 index 000000000..b131fb912 --- /dev/null +++ b/src/core/course/pages/list-mod-type/list-mod-type.html @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/core/course/pages/list-mod-type/list-mod-type.module.ts b/src/core/course/pages/list-mod-type/list-mod-type.module.ts new file mode 100644 index 000000000..1de8ec959 --- /dev/null +++ b/src/core/course/pages/list-mod-type/list-mod-type.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 { CoreCourseListModTypePage } from './list-mod-type'; +import { CoreComponentsModule } from '@components/components.module'; +import { CoreDirectivesModule } from '@directives/directives.module'; +import { CoreCourseComponentsModule } from '@core/course/components/components.module'; + +@NgModule({ + declarations: [ + CoreCourseListModTypePage + ], + imports: [ + CoreComponentsModule, + CoreDirectivesModule, + CoreCourseComponentsModule, + IonicPageModule.forChild(CoreCourseListModTypePage), + TranslateModule.forChild() + ], +}) +export class CoreCourseListModTypePageModule {} diff --git a/src/core/course/pages/list-mod-type/list-mod-type.ts b/src/core/course/pages/list-mod-type/list-mod-type.ts new file mode 100644 index 000000000..2a1694243 --- /dev/null +++ b/src/core/course/pages/list-mod-type/list-mod-type.ts @@ -0,0 +1,120 @@ +// (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, NavParams } from 'ionic-angular'; +import { CoreDomUtilsProvider } from '@providers/utils/dom'; +import { CoreCourseProvider } from '../../providers/course'; +import { CoreCourseModuleDelegate } from '../../providers/module-delegate'; +import { CoreCourseHelperProvider } from '../../providers/helper'; +import { CoreConstants } from '@core/constants'; + +/** + * Page that displays comments. + */ +@IonicPage({ segment: 'core-course-list-mod-type' }) +@Component({ + selector: 'page-core-course-list-mod-type', + templateUrl: 'list-mod-type.html', +}) +export class CoreCourseListModTypePage { + + modules = []; + title: string; + loaded = false; + + protected courseId: number; + protected modName: string; + protected archetypes = {}; // To speed up the check of modules. + + constructor(navParams: NavParams, private courseProvider: CoreCourseProvider, private moduleDelegate: CoreCourseModuleDelegate, + private domUtils: CoreDomUtilsProvider, private courseHelper: CoreCourseHelperProvider) { + + this.title = navParams.get('title'); + this.courseId = navParams.get('courseId'); + this.modName = navParams.get('modName'); + } + + /** + * View loaded. + */ + ionViewDidLoad(): void { + this.fetchData().finally(() => { + this.loaded = true; + }); + } + + /** + * Fetches the data. + * + * @return {Promise} Resolved when done. + */ + protected fetchData(): Promise { + // Get all the modules in the course. + return this.courseProvider.getSections(this.courseId, false, true).then((sections) => { + + this.modules = []; + + sections.forEach((section) => { + if (!section.modules) { + return; + } + + section.modules.forEach((mod) => { + if (mod.uservisible === false || !this.courseProvider.moduleHasView(mod)) { + // Ignore this module. + return; + } + + if (this.modName === 'resources') { + // Check that the module is a resource. + if (typeof this.archetypes[mod.modname] == 'undefined') { + this.archetypes[mod.modname] = this.moduleDelegate.supportsFeature(mod.modname, + CoreConstants.FEATURE_MOD_ARCHETYPE, CoreConstants.MOD_ARCHETYPE_OTHER); + } + + if (this.archetypes[mod.modname] == CoreConstants.MOD_ARCHETYPE_RESOURCE) { + this.modules.push(mod); + } + + } else if (mod.modname == this.modName) { + this.modules.push(mod); + } + }); + }); + + // Get the handler data for the modules. + const fakeSection = { + visible: 1, + modules: this.modules + }; + this.courseHelper.addHandlerDataForModules([fakeSection], this.courseId); + }).catch((error) => { + this.domUtils.showErrorModalDefault(error, 'Error getting data'); + }); + } + + /** + * Refresh the data. + * + * @param {any} refresher Refresher. + */ + refreshData(refresher: any): void { + this.courseProvider.invalidateSections(this.courseId).finally(() => { + return this.fetchData().finally(() => { + refresher.complete(); + }); + }); + } +} diff --git a/src/core/course/providers/course.ts b/src/core/course/providers/course.ts index 35a8a3997..16a1bc386 100644 --- a/src/core/course/providers/course.ts +++ b/src/core/course/providers/course.ts @@ -85,11 +85,22 @@ export class CoreCourseProvider { this.sitesProvider.createTableFromSchema(this.courseStatusTableSchema); } + /** + * Check if the get course blocks WS is available in current site. + * + * @return {boolean} Whether it's available. + * @since 3.3 + */ + canGetCourseBlocks(): boolean { + return this.sitesProvider.wsAvailableInCurrentSite('core_block_get_course_blocks'); + } + /** * Check whether the site supports requesting stealth modules. * * @param {CoreSite} [site] Site. If not defined, current site. * @return {boolean} Whether the site supports requesting stealth modules. + * @since 3.4.6, 3.5.3, 3.6 */ canRequestStealthModules(site?: CoreSite): boolean { site = site || this.sitesProvider.getCurrentSite(); @@ -208,6 +219,39 @@ export class CoreCourseProvider { return this.ROOT_CACHE_KEY + 'activitiescompletion:' + courseId + ':' + userId; } + /** + * Get course blocks. + * + * @param {number} courseId Course ID. + * @param {string} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved with the list of blocks. + * @since 3.3 + */ + getCourseBlocks(courseId: number, siteId?: string): Promise { + return this.sitesProvider.getSite(siteId).then((site) => { + const params = { + courseid: courseId + }, + preSets: CoreSiteWSPreSets = { + cacheKey: this.getCourseBlocksCacheKey(courseId) + }; + + return site.read('core_block_get_course_blocks', params, preSets).then((result) => { + return result.blocks || []; + }); + }); + } + + /** + * Get cache key for course blocks WS calls. + * + * @param {number} courseId Course ID. + * @return {string} Cache key. + */ + protected getCourseBlocksCacheKey(courseId: number): string { + return this.ROOT_CACHE_KEY + 'courseblocks:' + courseId; + } + /** * Get the data stored for a course. * @@ -608,6 +652,19 @@ export class CoreCourseProvider { return modules; } + /** + * Invalidates course blocks WS call. + * + * @param {number} courseId Course ID. + * @param {string} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the data is invalidated. + */ + invalidateCourseBlocks(courseId: number, siteId?: string): Promise { + return this.sitesProvider.getSite(siteId).then((site) => { + return site.invalidateWsCacheForKey(this.getCourseBlocksCacheKey(courseId)); + }); + } + /** * Invalidates module WS call. * @@ -785,6 +842,16 @@ export class CoreCourseProvider { }); } + /** + * Check if a module has a view page. E.g. labels don't have a view page. + * + * @param {any} module The module object. + * @return {boolean} Whether the module has a view page. + */ + moduleHasView(module: any): boolean { + return !!module.url; + } + /** * Change the course status, setting it to the previous status. * diff --git a/src/core/course/providers/module-delegate.ts b/src/core/course/providers/module-delegate.ts index 459110be2..52daed19e 100644 --- a/src/core/course/providers/module-delegate.ts +++ b/src/core/course/providers/module-delegate.ts @@ -33,6 +33,14 @@ export interface CoreCourseModuleHandler extends CoreDelegateHandler { */ modName: string; + /** + * List of supported features. The keys should be the name of the feature. + * This is to replicate the "plugin_supports" function of Moodle. + * If you need some dynamic checks please implement the supportsFeature function. + * @type {{[name: string]: any}} + */ + supportedFeatures?: {[name: string]: any}; + /** * Get the data required to display the module in the course contents view. * @@ -62,6 +70,22 @@ export interface CoreCourseModuleHandler extends CoreDelegateHandler { * @return {boolean} Whether the refresher should be displayed. */ displayRefresherInSingleActivity?(): boolean; + + /** + * Get the icon src for the module. + * + * @return {string} The icon src. + */ + getIconSrc?(): string; + + /** + * Check if this type of module supports a certain feature. + * If this function is implemented, the supportedFeatures object will be ignored. + * + * @param {string} feature The feature to check. + * @return {any} The result of the supports check. + */ + supportsFeature?(feature: string): any; } /** @@ -284,4 +308,44 @@ export class CoreCourseModuleDelegate extends CoreDelegate { displayRefresherInSingleActivity(modname: string): boolean { return this.executeFunctionOnEnabled(modname, 'displayRefresherInSingleActivity'); } + + /** + * Get the icon src for a certain type of module. + * + * @param {any} modname The name of the module type. + * @return {string} The icon src. + */ + getModuleIconSrc(modname: string): string { + return this.executeFunctionOnEnabled(modname, 'getIconSrc') || this.courseProvider.getModuleIconSrc(modname); + } + + /** + * Check if a certain type of module supports a certain feature. + * + * @param {string} modname The modname. + * @param {string} feature The feature to check. + * @param {any} defaultValue Value to return if the module is not supported or doesn't know if it's supported. + * @return {any} The result of the supports check. + */ + supportsFeature(modname: string, feature: string, defaultValue: any): any { + const handler = this.enabledHandlers[modname]; + let result; + + if (handler) { + if (handler['supportsFeature']) { + // The handler specified a function to determine the feature, use it. + result = handler['supportsFeature'].apply(handler, [feature]); + } else if (handler['supportedFeatures']) { + // Handler has an object to determine the feature, use it. + result = handler['supportedFeatures'][feature]; + } + } + + if (result === null || typeof result == 'undefined') { + // Not supported or doesn't know, return defaul. + return defaultValue; + } else { + return result; + } + } } diff --git a/src/core/sitehome/components/components.module.ts b/src/core/sitehome/components/components.module.ts index d0fd2ddf8..55f9916d9 100644 --- a/src/core/sitehome/components/components.module.ts +++ b/src/core/sitehome/components/components.module.ts @@ -19,6 +19,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { CoreComponentsModule } from '@components/components.module'; import { CoreDirectivesModule } from '@directives/directives.module'; import { CoreCourseComponentsModule } from '@core/course/components/components.module'; +import { CoreBlockComponentsModule } from '@core/block/components/components.module'; import { CoreSiteHomeIndexComponent } from './index/index'; import { CoreSiteHomeAllCourseListComponent } from './all-course-list/all-course-list'; import { CoreSiteHomeCategoriesComponent } from './categories/categories'; @@ -41,7 +42,8 @@ import { CoreSiteHomeNewsComponent } from './news/news'; TranslateModule.forChild(), CoreComponentsModule, CoreDirectivesModule, - CoreCourseComponentsModule + CoreCourseComponentsModule, + CoreBlockComponentsModule ], exports: [ CoreSiteHomeIndexComponent, diff --git a/src/core/sitehome/components/index/core-sitehome-index.html b/src/core/sitehome/components/index/core-sitehome-index.html index 80850db1f..600834cd1 100644 --- a/src/core/sitehome/components/index/core-sitehome-index.html +++ b/src/core/sitehome/components/index/core-sitehome-index.html @@ -22,16 +22,11 @@ - - - - - - - - + + + - + diff --git a/src/core/sitehome/components/index/index.ts b/src/core/sitehome/components/index/index.ts index ee581ec75..36ae14d5a 100644 --- a/src/core/sitehome/components/index/index.ts +++ b/src/core/sitehome/components/index/index.ts @@ -12,13 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChildren, QueryList } from '@angular/core'; import { CoreSitesProvider } from '@providers/sites'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreCourseProvider } from '@core/course/providers/course'; import { CoreCourseHelperProvider } from '@core/course/providers/helper'; import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate'; -import { CoreSiteHomeProvider } from '../../providers/sitehome'; +import { CoreBlockDelegate } from '@core/block/providers/delegate'; +import { CoreBlockComponent } from '@core/block/components/block/block'; /** * Component that displays site home index. @@ -28,18 +29,19 @@ import { CoreSiteHomeProvider } from '../../providers/sitehome'; templateUrl: 'core-sitehome-index.html', }) export class CoreSiteHomeIndexComponent implements OnInit { + @ViewChildren(CoreBlockComponent) blocksComponents: QueryList; + dataLoaded = false; section: any; - block: any; hasContent: boolean; + hasSupportedBlock: boolean; items: any[] = []; siteHomeId: number; - - protected sectionsLoaded: any[]; + blocks: any[]; constructor(private domUtils: CoreDomUtilsProvider, private sitesProvider: CoreSitesProvider, private courseProvider: CoreCourseProvider, private courseHelper: CoreCourseHelperProvider, - private prefetchDelegate: CoreCourseModulePrefetchDelegate, private siteHomeProvider: CoreSiteHomeProvider) { + private prefetchDelegate: CoreCourseModulePrefetchDelegate, private blockDelegate: CoreBlockDelegate) { this.siteHomeId = sitesProvider.getCurrentSite().getSiteHomeId(); } @@ -69,12 +71,22 @@ export class CoreSiteHomeIndexComponent implements OnInit { }); })); - if (this.sectionsLoaded) { + if (this.section && this.section.modules) { // Invalidate modules prefetch data. - const modules = this.courseProvider.getSectionsModules(this.sectionsLoaded); - promises.push(this.prefetchDelegate.invalidateModules(modules, this.siteHomeId)); + promises.push(this.prefetchDelegate.invalidateModules(this.section.modules, this.siteHomeId)); } + if (this.courseProvider.canGetCourseBlocks()) { + promises.push(this.courseProvider.invalidateCourseBlocks(this.siteHomeId)); + } + + // Invalidate the blocks. + this.blocksComponents.forEach((blockComponent) => { + promises.push(blockComponent.invalidate().catch(() => { + // Ignore errors. + })); + }); + Promise.all(promises).finally(() => { this.loadContent().finally(() => { refresher.complete(); @@ -88,7 +100,6 @@ export class CoreSiteHomeIndexComponent implements OnInit { * @return {Promise} Promise resolved when done. */ protected loadContent(): Promise { - let hasNewsItem = false; this.hasContent = false; const config = this.sitesProvider.getCurrentSite().getStoredConfig() || { numsections: 1 }; @@ -116,50 +127,49 @@ export class CoreSiteHomeIndexComponent implements OnInit { return; } - if (item == 'news') { - hasNewsItem = true; - } - this.hasContent = true; this.items.push(item); }); } return this.courseProvider.getSections(this.siteHomeId, false, true).then((sections) => { - this.sectionsLoaded = Array.from(sections); // Check "Include a topic section" setting from numsections. - this.section = config.numsections && sections.length > 0 ? sections.pop() : false; + this.section = config.numsections ? sections[1] : false; if (this.section) { this.section.hasContent = this.courseHelper.sectionHasContent(this.section); + this.hasContent = this.courseHelper.addHandlerDataForModules([this.section], this.siteHomeId) || this.hasContent; } - this.block = sections.length > 0 ? sections.pop() : false; - if (this.block) { - this.block.hasContent = this.courseHelper.sectionHasContent(this.block); - } - - this.hasContent = this.courseHelper.addHandlerDataForModules(this.sectionsLoaded, this.siteHomeId) || this.hasContent; - // Add log in Moodle. - this.courseProvider.logView(this.siteHomeId); + this.courseProvider.logView(this.siteHomeId).catch(() => { + // Ignore errors. + }); - if (hasNewsItem && this.block && this.block.modules) { - // Remove forum activity (news one only) to prevent duplicates. - return this.siteHomeProvider.getNewsForum(this.siteHomeId).then((forum) => { - // Search the module that belongs to site news. - for (let i = 0; i < this.block.modules.length; i++) { - const module = this.block.modules[i]; + // Get site home blocks. + const canGetBlocks = this.courseProvider.canGetCourseBlocks(), + promise = canGetBlocks ? this.courseProvider.getCourseBlocks(this.siteHomeId) : Promise.reject(null); - if (module.modname == 'forum' && module.instance == forum.id) { - this.block.modules.splice(i, 1); - break; - } - } - }).catch(() => { - // Ignore errors. - }); - } + return promise.then((blocks) => { + this.blocks = blocks; + this.hasSupportedBlock = this.blockDelegate.hasSupportedBlock(blocks); + + }).catch((error) => { + if (canGetBlocks) { + this.domUtils.showErrorModal(error); + } + + // Cannot get the blocks, just show site main menu if needed. + if (sections[0] && this.courseHelper.sectionHasContent(sections[0])) { + this.blocks.push({ + name: 'site_main_menu' + }); + this.hasSupportedBlock = true; + } else { + this.blocks = []; + this.hasSupportedBlock = false; + } + }); }).catch((error) => { this.domUtils.showErrorModalDefault(error, 'core.course.couldnotloadsectioncontent', true); }); diff --git a/src/core/sitehome/providers/sitehome.ts b/src/core/sitehome/providers/sitehome.ts index 651df4a89..2d5fa3aaf 100644 --- a/src/core/sitehome/providers/sitehome.ts +++ b/src/core/sitehome/providers/sitehome.ts @@ -49,6 +49,16 @@ export class CoreSiteHomeProvider { }); } + /** + * Invalidate the WS call to get the news forum for the Site Home. + * + * @param {number} siteHomeId Site Home ID. + * @return {Promise} Promise resolved when invalidated. + */ + invalidateNewsForum(siteHomeId: number): Promise { + return this.forumProvider.invalidateForumData(siteHomeId); + } + /** * Returns whether or not the frontpage is available for the current site. * diff --git a/src/core/siteplugins/classes/handlers/module-handler.ts b/src/core/siteplugins/classes/handlers/module-handler.ts index ffaf73af6..41cffe6c6 100644 --- a/src/core/siteplugins/classes/handlers/module-handler.ts +++ b/src/core/siteplugins/classes/handlers/module-handler.ts @@ -23,9 +23,18 @@ import { CoreSitePluginsModuleIndexComponent } from '../../components/module-ind */ export class CoreSitePluginsModuleHandler extends CoreSitePluginsBaseHandler implements CoreCourseModuleHandler { priority: number; + supportedFeatures: {[name: string]: any}; + supportsFeature: (feature: string) => any; - constructor(name: string, public modName: string, protected handlerSchema: any) { + constructor(name: string, public modName: string, protected handlerSchema: any, protected initResult: any) { super(name); + + this.supportedFeatures = handlerSchema.supportedfeatures; + + if (initResult && initResult.jsResult && initResult.jsResult.supportsFeature) { + // The init result defines a function to check if a feature is supported, use it. + this.supportsFeature = initResult.jsResult.supportsFeature.bind(initResult.jsResult); + } } /** @@ -58,6 +67,15 @@ export class CoreSitePluginsModuleHandler extends CoreSitePluginsBaseHandler imp }; } + /** + * Get the icon src for the module. + * + * @return {string} The icon src. + */ + getIconSrc(): string { + return this.handlerSchema.displaydata.icon; + } + /** * Get the component to render the module. This is needed to support singleactivity course format. * The component returned must implement CoreCourseModuleMainComponent. diff --git a/src/core/siteplugins/providers/helper.ts b/src/core/siteplugins/providers/helper.ts index 26124d2b6..666044bd0 100644 --- a/src/core/siteplugins/providers/helper.ts +++ b/src/core/siteplugins/providers/helper.ts @@ -443,7 +443,7 @@ export class CoreSitePluginsHelperProvider { break; case 'CoreCourseModuleDelegate': - promise = Promise.resolve(this.registerModuleHandler(plugin, handlerName, handlerSchema)); + promise = Promise.resolve(this.registerModuleHandler(plugin, handlerName, handlerSchema, result)); break; case 'CoreUserDelegate': @@ -720,9 +720,10 @@ export class CoreSitePluginsHelperProvider { * @param {any} plugin Data of the plugin. * @param {string} handlerName Name of the handler in the plugin. * @param {any} handlerSchema Data about the handler. + * @param {any} initResult Result of the init WS call. * @return {string} A string to identify the handler. */ - protected registerModuleHandler(plugin: any, handlerName: string, handlerSchema: any): string { + protected registerModuleHandler(plugin: any, handlerName: string, handlerSchema: any, initResult: any): string { if (!handlerSchema.displaydata) { // Required data not provided, stop. this.logger.warn('Ignore site plugin because it doesn\'t provide displaydata', plugin, handlerSchema); @@ -730,13 +731,13 @@ export class CoreSitePluginsHelperProvider { return; } - this.logger.debug('Register site plugin in module delegate:', plugin, handlerSchema); + this.logger.debug('Register site plugin in module delegate:', plugin, handlerSchema, initResult); // Create and register the handler. const uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName), modName = plugin.component.replace('mod_', ''); - this.moduleDelegate.registerHandler(new CoreSitePluginsModuleHandler(uniqueName, modName, handlerSchema)); + this.moduleDelegate.registerHandler(new CoreSitePluginsModuleHandler(uniqueName, modName, handlerSchema, initResult)); if (handlerSchema.offlinefunctions && Object.keys(handlerSchema.offlinefunctions).length) { // Register the prefetch handler. diff --git a/src/lang/en.json b/src/lang/en.json index ebd2b9aa2..3838eab45 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -189,6 +189,7 @@ "refresh": "Refresh", "required": "Required", "requireduserdatamissing": "This user lacks some required profile data. Please enter the data in your site and try again.
{{$a}}", + "resources": "Resources", "restore": "Restore", "retry": "Retry", "save": "Save", diff --git a/src/providers/utils/utils.ts b/src/providers/utils/utils.ts index 85b0bfbd5..408a4c950 100644 --- a/src/providers/utils/utils.ts +++ b/src/providers/utils/utils.ts @@ -931,10 +931,11 @@ export class CoreUtilsProvider { * @param {object} obj Object to convert. * @param {string} keyName Name of the properties where to store the keys. * @param {string} valueName Name of the properties where to store the values. - * @param {boolean} [sort] True to sort keys alphabetically, false otherwise. + * @param {boolean} [sortByKey] True to sort keys alphabetically, false otherwise. Has priority over sortByValue. + * @param {boolean} [sortByValue] True to sort values alphabetically, false otherwise. * @return {any[]} Array of objects with the name & value of each property. */ - objectToArrayOfObjects(obj: object, keyName: string, valueName: string, sort?: boolean): any[] { + objectToArrayOfObjects(obj: object, keyName: string, valueName: string, sortByKey?: boolean, sortByValue?: boolean): any[] { // Get the entries from an object or primitive value. const getEntries = (elKey, value): any[] | any => { if (typeof value == 'object') { @@ -964,9 +965,13 @@ export class CoreUtilsProvider { // "obj" will always be an object, so "entries" will always be an array. const entries = getEntries('', obj); - if (sort) { + if (sortByKey || sortByValue) { return entries.sort((a, b) => { - return a.name >= b.name ? 1 : -1; + if (sortByKey) { + return a[keyName] >= b[keyName] ? 1 : -1; + } else { + return a[valueName] >= b[valueName] ? 1 : -1; + } }); } @@ -980,7 +985,7 @@ export class CoreUtilsProvider { * @param {object[]} objects List of objects to convert. * @param {string} keyName Name of the properties where the keys are stored. * @param {string} valueName Name of the properties where the values are stored. - * @param [keyPrefix] Key prefix if neededs to delete it. + * @param {string} [keyPrefix] Key prefix if neededs to delete it. * @return {object} Object. */ objectToKeyValueMap(objects: object[], keyName: string, valueName: string, keyPrefix?: string): object { @@ -1096,6 +1101,23 @@ export class CoreUtilsProvider { } } + /** + * Given an object, sort its values. Values need to be primitive values, it cannot have subobjects. + * + * @param {object} obj The object to sort. If it isn't an object, the original value will be returned. + * @return {object} Sorted object. + */ + sortValues(obj: object): object { + if (typeof obj == 'object' && !Array.isArray(obj)) { + // It's an object, sort it. Convert it to an array to be able to sort it and then convert it back to object. + const array = this.objectToArrayOfObjects(obj, 'name', 'value', false, true); + + return this.objectToKeyValueMap(array, 'name', 'value'); + } else { + return obj; + } + } + /** * Sum the filesizes from a list of files checking if the size will be partial or totally calculated. *