diff --git a/src/addon/badges/pages/issued-badge/issued-badge.html b/src/addon/badges/pages/issued-badge/issued-badge.html index 0dcc1e810..75ee12adf 100644 --- a/src/addon/badges/pages/issued-badge/issued-badge.html +++ b/src/addon/badges/pages/issued-badge/issued-badge.html @@ -24,9 +24,7 @@

{{ 'core.name' | translate}}

-

- -

+

{{ user.fullname }}

@@ -36,14 +34,12 @@

{{ 'addon.badges.issuername' | translate}}

-

- -

+

{{ badge.issuername }}

{{ 'addon.badges.contact' | translate}}

- + {{ badge.issuercontact }}

@@ -66,9 +62,7 @@

{{ 'core.description' | translate}}

-

- -

+

{{ badge.description }}

{{ 'addon.badges.imageauthorname' | translate}}

@@ -77,23 +71,23 @@

{{ 'addon.badges.imageauthoremail' | translate}}

- + {{ badge.imageauthoremail }}

{{ 'addon.badges.imageauthorurl' | translate}}

- + {{ badge.imageauthorurl }}

{{ 'addon.badges.imagecaption' | translate}}

-

+

{{ badge.imagecaption }}

{{ 'core.course' | translate}}

- +

@@ -131,13 +125,13 @@

{{ 'addon.badges.issueremail' | translate}}

- + {{ badge.endorsement.issueremail }}

{{ 'addon.badges.issuerurl' | translate}}

- + {{ badge.endorsement.issuerurl }}

@@ -147,14 +141,12 @@

{{ 'addon.badges.claimid' | translate}}

- + {{ badge.endorsement.claimid }}

{{ 'addon.badges.claimcomment' | translate}}

-

- -

+

{{ badge.endorsement.claimcomment }}

@@ -164,7 +156,7 @@

{{ 'addon.badges.relatedbages' | translate}}

-

+

<{{ relatedBadge.name }}

{{ 'addon.badges.norelated' | translate}}

@@ -177,7 +169,7 @@

{{ 'addon.badges.alignment' | translate}}

-

+

{{ alignment.targetname }}

{{ 'addon.badges.noalignment' | translate}}

diff --git a/src/addon/badges/pages/user-badges/user-badges.html b/src/addon/badges/pages/user-badges/user-badges.html index 6a2a33a24..315e9af08 100644 --- a/src/addon/badges/pages/user-badges/user-badges.html +++ b/src/addon/badges/pages/user-badges/user-badges.html @@ -17,7 +17,7 @@ -

+

{{ badge.name }}

{{ badge.dateissued * 1000 | coreFormatDate :'strftimedatetimeshort' }}

{{ 'addon.badges.expired' | translate }} diff --git a/src/addon/block/activitymodules/components/activitymodules/addon-block-activitymodules.html b/src/addon/block/activitymodules/components/activitymodules/addon-block-activitymodules.html index 7711b65f6..342e38924 100644 --- a/src/addon/block/activitymodules/components/activitymodules/addon-block-activitymodules.html +++ b/src/addon/block/activitymodules/components/activitymodules/addon-block-activitymodules.html @@ -4,6 +4,6 @@ - + {{ entry.name }} diff --git a/src/addon/block/recentlyaccesseditems/components/recentlyaccesseditems/addon-block-recentlyaccesseditems.html b/src/addon/block/recentlyaccesseditems/components/recentlyaccesseditems/addon-block-recentlyaccesseditems.html index f6e60ba65..cfa2892d6 100644 --- a/src/addon/block/recentlyaccesseditems/components/recentlyaccesseditems/addon-block-recentlyaccesseditems.html +++ b/src/addon/block/recentlyaccesseditems/components/recentlyaccesseditems/addon-block-recentlyaccesseditems.html @@ -7,8 +7,8 @@ -

-

+

+

diff --git a/src/addon/block/sitemainmenu/components/sitemainmenu/addon-block-sitemainmenu.html b/src/addon/block/sitemainmenu/components/sitemainmenu/addon-block-sitemainmenu.html index f9a5b7f82..49dfb8748 100644 --- a/src/addon/block/sitemainmenu/components/sitemainmenu/addon-block-sitemainmenu.html +++ b/src/addon/block/sitemainmenu/components/sitemainmenu/addon-block-sitemainmenu.html @@ -4,7 +4,7 @@ - + diff --git a/src/addon/block/sitemainmenu/components/sitemainmenu/sitemainmenu.ts b/src/addon/block/sitemainmenu/components/sitemainmenu/sitemainmenu.ts index 8568c8225..20651772a 100644 --- a/src/addon/block/sitemainmenu/components/sitemainmenu/sitemainmenu.ts +++ b/src/addon/block/sitemainmenu/components/sitemainmenu/sitemainmenu.ts @@ -30,6 +30,7 @@ import { CoreBlockBaseComponent } from '@core/block/classes/base-block-component export class AddonBlockSiteMainMenuComponent extends CoreBlockBaseComponent implements OnInit { @Input() downloadEnabled: boolean; + component = 'AddonBlockSiteMainMenu'; mainMenuBlock: any; siteHomeId: number; diff --git a/src/addon/block/timeline/components/events/addon-block-timeline-events.html b/src/addon/block/timeline/components/events/addon-block-timeline-events.html index 46af070cc..832c4902d 100644 --- a/src/addon/block/timeline/components/events/addon-block-timeline-events.html +++ b/src/addon/block/timeline/components/events/addon-block-timeline-events.html @@ -5,9 +5,9 @@ -

+

- +

diff --git a/src/addon/mod/glossary/pages/entry/entry.html b/src/addon/mod/glossary/pages/entry/entry.html index 5954398ff..7a9741482 100644 --- a/src/addon/mod/glossary/pages/entry/entry.html +++ b/src/addon/mod/glossary/pages/entry/entry.html @@ -1,6 +1,6 @@ - + @@ -12,16 +12,16 @@ -

+

{{ entry.timemodified | coreDateDayOrTime }} -

+

{{ entry.userfullname }}

-

+

{{ entry.timemodified | coreDateDayOrTime }}
- +
diff --git a/src/addon/mod/glossary/pages/index/index.html b/src/addon/mod/glossary/pages/index/index.html index f33735512..bd651f76a 100644 --- a/src/addon/mod/glossary/pages/index/index.html +++ b/src/addon/mod/glossary/pages/index/index.html @@ -1,6 +1,6 @@ - + diff --git a/src/addon/mod/glossary/providers/prefetch-handler.ts b/src/addon/mod/glossary/providers/prefetch-handler.ts index 2ce18b053..b087762ac 100644 --- a/src/addon/mod/glossary/providers/prefetch-handler.ts +++ b/src/addon/mod/glossary/providers/prefetch-handler.ts @@ -23,6 +23,7 @@ import { CoreCourseProvider } from '@core/course/providers/course'; import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler'; import { AddonModGlossaryProvider } from './glossary'; import { AddonModGlossarySyncProvider } from './sync'; +import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; /** * Handler to prefetch forums. @@ -41,10 +42,11 @@ export class AddonModGlossaryPrefetchHandler extends CoreCourseActivityPrefetchH filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider, domUtils: CoreDomUtilsProvider, + filterHelper: CoreFilterHelperProvider, private glossaryProvider: AddonModGlossaryProvider, private syncProvider: AddonModGlossarySyncProvider) { - super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); + super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); } /** diff --git a/src/addon/mod/imscp/components/index/addon-mod-imscp-index.html b/src/addon/mod/imscp/components/index/addon-mod-imscp-index.html index e8c542dfa..4e431dbfd 100644 --- a/src/addon/mod/imscp/components/index/addon-mod-imscp-index.html +++ b/src/addon/mod/imscp/components/index/addon-mod-imscp-index.html @@ -16,8 +16,7 @@
- - +
diff --git a/src/addon/mod/imscp/pages/index/index.html b/src/addon/mod/imscp/pages/index/index.html index 8d8662c3d..b99777991 100644 --- a/src/addon/mod/imscp/pages/index/index.html +++ b/src/addon/mod/imscp/pages/index/index.html @@ -1,6 +1,6 @@ - + diff --git a/src/addon/mod/imscp/providers/prefetch-handler.ts b/src/addon/mod/imscp/providers/prefetch-handler.ts index 22b793f0c..0b9c5b57e 100644 --- a/src/addon/mod/imscp/providers/prefetch-handler.ts +++ b/src/addon/mod/imscp/providers/prefetch-handler.ts @@ -22,6 +22,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreCourseProvider } from '@core/course/providers/course'; import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler'; import { AddonModImscpProvider } from './imscp'; +import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; /** * Handler to prefetch IMSCPs. @@ -32,11 +33,17 @@ export class AddonModImscpPrefetchHandler extends CoreCourseResourcePrefetchHand modName = 'imscp'; component = AddonModImscpProvider.COMPONENT; - constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider, - courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider, - domUtils: CoreDomUtilsProvider, protected imscpProvider: AddonModImscpProvider) { + constructor(translate: TranslateService, + appProvider: CoreAppProvider, + utils: CoreUtilsProvider, + courseProvider: CoreCourseProvider, + filepoolProvider: CoreFilepoolProvider, + sitesProvider: CoreSitesProvider, + domUtils: CoreDomUtilsProvider, + filterHelper: CoreFilterHelperProvider, + protected imscpProvider: AddonModImscpProvider) { - super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); + super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); } /** diff --git a/src/addon/mod/label/providers/prefetch-handler.ts b/src/addon/mod/label/providers/prefetch-handler.ts index d9679a430..140c23538 100644 --- a/src/addon/mod/label/providers/prefetch-handler.ts +++ b/src/addon/mod/label/providers/prefetch-handler.ts @@ -22,6 +22,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreCourseProvider } from '@core/course/providers/course'; import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler'; import { AddonModLabelProvider } from './label'; +import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; /** * Handler to prefetch labels. @@ -34,11 +35,17 @@ export class AddonModLabelPrefetchHandler extends CoreCourseResourcePrefetchHand updatesNames = /^.*files$/; skipListStatus = true; - constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider, - courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider, - domUtils: CoreDomUtilsProvider, protected labelProvider: AddonModLabelProvider) { + constructor(translate: TranslateService, + appProvider: CoreAppProvider, + utils: CoreUtilsProvider, + courseProvider: CoreCourseProvider, + filepoolProvider: CoreFilepoolProvider, + sitesProvider: CoreSitesProvider, + domUtils: CoreDomUtilsProvider, + filterHelper: CoreFilterHelperProvider, + protected labelProvider: AddonModLabelProvider) { - super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); + super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); } /** diff --git a/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html b/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html index 655de6301..d7549ccb4 100644 --- a/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html +++ b/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html @@ -18,12 +18,12 @@ - +
- +
diff --git a/src/addon/mod/lesson/pages/index/index.html b/src/addon/mod/lesson/pages/index/index.html index e09f2c477..691bb7d19 100644 --- a/src/addon/mod/lesson/pages/index/index.html +++ b/src/addon/mod/lesson/pages/index/index.html @@ -1,6 +1,6 @@ - + diff --git a/src/addon/mod/lesson/pages/menu-modal/menu-modal.html b/src/addon/mod/lesson/pages/menu-modal/menu-modal.html index 5744f07bd..a3fe189bc 100644 --- a/src/addon/mod/lesson/pages/menu-modal/menu-modal.html +++ b/src/addon/mod/lesson/pages/menu-modal/menu-modal.html @@ -26,7 +26,7 @@ diff --git a/src/addon/mod/lesson/pages/player/player.html b/src/addon/mod/lesson/pages/player/player.html index 6c83c1f4b..13c7e7f0b 100644 --- a/src/addon/mod/lesson/pages/player/player.html +++ b/src/addon/mod/lesson/pages/player/player.html @@ -1,6 +1,6 @@ - +
diff --git a/src/addon/mod/quiz/pages/review/review.html b/src/addon/mod/quiz/pages/review/review.html index 4d398ed27..21491de5d 100644 --- a/src/addon/mod/quiz/pages/review/review.html +++ b/src/addon/mod/quiz/pages/review/review.html @@ -46,7 +46,7 @@

{{ 'addon.mod_quiz.marks' | translate }}

-

+

<{{ attempt.readableMark }}

{{ 'addon.mod_quiz.grade' | translate }}

@@ -54,7 +54,7 @@

{{ data.title }}

- +
@@ -73,11 +73,11 @@

{{ 'core.question.information' | translate }}

{{question.status}}

-

+

{{question.readableMark}}

- + diff --git a/src/addon/mod/quiz/providers/prefetch-handler.ts b/src/addon/mod/quiz/providers/prefetch-handler.ts index 4801db409..1874ce516 100644 --- a/src/addon/mod/quiz/providers/prefetch-handler.ts +++ b/src/addon/mod/quiz/providers/prefetch-handler.ts @@ -28,6 +28,7 @@ import { AddonModQuizHelperProvider } from './helper'; import { AddonModQuizAccessRuleDelegate } from './access-rules-delegate'; import { AddonModQuizSyncProvider } from './quiz-sync'; import { CoreConstants } from '@core/constants'; +import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; /** * Handler to prefetch quizzes. @@ -41,13 +42,22 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl protected syncProvider: AddonModQuizSyncProvider; // It will be injected later to prevent circular dependencies. - constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider, - courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider, - domUtils: CoreDomUtilsProvider, protected injector: Injector, protected quizProvider: AddonModQuizProvider, - protected textUtils: CoreTextUtilsProvider, protected quizHelper: AddonModQuizHelperProvider, - protected accessRuleDelegate: AddonModQuizAccessRuleDelegate, protected questionHelper: CoreQuestionHelperProvider) { + constructor(translate: TranslateService, + appProvider: CoreAppProvider, + utils: CoreUtilsProvider, + courseProvider: CoreCourseProvider, + filepoolProvider: CoreFilepoolProvider, + sitesProvider: CoreSitesProvider, + domUtils: CoreDomUtilsProvider, + filterHelper: CoreFilterHelperProvider, + protected injector: Injector, + protected quizProvider: AddonModQuizProvider, + protected textUtils: CoreTextUtilsProvider, + protected quizHelper: AddonModQuizHelperProvider, + protected accessRuleDelegate: AddonModQuizAccessRuleDelegate, + protected questionHelper: CoreQuestionHelperProvider) { - super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); + super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); } /** diff --git a/src/addon/mod/resource/components/index/addon-mod-resource-index.html b/src/addon/mod/resource/components/index/addon-mod-resource-index.html index 43e4c906f..57c634f15 100644 --- a/src/addon/mod/resource/components/index/addon-mod-resource-index.html +++ b/src/addon/mod/resource/components/index/addon-mod-resource-index.html @@ -13,14 +13,14 @@ - +
- +
diff --git a/src/addon/mod/resource/pages/index/index.html b/src/addon/mod/resource/pages/index/index.html index bae9e1278..d52cc3f30 100644 --- a/src/addon/mod/resource/pages/index/index.html +++ b/src/addon/mod/resource/pages/index/index.html @@ -1,6 +1,6 @@ - + diff --git a/src/addon/mod/resource/providers/prefetch-handler.ts b/src/addon/mod/resource/providers/prefetch-handler.ts index 94a946ae4..2f9bb6215 100644 --- a/src/addon/mod/resource/providers/prefetch-handler.ts +++ b/src/addon/mod/resource/providers/prefetch-handler.ts @@ -24,6 +24,7 @@ import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/reso import { AddonModResourceProvider } from './resource'; import { AddonModResourceHelperProvider } from './helper'; import { CoreConstants } from '@core/constants'; +import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; /** * Handler to prefetch resources. @@ -34,12 +35,18 @@ export class AddonModResourcePrefetchHandler extends CoreCourseResourcePrefetchH modName = 'resource'; component = AddonModResourceProvider.COMPONENT; - constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider, - courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider, - domUtils: CoreDomUtilsProvider, protected resourceProvider: AddonModResourceProvider, + constructor(translate: TranslateService, + appProvider: CoreAppProvider, + utils: CoreUtilsProvider, + courseProvider: CoreCourseProvider, + filepoolProvider: CoreFilepoolProvider, + sitesProvider: CoreSitesProvider, + domUtils: CoreDomUtilsProvider, + filterHelper: CoreFilterHelperProvider, + protected resourceProvider: AddonModResourceProvider, protected resourceHelper: AddonModResourceHelperProvider) { - super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); + super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper); } /** diff --git a/src/addon/mod/scorm/components/index/addon-mod-scorm-index.html b/src/addon/mod/scorm/components/index/addon-mod-scorm-index.html index 959fd819f..27e83c61e 100644 --- a/src/addon/mod/scorm/components/index/addon-mod-scorm-index.html +++ b/src/addon/mod/scorm/components/index/addon-mod-scorm-index.html @@ -14,7 +14,7 @@ - +
@@ -98,8 +98,8 @@

- {{ sco.title }} - {{ sco.title }} + +

diff --git a/src/addon/mod/scorm/pages/index/index.html b/src/addon/mod/scorm/pages/index/index.html index f8a5f7d42..9a0b2d855 100644 --- a/src/addon/mod/scorm/pages/index/index.html +++ b/src/addon/mod/scorm/pages/index/index.html @@ -1,6 +1,6 @@ - + diff --git a/src/addon/mod/scorm/pages/player/player.html b/src/addon/mod/scorm/pages/player/player.html index bdf47bd53..6d7874bad 100644 --- a/src/addon/mod/scorm/pages/player/player.html +++ b/src/addon/mod/scorm/pages/player/player.html @@ -1,6 +1,6 @@ - + - - - + {{ note.content }} diff --git a/src/addon/notes/components/list/list.ts b/src/addon/notes/components/list/list.ts index 57a9de314..843ff1c39 100644 --- a/src/addon/notes/components/list/list.ts +++ b/src/addon/notes/components/list/list.ts @@ -103,6 +103,10 @@ export class AddonNotesListComponent implements OnInit, OnDestroy { return this.notesProvider.getNotes(this.courseId, this.userId).then((notes) => { const notesList: AddonNotesNoteFormatted[] = notes[this.type + 'notes'] || []; + notesList.forEach((note) => { + note.content = this.textUtils.decodeHTML(note.content); + }); + return this.notesProvider.setOfflineDeletedNotes(notesList, this.courseId).then((notesList) => { this.hasOffline = notesList.some((note) => note.offline || note.deleted); diff --git a/src/addon/notifications/pages/list/list.html b/src/addon/notifications/pages/list/list.html index bd523d6ba..951c63659 100644 --- a/src/addon/notifications/pages/list/list.html +++ b/src/addon/notifications/pages/list/list.html @@ -21,16 +21,16 @@ -

+

{{ notification.subject }}

{{notification.timecreated | coreDateDayOrTime}}

-

+

{{ notification.userfromfullname }}

-

+

diff --git a/src/addon/qbehaviour/deferredcbm/component/addon-qbehaviour-deferredcbm.html b/src/addon/qbehaviour/deferredcbm/component/addon-qbehaviour-deferredcbm.html index 0975635c1..a141d0e03 100644 --- a/src/addon/qbehaviour/deferredcbm/component/addon-qbehaviour-deferredcbm.html +++ b/src/addon/qbehaviour/deferredcbm/component/addon-qbehaviour-deferredcbm.html @@ -4,9 +4,7 @@
- - - + {{ option.text }}
diff --git a/src/addon/qbehaviour/deferredcbm/component/deferredcbm.ts b/src/addon/qbehaviour/deferredcbm/component/deferredcbm.ts index d85eccf09..dcb4c1310 100644 --- a/src/addon/qbehaviour/deferredcbm/component/deferredcbm.ts +++ b/src/addon/qbehaviour/deferredcbm/component/deferredcbm.ts @@ -27,6 +27,8 @@ export class AddonQbehaviourDeferredCBMComponent { @Input() componentId: number; // ID of the component the question belongs to. @Input() attemptId: number; // Attempt ID. @Input() offlineEnabled?: boolean | string; // Whether the question can be answered in offline. + @Input() contextLevel?: string; // The context level. + @Input() contextInstanceId?: number; // The instance ID related to the context. @Output() buttonClicked: EventEmitter; // Should emit an event when a behaviour button is clicked. @Output() onAbort: EventEmitter; // Should emit an event if the question should be aborted. diff --git a/src/addon/qbehaviour/informationitem/component/informationitem.ts b/src/addon/qbehaviour/informationitem/component/informationitem.ts index 3842fca29..aaa44569e 100644 --- a/src/addon/qbehaviour/informationitem/component/informationitem.ts +++ b/src/addon/qbehaviour/informationitem/component/informationitem.ts @@ -27,6 +27,8 @@ export class AddonQbehaviourInformationItemComponent { @Input() componentId: number; // ID of the component the question belongs to. @Input() attemptId: number; // Attempt ID. @Input() offlineEnabled?: boolean | string; // Whether the question can be answered in offline. + @Input() contextLevel?: string; // The context level. + @Input() contextInstanceId?: number; // The instance ID related to the context. @Output() buttonClicked: EventEmitter; // Should emit an event when a behaviour button is clicked. @Output() onAbort: EventEmitter; // Should emit an event if the question should be aborted. diff --git a/src/addon/qtype/calculated/component/addon-qtype-calculated.html b/src/addon/qtype/calculated/component/addon-qtype-calculated.html index e2ea63c89..e0096a827 100644 --- a/src/addon/qtype/calculated/component/addon-qtype-calculated.html +++ b/src/addon/qtype/calculated/component/addon-qtype-calculated.html @@ -1,6 +1,6 @@
-

+

@@ -55,9 +55,7 @@
- - - + {{ option.text }} diff --git a/src/addon/qtype/ddimageortext/component/addon-qtype-ddimageortext.html b/src/addon/qtype/ddimageortext/component/addon-qtype-ddimageortext.html index 218b25b24..f07233836 100644 --- a/src/addon/qtype/ddimageortext/component/addon-qtype-ddimageortext.html +++ b/src/addon/qtype/ddimageortext/component/addon-qtype-ddimageortext.html @@ -7,7 +7,7 @@ {{ 'core.question.howtodraganddrop' | translate }}

-

- +

+
diff --git a/src/addon/qtype/ddmarker/component/addon-qtype-ddmarker.html b/src/addon/qtype/ddmarker/component/addon-qtype-ddmarker.html index 199abc85d..2284c4265 100644 --- a/src/addon/qtype/ddmarker/component/addon-qtype-ddmarker.html +++ b/src/addon/qtype/ddmarker/component/addon-qtype-ddmarker.html @@ -7,7 +7,7 @@ {{ 'core.question.howtodraganddrop' | translate }}

-

- +

+ diff --git a/src/addon/qtype/ddwtos/component/addon-qtype-ddwtos.html b/src/addon/qtype/ddwtos/component/addon-qtype-ddwtos.html index 67c15fdfd..e70dcfd69 100644 --- a/src/addon/qtype/ddwtos/component/addon-qtype-ddwtos.html +++ b/src/addon/qtype/ddwtos/component/addon-qtype-ddwtos.html @@ -7,8 +7,8 @@ {{ 'core.question.howtodraganddrop' | translate }}

-

- +

+
diff --git a/src/addon/qtype/ddwtos/component/ddwtos.ts b/src/addon/qtype/ddwtos/component/ddwtos.ts index b144a4013..2ad23fcc6 100644 --- a/src/addon/qtype/ddwtos/component/ddwtos.ts +++ b/src/addon/qtype/ddwtos/component/ddwtos.ts @@ -95,7 +95,8 @@ export class AddonQtypeDdwtosComponent extends CoreQuestionBaseComponent impleme this.questionInstance = new AddonQtypeDdwtosQuestion(this.loggerProvider, this.domUtils, this.element, this.question, this.question.readOnly, this.inputIds, this.textUtils); - this.questionHelper.treatCorrectnessIconsClicks(this.element, this.component, this.componentId); + this.questionHelper.treatCorrectnessIconsClicks(this.element, this.component, this.componentId, this.contextLevel, + this.contextInstanceId, this.courseId); this.question.loaded = true; }); diff --git a/src/addon/qtype/description/component/addon-qtype-description.html b/src/addon/qtype/description/component/addon-qtype-description.html index 74d4f190d..1264d7c70 100644 --- a/src/addon/qtype/description/component/addon-qtype-description.html +++ b/src/addon/qtype/description/component/addon-qtype-description.html @@ -2,6 +2,6 @@ -

+

diff --git a/src/addon/qtype/essay/component/addon-qtype-essay.html b/src/addon/qtype/essay/component/addon-qtype-essay.html index ec4293251..5c171fedc 100644 --- a/src/addon/qtype/essay/component/addon-qtype-essay.html +++ b/src/addon/qtype/essay/component/addon-qtype-essay.html @@ -1,7 +1,7 @@
-

+

@@ -20,7 +20,7 @@

{{ 'core.question.errorinlinefilesnotsupported' | translate }}

-

+

@@ -31,7 +31,7 @@ -

+

diff --git a/src/addon/qtype/gapselect/component/addon-qtype-gapselect.html b/src/addon/qtype/gapselect/component/addon-qtype-gapselect.html index 70efb95b7..88b29f7fc 100644 --- a/src/addon/qtype/gapselect/component/addon-qtype-gapselect.html +++ b/src/addon/qtype/gapselect/component/addon-qtype-gapselect.html @@ -1,5 +1,5 @@
-

+

diff --git a/src/addon/qtype/gapselect/component/gapselect.ts b/src/addon/qtype/gapselect/component/gapselect.ts index 34de237db..7dd56017f 100644 --- a/src/addon/qtype/gapselect/component/gapselect.ts +++ b/src/addon/qtype/gapselect/component/gapselect.ts @@ -44,6 +44,7 @@ export class AddonQtypeGapSelectComponent extends CoreQuestionBaseComponent impl * The question has been rendered. */ questionRendered(): void { - this.questionHelper.treatCorrectnessIconsClicks(this.element, this.component, this.componentId); + this.questionHelper.treatCorrectnessIconsClicks(this.element, this.component, this.componentId, this.contextLevel, + this.contextInstanceId, this.courseId); } } diff --git a/src/addon/qtype/match/component/addon-qtype-match.html b/src/addon/qtype/match/component/addon-qtype-match.html index 95bed5ddc..08bbe1274 100644 --- a/src/addon/qtype/match/component/addon-qtype-match.html +++ b/src/addon/qtype/match/component/addon-qtype-match.html @@ -1,12 +1,12 @@
- + -

+

diff --git a/src/addon/qtype/multianswer/component/addon-qtype-multianswer.html b/src/addon/qtype/multianswer/component/addon-qtype-multianswer.html index 74bc91da4..919da0149 100644 --- a/src/addon/qtype/multianswer/component/addon-qtype-multianswer.html +++ b/src/addon/qtype/multianswer/component/addon-qtype-multianswer.html @@ -1,5 +1,5 @@
- +
diff --git a/src/addon/qtype/multianswer/component/multianswer.ts b/src/addon/qtype/multianswer/component/multianswer.ts index 5fa7ce6ca..7c2257113 100644 --- a/src/addon/qtype/multianswer/component/multianswer.ts +++ b/src/addon/qtype/multianswer/component/multianswer.ts @@ -44,6 +44,7 @@ export class AddonQtypeMultiAnswerComponent extends CoreQuestionBaseComponent im * The question has been rendered. */ questionRendered(): void { - this.questionHelper.treatCorrectnessIconsClicks(this.element, this.component, this.componentId); + this.questionHelper.treatCorrectnessIconsClicks(this.element, this.component, this.componentId, this.contextLevel, + this.contextInstanceId, this.courseId); } } diff --git a/src/addon/qtype/multichoice/component/addon-qtype-multichoice.html b/src/addon/qtype/multichoice/component/addon-qtype-multichoice.html index 56ac05cc3..32fc617f0 100644 --- a/src/addon/qtype/multichoice/component/addon-qtype-multichoice.html +++ b/src/addon/qtype/multichoice/component/addon-qtype-multichoice.html @@ -1,16 +1,16 @@
- - + + {{ question.prompt }} - -
+ +
@@ -25,8 +25,8 @@
- -
+ +
diff --git a/src/addon/qtype/shortanswer/component/addon-qtype-shortanswer.html b/src/addon/qtype/shortanswer/component/addon-qtype-shortanswer.html index 42febebf0..5cfaf0139 100644 --- a/src/addon/qtype/shortanswer/component/addon-qtype-shortanswer.html +++ b/src/addon/qtype/shortanswer/component/addon-qtype-shortanswer.html @@ -1,6 +1,6 @@
- + {{ 'addon.mod_quiz.answercolon' | translate }} diff --git a/src/addon/userprofilefield/checkbox/component/checkbox.ts b/src/addon/userprofilefield/checkbox/component/checkbox.ts index 0212563d4..80a8143ab 100644 --- a/src/addon/userprofilefield/checkbox/component/checkbox.ts +++ b/src/addon/userprofilefield/checkbox/component/checkbox.ts @@ -28,6 +28,8 @@ export class AddonUserProfileFieldCheckboxComponent implements OnInit { @Input() edit = false; // True if editing the field. Defaults to false. @Input() disabled = false; // True if disabled. Defaults to false. @Input() form: FormGroup; // Form where to add the form control. + @Input() contextLevel?: string; // The context level. + @Input() contextInstanceId?: number; // The instance ID related to the context. constructor(private fb: FormBuilder, protected utils: CoreUtilsProvider) { } diff --git a/src/addon/userprofilefield/datetime/component/datetime.ts b/src/addon/userprofilefield/datetime/component/datetime.ts index e1b287627..a9b66bf1f 100644 --- a/src/addon/userprofilefield/datetime/component/datetime.ts +++ b/src/addon/userprofilefield/datetime/component/datetime.ts @@ -30,6 +30,8 @@ export class AddonUserProfileFieldDatetimeComponent implements OnInit { @Input() edit = false; // True if editing the field. Defaults to false. @Input() disabled = false; // True if disabled. Defaults to false. @Input() form?: FormGroup; // Form where to add the form control. + @Input() contextLevel?: string; // The context level. + @Input() contextInstanceId?: number; // The instance ID related to the context. constructor(private fb: FormBuilder, private timeUtils: CoreTimeUtilsProvider, protected utils: CoreUtilsProvider, private translate: TranslateService) { } diff --git a/src/addon/userprofilefield/menu/component/addon-user-profile-field-menu.html b/src/addon/userprofilefield/menu/component/addon-user-profile-field-menu.html index dcde5daa8..ac8f11b04 100644 --- a/src/addon/userprofilefield/menu/component/addon-user-profile-field-menu.html +++ b/src/addon/userprofilefield/menu/component/addon-user-profile-field-menu.html @@ -1,7 +1,7 @@

{{ field.name }}

-

+

diff --git a/src/addon/userprofilefield/menu/component/menu.ts b/src/addon/userprofilefield/menu/component/menu.ts index 59642861a..c4365a44f 100644 --- a/src/addon/userprofilefield/menu/component/menu.ts +++ b/src/addon/userprofilefield/menu/component/menu.ts @@ -27,6 +27,9 @@ export class AddonUserProfileFieldMenuComponent implements OnInit { @Input() edit = false; // True if editing the field. Defaults to false. @Input() disabled = false; // True if disabled. Defaults to false. @Input() form?: FormGroup; // Form where to add the form control. + @Input() contextLevel?: string; // The context level. + @Input() contextInstanceId?: number; // The instance ID related to the context. + @Input() courseId?: number; // The course the field belongs to (if any). constructor(private fb: FormBuilder) { } diff --git a/src/addon/userprofilefield/text/component/addon-user-profile-field-text.html b/src/addon/userprofilefield/text/component/addon-user-profile-field-text.html index 1ca1a727d..977c7cd49 100644 --- a/src/addon/userprofilefield/text/component/addon-user-profile-field-text.html +++ b/src/addon/userprofilefield/text/component/addon-user-profile-field-text.html @@ -1,7 +1,7 @@

{{ field.name }}

-

+

diff --git a/src/addon/userprofilefield/text/component/text.ts b/src/addon/userprofilefield/text/component/text.ts index 089a58bb0..1eda97aca 100644 --- a/src/addon/userprofilefield/text/component/text.ts +++ b/src/addon/userprofilefield/text/component/text.ts @@ -28,6 +28,9 @@ export class AddonUserProfileFieldTextComponent implements OnInit { @Input() edit = false; // True if editing the field. Defaults to false. @Input() disabled = false; // True if disabled. Defaults to false. @Input() form?: FormGroup; // Form where to add the form control. + @Input() contextLevel?: string; // The context level. + @Input() contextInstanceId?: number; // The instance ID related to the context. + @Input() courseId?: number; // The course the field belongs to (if any). constructor(private fb: FormBuilder, protected utils: CoreUtilsProvider) { } diff --git a/src/addon/userprofilefield/textarea/component/addon-user-profile-field-textarea.html b/src/addon/userprofilefield/textarea/component/addon-user-profile-field-textarea.html index 4a993015b..1d149a8ed 100644 --- a/src/addon/userprofilefield/textarea/component/addon-user-profile-field-textarea.html +++ b/src/addon/userprofilefield/textarea/component/addon-user-profile-field-textarea.html @@ -1,7 +1,7 @@

{{ field.name }}

-

+

diff --git a/src/addon/userprofilefield/textarea/component/textarea.ts b/src/addon/userprofilefield/textarea/component/textarea.ts index 79919bd35..43c9701b2 100644 --- a/src/addon/userprofilefield/textarea/component/textarea.ts +++ b/src/addon/userprofilefield/textarea/component/textarea.ts @@ -27,6 +27,9 @@ export class AddonUserProfileFieldTextareaComponent implements OnInit { @Input() edit = false; // True if editing the field. Defaults to false. @Input() disabled = false; // True if disabled. Defaults to false. @Input() form?: FormGroup; // Form where to add the form control. + @Input() contextLevel?: string; // The context level. + @Input() contextInstanceId?: number; // The instance ID related to the context. + @Input() courseId?: number; // The course the field belongs to (if any). control: FormControl; diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4d55ba341..6f9966fa8 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -82,6 +82,7 @@ import { CoreCommentsModule } from '@core/comments/comments.module'; import { CoreBlockModule } from '@core/block/block.module'; import { CoreRatingModule } from '@core/rating/rating.module'; import { CoreTagModule } from '@core/tag/tag.module'; +import { CoreFilterModule } from '@core/filter/filter.module'; // Addon modules. import { AddonBadgesModule } from '@addon/badges/badges.module'; @@ -147,6 +148,7 @@ import { AddonRemoteThemesModule } from '@addon/remotethemes/remotethemes.module import { AddonQbehaviourModule } from '@addon/qbehaviour/qbehaviour.module'; import { AddonQtypeModule } from '@addon/qtype/qtype.module'; import { AddonStorageManagerModule } from '@addon/storagemanager/storagemanager.module'; +import { AddonFilterModule } from '@addon/filter/filter.module'; // For translate loader. AoT requires an exported function for factories. export function createTranslateLoader(http: HttpClient): TranslateHttpLoader { @@ -227,6 +229,7 @@ export const WP_PROVIDER: any = null; CoreRatingModule, CorePushNotificationsModule, CoreTagModule, + CoreFilterModule, AddonBadgesModule, AddonBlogModule, AddonCalendarModule, @@ -288,7 +291,8 @@ export const WP_PROVIDER: any = null; AddonRemoteThemesModule, AddonQbehaviourModule, AddonQtypeModule, - AddonStorageManagerModule + AddonStorageManagerModule, + AddonFilterModule ], bootstrap: [IonicApp], entryComponents: [ diff --git a/src/classes/delegate.ts b/src/classes/delegate.ts index ca6cea0e5..db31ff907 100644 --- a/src/classes/delegate.ts +++ b/src/classes/delegate.ts @@ -79,6 +79,21 @@ export class CoreDelegate { */ protected updatePromises: {[siteId: string]: {[name: string]: Promise}} = {}; + /** + * Whether handlers have been initialized. + */ + protected handlersInitialized = false; + + /** + * Promise to wait for handlers to be initialized. + */ + protected handlersInitPromise: Promise; + + /** + * Function to resolve the handlers init promise. + */ + protected handlersInitResolve: (value?: any) => void; + /** * Constructor of the Delegate. * @@ -92,6 +107,10 @@ export class CoreDelegate { protected eventsProvider?: CoreEventsProvider) { this.logger = this.loggerProvider.getInstance(delegateName); + this.handlersInitPromise = new Promise((resolve): void => { + this.handlersInitResolve = resolve; + }); + if (eventsProvider) { // Update handlers on this cases. eventsProvider.on(CoreEventsProvider.LOGIN, this.updateHandlers.bind(this)); @@ -315,6 +334,9 @@ export class CoreDelegate { // Verify that this call is the last one that was started. if (this.isLastUpdateCall(now)) { + this.handlersInitialized = true; + this.handlersInitResolve(); + this.updateData(); } }); diff --git a/src/classes/site.ts b/src/classes/site.ts index 84e7bdaaf..d4988f66a 100644 --- a/src/classes/site.ts +++ b/src/classes/site.ts @@ -1036,15 +1036,7 @@ export class CoreSite { preSets.omitExpires = preSets.omitExpires || preSets.forceOffline || !this.appProvider.isOnline(); if (!preSets.omitExpires) { - let expirationDelay = this.UPDATE_FREQUENCIES[preSets.updateFrequency] || - this.UPDATE_FREQUENCIES[CoreSite.FREQUENCY_USUALLY]; - - if (this.appProvider.isNetworkAccessLimited()) { - // Not WiFi, increase the expiration delay a 50% to decrease the data usage in this case. - expirationDelay *= 1.5; - } - - expirationTime = entry.expirationTime + expirationDelay; + expirationTime = entry.expirationTime + this.getExpirationDelay(preSets.updateFrequency); if (now > expirationTime) { this.logger.debug('Cached element found, but it is expired'); @@ -1165,7 +1157,9 @@ export class CoreSite { this.logger.debug('Invalidate all the cache for site: ' + this.id); - return this.db.updateRecords(CoreSite.WS_CACHE_TABLE, { expirationTime: 0 }); + return this.db.updateRecords(CoreSite.WS_CACHE_TABLE, { expirationTime: 0 }).finally(() => { + this.eventsProvider.trigger(CoreEventsProvider.WS_CACHE_INVALIDATED, {}, this.getId()); + }); } /** @@ -1875,4 +1869,21 @@ export class CoreSite { setLocalSiteConfig(name: string, value: number | string): Promise { return this.db.insertRecord(CoreSite.CONFIG_TABLE, { name: name, value: value }); } + + /** + * Get a certain cache expiration delay. + * + * @param updateFrequency The update frequency of the entry. + * @return {number} Expiration delay. + */ + getExpirationDelay(updateFrequency?: number): number { + let expirationDelay = this.UPDATE_FREQUENCIES[updateFrequency] || this.UPDATE_FREQUENCIES[CoreSite.FREQUENCY_USUALLY]; + + if (this.appProvider.isNetworkAccessLimited()) { + // Not WiFi, increase the expiration delay a 50% to decrease the data usage in this case. + expirationDelay *= 1.5; + } + + return expirationDelay; + } } diff --git a/src/components/chart/chart.ts b/src/components/chart/chart.ts index 8d67b8853..b3715ad43 100644 --- a/src/components/chart/chart.ts +++ b/src/components/chart/chart.ts @@ -14,6 +14,9 @@ import { Component, Input, OnDestroy, OnInit, ElementRef, OnChanges, ViewChild } from '@angular/core'; import { Chart } from 'chart.js'; +import { CoreFilterProvider } from '@core/filter/providers/filter'; +import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; +import { CoreUtilsProvider } from '@providers/utils/utils'; /** * This component shows a chart using chart.js. @@ -44,13 +47,17 @@ export class CoreChartComponent implements OnDestroy, OnInit, OnChanges { @Input() type: string; // Type of chart. @Input() legend: any; // Legend options. @Input() height = 300; // Height of the chart element. + @Input() filter?: boolean | string; // Whether to filter labels. If not defined, true if contextLevel and instanceId are set. + @Input() contextLevel?: string; // The context level of the text. + @Input() contextInstanceId?: number; // The instance ID related to the context. + @Input() courseId?: number; // Course ID the text belongs to. It can be used to improve performance with filters. + @Input() wsNotFiltered?: boolean | string; // If true it means the WS didn't filter the labels for some reason. @ViewChild('canvas') canvas: ElementRef; chart: any; - constructor() { - // Nothing to do. - } + constructor(protected filterProvider: CoreFilterProvider, private utils: CoreUtilsProvider, + private filterHelper: CoreFilterHelperProvider) { } /** * Component being initialized. @@ -86,17 +93,21 @@ export class CoreChartComponent implements OnDestroy, OnInit, OnChanges { this.type = 'horizontalBar'; } - const context = this.canvas.nativeElement.getContext('2d'); - this.chart = new Chart(context, { - type: this.type, - data: { - labels: this.labels, - datasets: [{ - data: this.data, - backgroundColor: this.getRandomColors(this.data.length) - }] - }, - options: {legend: legend} + // Format labels if needed. + this.formatLabels().then(() => { + + const context = this.canvas.nativeElement.getContext('2d'); + this.chart = new Chart(context, { + type: this.type, + data: { + labels: this.labels, + datasets: [{ + data: this.data, + backgroundColor: this.getRandomColors(this.data.length) + }] + }, + options: {legend: legend} + }); }); } @@ -105,15 +116,50 @@ export class CoreChartComponent implements OnDestroy, OnInit, OnChanges { */ ngOnChanges(): void { if (this.chart) { - this.chart.data.datasets[0] = { - data: this.data, - backgroundColor: this.getRandomColors(this.data.length) - }; - this.chart.data.labels = this.labels; - this.chart.update(); + // Format labels if needed. + this.formatLabels().then(() => { + this.chart.data.datasets[0] = { + data: this.data, + backgroundColor: this.getRandomColors(this.data.length) + }; + this.chart.data.labels = this.labels; + this.chart.update(); + }); } } + /** + * Format labels if needed. + * + * @return Promise resolved when done. + */ + protected formatLabels(): Promise { + this.filter = typeof this.filter == 'undefined' ? !!(this.contextLevel && this.contextInstanceId) : !!this.filter; + + if (!this.filter) { + return Promise.resolve(); + } + + const options = { + clean: true, + singleLine: true, + courseId: this.courseId, + wsNotFiltered: this.utils.isTrueOrOne(this.wsNotFiltered) + }; + + return this.filterHelper.getFilters(this.contextLevel, this.contextInstanceId, options).then((filters) => { + const promises = []; + + this.labels.forEach((label, i) => { + promises.push(this.filterProvider.formatText(label, options, filters).then((text) => { + this.labels[i] = text; + })); + }); + + return Promise.all(promises); + }); + } + /** * Generate random colors if needed. * diff --git a/src/components/context-menu/core-context-menu-popover.html b/src/components/context-menu/core-context-menu-popover.html index 69ffdadf7..76a6b96d1 100644 --- a/src/components/context-menu/core-context-menu-popover.html +++ b/src/components/context-menu/core-context-menu-popover.html @@ -2,7 +2,7 @@ {{title}} - + {{item.badge}} diff --git a/src/components/course-picker-menu/core-course-picker-menu-popover.html b/src/components/course-picker-menu/core-course-picker-menu-popover.html index 6eea11d5e..ebfa0f52a 100644 --- a/src/components/course-picker-menu/core-course-picker-menu-popover.html +++ b/src/components/course-picker-menu/core-course-picker-menu-popover.html @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/src/components/navigation-bar/navigation-bar.ts b/src/components/navigation-bar/navigation-bar.ts index b5c2b0b42..2942e5c2d 100644 --- a/src/components/navigation-bar/navigation-bar.ts +++ b/src/components/navigation-bar/navigation-bar.ts @@ -35,6 +35,9 @@ export class CoreNavigationBarComponent { @Input() title?: string; // Title to show when seeing the info (new page). @Input() component?: string; // Component the bar belongs to. @Input() componentId?: number; // Component ID. + @Input() contextLevel?: string; // The context level. + @Input() contextInstanceId?: number; // The instance ID related to the context. + @Input() courseId?: number; // Course ID the text belongs to. It can be used to improve performance with filters. @Output() action?: EventEmitter; // Function to call when an arrow is clicked. Will receive as a param the item to load. constructor(private textUtils: CoreTextUtilsProvider) { @@ -42,6 +45,7 @@ export class CoreNavigationBarComponent { } showInfo(): void { - this.textUtils.expandText(this.title, this.info, this.component, this.componentId); + this.textUtils.expandText(this.title, this.info, this.component, this.componentId, [], true, this.contextLevel, + this.contextInstanceId, this.courseId); } } diff --git a/src/components/site-picker/site-picker.ts b/src/components/site-picker/site-picker.ts index e58dfda86..aa934bf57 100644 --- a/src/components/site-picker/site-picker.ts +++ b/src/components/site-picker/site-picker.ts @@ -15,7 +15,7 @@ import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { CoreSitesProvider } from '@providers/sites'; -import { CoreTextUtilsProvider } from '@providers/utils/text'; +import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; /** * Component to display a site selector. It will display a select with the list of sites. If the selected site changes, @@ -36,7 +36,7 @@ export class CoreSitePickerComponent implements OnInit { sites: any[]; constructor(private translate: TranslateService, private sitesProvider: CoreSitesProvider, - private textUtils: CoreTextUtilsProvider) { + private filterHelper: CoreFilterHelperProvider) { this.siteSelected = new EventEmitter(); } @@ -49,7 +49,8 @@ export class CoreSitePickerComponent implements OnInit { sites.forEach((site: any) => { // Format the site name. - promises.push(this.textUtils.formatText(site.siteName, true, true).catch(() => { + promises.push(this.filterHelper.getFiltersAndFormatText(site.siteName, 'system', 0, + {clean: true, singleLine: true}, site.getId()).catch(() => { return site.siteName; }).then((formatted) => { site.fullNameAndSiteName = this.translate.instant('core.fullnameandsitename', diff --git a/src/core/block/components/only-title-block/core-block-only-title.html b/src/core/block/components/only-title-block/core-block-only-title.html index 358fbde44..287592371 100644 --- a/src/core/block/components/only-title-block/core-block-only-title.html +++ b/src/core/block/components/only-title-block/core-block-only-title.html @@ -1,3 +1,3 @@ -

+

{{ title | translate }}

\ No newline at end of file diff --git a/src/core/block/components/pre-rendered-block/core-block-pre-rendered.html b/src/core/block/components/pre-rendered-block/core-block-pre-rendered.html index 84cf2ac52..4b3f46315 100644 --- a/src/core/block/components/pre-rendered-block/core-block-pre-rendered.html +++ b/src/core/block/components/pre-rendered-block/core-block-pre-rendered.html @@ -1,11 +1,11 @@ -

+

- + - + diff --git a/src/core/comments/components/comments/comments.ts b/src/core/comments/components/comments/comments.ts index ae310eae8..0f23b3353 100644 --- a/src/core/comments/components/comments/comments.ts +++ b/src/core/comments/components/comments/comments.ts @@ -35,6 +35,7 @@ export class CoreCommentsCommentsComponent implements OnChanges, OnDestroy { @Input() title?: string; @Input() displaySpinner = true; // Whether to display the loading spinner. @Output() onLoading: EventEmitter; // Eevent that indicates whether the component is loading data. + @Input() courseId?: number; // Course ID the comments belong to. It can be used to improve performance with filters. commentsLoaded = false; commentsCount: string; @@ -155,6 +156,7 @@ export class CoreCommentsCommentsComponent implements OnChanges, OnDestroy { itemId: this.itemId, area: this.area, title: this.title, + courseId: this.courseId }); } } diff --git a/src/core/comments/pages/viewer/viewer.html b/src/core/comments/pages/viewer/viewer.html index 2a023a419..40eadf01b 100644 --- a/src/core/comments/pages/viewer/viewer.html +++ b/src/core/comments/pages/viewer/viewer.html @@ -1,6 +1,6 @@ - +
- + @@ -56,7 +56,7 @@
- + diff --git a/src/core/comments/pages/viewer/viewer.ts b/src/core/comments/pages/viewer/viewer.ts index 63f88471b..b17d39f17 100644 --- a/src/core/comments/pages/viewer/viewer.ts +++ b/src/core/comments/pages/viewer/viewer.ts @@ -47,6 +47,7 @@ export class CoreCommentsViewerPage implements OnDestroy { area: string; page: number; title: string; + courseId: number; canLoadMore = false; loadMoreError = false; canAddComments = false; @@ -74,6 +75,7 @@ export class CoreCommentsViewerPage implements OnDestroy { this.itemId = navParams.get('itemId'); this.area = navParams.get('area') || ''; this.title = navParams.get('title') || this.translate.instant('core.comments.comments'); + this.courseId = navParams.get('courseId'); this.page = 0; // Refresh data if comments are synchronized automatically. diff --git a/src/core/compile/providers/compile.ts b/src/core/compile/providers/compile.ts index b394538b4..bbfc35f48 100644 --- a/src/core/compile/providers/compile.ts +++ b/src/core/compile/providers/compile.ts @@ -28,6 +28,7 @@ import { CORE_CONTENTLINKS_PROVIDERS } from '@core/contentlinks/contentlinks.mod import { CORE_COURSE_PROVIDERS } from '@core/course/course.module'; import { CORE_COURSES_PROVIDERS } from '@core/courses/courses.module'; import { CORE_FILEUPLOADER_PROVIDERS } from '@core/fileuploader/fileuploader.module'; +import { CORE_FILTER_PROVIDERS } from '@core/filter/filter.module'; import { CORE_GRADES_PROVIDERS } from '@core/grades/grades.module'; import { CORE_LOGIN_PROVIDERS } from '@core/login/login.module'; import { CORE_MAINMENU_PROVIDERS } from '@core/mainmenu/mainmenu.module'; @@ -234,7 +235,8 @@ 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(CORE_PUSHNOTIFICATIONS_PROVIDERS).concat(ADDON_REMOTETHEMES_PROVIDERS).concat(CORE_BLOCK_PROVIDERS); + .concat(CORE_PUSHNOTIFICATIONS_PROVIDERS).concat(ADDON_REMOTETHEMES_PROVIDERS).concat(CORE_BLOCK_PROVIDERS) + .concat(CORE_FILTER_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/contentlinks/pages/choose-site/choose-site.html b/src/core/contentlinks/pages/choose-site/choose-site.html index c6a401175..5ade9add5 100644 --- a/src/core/contentlinks/pages/choose-site/choose-site.html +++ b/src/core/contentlinks/pages/choose-site/choose-site.html @@ -15,7 +15,7 @@ {{ 'core.pictureof' | translate:{$a: site.fullname} }}

{{site.fullName}}

-

+

{{site.siteUrl}}

diff --git a/src/core/course/classes/activity-prefetch-handler.ts b/src/core/course/classes/activity-prefetch-handler.ts index c98a702fc..b655979f6 100644 --- a/src/core/course/classes/activity-prefetch-handler.ts +++ b/src/core/course/classes/activity-prefetch-handler.ts @@ -101,10 +101,11 @@ export class CoreCourseActivityPrefetchHandlerBase extends CoreCourseModulePrefe } const prefetchPromise = this.setDownloading(module.id, siteId).then(() => { - // Package marked as downloading, get module info to be able to handle links. + // Package marked as downloading, get module info to be able to handle links. Get module filters too. return Promise.all([ this.courseProvider.getModuleBasicInfo(module.id, siteId), this.courseProvider.getModule(module.id, courseId, undefined, false, true, siteId), + this.filterHelper.getFilters('module', module.id, {courseId: courseId}) ]); }).then(() => { // Call the download function, send all the params except downloadFn. This includes all params passed after siteId. diff --git a/src/core/course/classes/main-resource-component.ts b/src/core/course/classes/main-resource-component.ts index 3ffae46fe..87691f7d8 100644 --- a/src/core/course/classes/main-resource-component.ts +++ b/src/core/course/classes/main-resource-component.ts @@ -236,7 +236,8 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, * Expand the description. */ expandDescription(): void { - this.textUtils.expandText(this.translate.instant('core.description'), this.description, this.component, this.module.id); + this.textUtils.expandText(this.translate.instant('core.description'), this.description, this.component, this.module.id, + [], true, 'module', this.module.id, this.courseId); } /** diff --git a/src/core/course/classes/module-prefetch-handler.ts b/src/core/course/classes/module-prefetch-handler.ts index 8173f615b..2e344104a 100644 --- a/src/core/course/classes/module-prefetch-handler.ts +++ b/src/core/course/classes/module-prefetch-handler.ts @@ -20,6 +20,7 @@ import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreCourseProvider } from '../providers/course'; import { CoreCourseModulePrefetchHandler } from '../providers/module-prefetch-delegate'; +import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; /** * Base prefetch handler to be registered in CoreCourseModulePrefetchDelegate. Prefetch handlers should inherit either @@ -59,9 +60,14 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref */ protected downloadPromises: { [s: string]: { [s: string]: Promise } } = {}; - constructor(protected translate: TranslateService, protected appProvider: CoreAppProvider, protected utils: CoreUtilsProvider, - protected courseProvider: CoreCourseProvider, protected filepoolProvider: CoreFilepoolProvider, - protected sitesProvider: CoreSitesProvider, protected domUtils: CoreDomUtilsProvider) { } + constructor(protected translate: TranslateService, + protected appProvider: CoreAppProvider, + protected utils: CoreUtilsProvider, + protected courseProvider: CoreCourseProvider, + protected filepoolProvider: CoreFilepoolProvider, + protected sitesProvider: CoreSitesProvider, + protected domUtils: CoreDomUtilsProvider, + protected filterHelper: CoreFilterHelperProvider) { } /** * Add an ongoing download to the downloadPromises list. When the promise finishes it will be removed. diff --git a/src/core/course/classes/resource-prefetch-handler.ts b/src/core/course/classes/resource-prefetch-handler.ts index 2847d3e69..db7a3a568 100644 --- a/src/core/course/classes/resource-prefetch-handler.ts +++ b/src/core/course/classes/resource-prefetch-handler.ts @@ -87,6 +87,8 @@ export class CoreCourseResourcePrefetchHandlerBase extends CoreCourseModulePrefe promises.push(downloadFn(siteId, files, this.component, module.id)); } + promises.push(this.filterHelper.getFilters('module', module.id, {courseId: courseId})); + return Promise.all(promises); }); diff --git a/src/core/course/components/format/core-course-format.html b/src/core/course/components/format/core-course-format.html index 7013b69f5..07b21f6db 100644 --- a/src/core/course/components/format/core-course-format.html +++ b/src/core/course/components/format/core-course-format.html @@ -58,10 +58,10 @@ @@ -74,13 +74,13 @@
- + - + diff --git a/src/core/course/components/module-completion/module-completion.ts b/src/core/course/components/module-completion/module-completion.ts index df4f4ceb2..a2db476ad 100644 --- a/src/core/course/components/module-completion/module-completion.ts +++ b/src/core/course/components/module-completion/module-completion.ts @@ -15,9 +15,9 @@ import { Component, Input, Output, EventEmitter, OnChanges, SimpleChange } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; -import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreUserProvider } from '@core/user/providers/user'; import { CoreCourseProvider } from '../../providers/course'; +import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; /** * Component to handle activity completion. It shows a checkbox with the current status, and allows manually changing @@ -34,13 +34,14 @@ import { CoreCourseProvider } from '../../providers/course'; }) export class CoreCourseModuleCompletionComponent implements OnChanges { @Input() completion: any; // The completion status. + @Input() moduleId?: number; // The name of the module this completion affects. @Input() moduleName?: string; // The name of the module this completion affects. @Output() completionChanged?: EventEmitter; // Will emit an event when the completion changes. completionImage: string; completionDescription: string; - constructor(private textUtils: CoreTextUtilsProvider, private domUtils: CoreDomUtilsProvider, + constructor(private filterHelper: CoreFilterHelperProvider, private domUtils: CoreDomUtilsProvider, private translate: TranslateService, private courseProvider: CoreCourseProvider, private userProvider: CoreUserProvider) { this.completionChanged = new EventEmitter(); @@ -137,7 +138,9 @@ export class CoreCourseModuleCompletionComponent implements OnChanges { } if (moduleName) { - this.textUtils.formatText(moduleName, true, true, 50).then((modNameFormatted) => { + this.filterHelper.getFiltersAndFormatText(moduleName, 'module', this.moduleId, + {clean: true, singleLine: true, shortenLength: 50, courseId: this.completion.courseId}).then((modName) => { + let promise; if (this.completion.overrideby > 0) { @@ -147,11 +150,11 @@ export class CoreCourseModuleCompletionComponent implements OnChanges { (profile) => { return { overrideuser: profile.fullname, - modname: modNameFormatted + modname: modName }; }); } else { - promise = Promise.resolve(modNameFormatted); + promise = Promise.resolve(modName); } return promise.then((translateParams) => { diff --git a/src/core/course/components/module-description/core-course-module-description.html b/src/core/course/components/module-description/core-course-module-description.html index 412d5bf3b..7cb12666b 100644 --- a/src/core/course/components/module-description/core-course-module-description.html +++ b/src/core/course/components/module-description/core-course-module-description.html @@ -1,6 +1,6 @@ - + {{ note }} diff --git a/src/core/course/components/module-description/module-description.ts b/src/core/course/components/module-description/module-description.ts index 0e19d86b1..c17f51609 100644 --- a/src/core/course/components/module-description/module-description.ts +++ b/src/core/course/components/module-description/module-description.ts @@ -40,6 +40,9 @@ export class CoreCourseModuleDescriptionComponent { @Input() component?: string; // Component for format text directive. @Input() componentId?: string | number; // Component ID to use in conjunction with the component. @Input() showFull?: string | boolean; // Whether to always display the full description. + @Input() contextLevel?: string; // The context level. + @Input() contextInstanceId?: number; // The instance ID related to the context. + @Input() courseId?: number; // Course ID the text belongs to. It can be used to improve performance with filters. constructor() { // Nothing to do. diff --git a/src/core/course/components/module/core-course-module.html b/src/core/course/components/module/core-course-module.html index 0b0239685..3c57e9abb 100644 --- a/src/core/course/components/module/core-course-module.html +++ b/src/core/course/components/module/core-course-module.html @@ -2,12 +2,12 @@
- +
- +
@@ -21,15 +21,15 @@
- + {{ 'core.course.hiddenfromstudents' | translate }} {{ 'core.course.hiddenoncoursepage' | translate }}
{{ 'core.restricted' | translate }} - +
{{ 'core.course.manualcompletionnotsynced' | translate }}
- + \ No newline at end of file diff --git a/src/core/course/components/unsupported-module/core-course-unsupported-module.html b/src/core/course/components/unsupported-module/core-course-unsupported-module.html index 3738ade00..e28fe05c8 100644 --- a/src/core/course/components/unsupported-module/core-course-unsupported-module.html +++ b/src/core/course/components/unsupported-module/core-course-unsupported-module.html @@ -1,5 +1,5 @@
- +

{{ 'core.whoops' | translate }}

{{ 'core.uhoh' | translate }}

diff --git a/src/core/course/components/unsupported-module/unsupported-module.ts b/src/core/course/components/unsupported-module/unsupported-module.ts index c606d4658..6a0cfdd2c 100644 --- a/src/core/course/components/unsupported-module/unsupported-module.ts +++ b/src/core/course/components/unsupported-module/unsupported-module.ts @@ -24,7 +24,7 @@ import { CoreCourseModuleDelegate } from '../../providers/module-delegate'; templateUrl: 'core-course-unsupported-module.html', }) export class CoreCourseUnsupportedModuleComponent implements OnInit { - @Input() course: any; // The course to module belongs to. + @Input() courseId: number; // The course to module belongs to. @Input() module: any; // The module to render. isDisabledInSite: boolean; 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 index 7315af183..39678efed 100644 --- a/src/core/course/pages/list-mod-type/list-mod-type.html +++ b/src/core/course/pages/list-mod-type/list-mod-type.html @@ -1,6 +1,6 @@ - + {{ title }} diff --git a/src/core/course/pages/section-selector/section-selector.html b/src/core/course/pages/section-selector/section-selector.html index e160fa1f6..e8af2bc87 100644 --- a/src/core/course/pages/section-selector/section-selector.html +++ b/src/core/course/pages/section-selector/section-selector.html @@ -13,10 +13,10 @@ -

+

{{ 'core.course.hiddenfromstudents' | translate }} - +
diff --git a/src/core/course/pages/section-selector/section-selector.ts b/src/core/course/pages/section-selector/section-selector.ts index c86cf171c..d3ce687c3 100644 --- a/src/core/course/pages/section-selector/section-selector.ts +++ b/src/core/course/pages/section-selector/section-selector.ts @@ -30,12 +30,15 @@ export class CoreCourseSectionSelectorPage { stealthModulesSectionId = CoreCourseProvider.STEALTH_MODULES_SECTION_ID; sections: any; selected: number; + courseId: number; constructor(navParams: NavParams, courseHelper: CoreCourseHelperProvider, private viewCtrl: ViewController) { this.sections = navParams.get('sections'); this.selected = navParams.get('selected'); const course = navParams.get('course'); + this.courseId = course && course.id; + if (course && course.enablecompletion && course.courseformatoptions && course.courseformatoptions.coursedisplay == 1 && course.completionusertracked !== false) { this.sections.forEach((section) => { diff --git a/src/core/course/pages/section/section.html b/src/core/course/pages/section/section.html index ea12ab46f..6d2411153 100644 --- a/src/core/course/pages/section/section.html +++ b/src/core/course/pages/section/section.html @@ -1,6 +1,6 @@ - + diff --git a/src/core/course/pages/section/section.ts b/src/core/course/pages/section/section.ts index 907e88518..de9e1cdf2 100644 --- a/src/core/course/pages/section/section.ts +++ b/src/core/course/pages/section/section.ts @@ -18,7 +18,6 @@ import { TranslateService } from '@ngx-translate/core'; import { CoreEventsProvider } from '@providers/events'; import { CoreSitesProvider } from '@providers/sites'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; -import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreTabsComponent } from '@components/tabs/tabs'; import { CoreCoursesProvider } from '@core/courses/providers/courses'; @@ -30,6 +29,7 @@ import { CoreCourseOptionsDelegate, CoreCourseOptionsHandlerToDisplay, CoreCourseOptionsMenuHandlerToDisplay } from '../../providers/options-delegate'; import { CoreCourseSyncProvider } from '../../providers/sync'; import { CoreCourseFormatComponent } from '../../components/format/format'; +import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; /** * Page that displays the list of courses the user is enrolled in. @@ -75,7 +75,7 @@ export class CoreCourseSectionPage implements OnDestroy { constructor(navParams: NavParams, private courseProvider: CoreCourseProvider, private domUtils: CoreDomUtilsProvider, private courseFormatDelegate: CoreCourseFormatDelegate, private courseOptionsDelegate: CoreCourseOptionsDelegate, private translate: TranslateService, private courseHelper: CoreCourseHelperProvider, eventsProvider: CoreEventsProvider, - private textUtils: CoreTextUtilsProvider, private coursesProvider: CoreCoursesProvider, + private coursesProvider: CoreCoursesProvider, private filterHelper: CoreFilterHelperProvider, sitesProvider: CoreSitesProvider, private navCtrl: NavController, private injector: Injector, private prefetchDelegate: CoreCourseModulePrefetchDelegate, private syncProvider: CoreCourseSyncProvider, private utils: CoreUtilsProvider) { @@ -263,7 +263,8 @@ export class CoreCourseSectionPage implements OnDestroy { // Format the name of each section and check if it has content. this.sections = sections.map((section) => { - this.textUtils.formatText(section.name.trim(), true, true).then((name) => { + this.filterHelper.getFiltersAndFormatText(section.name.trim(), 'course', this.course.id, + {clean: true, singleLine: true}).then((name) => { section.formattedName = name; }); section.hasContent = this.courseHelper.sectionHasContent(section); diff --git a/src/core/course/pages/unsupported-module/unsupported-module.html b/src/core/course/pages/unsupported-module/unsupported-module.html index 13c933949..21a839390 100644 --- a/src/core/course/pages/unsupported-module/unsupported-module.html +++ b/src/core/course/pages/unsupported-module/unsupported-module.html @@ -1,6 +1,6 @@ - + @@ -11,5 +11,5 @@ - + diff --git a/src/core/course/pages/unsupported-module/unsupported-module.ts b/src/core/course/pages/unsupported-module/unsupported-module.ts index 8ecd58f00..a28a2dde6 100644 --- a/src/core/course/pages/unsupported-module/unsupported-module.ts +++ b/src/core/course/pages/unsupported-module/unsupported-module.ts @@ -27,15 +27,18 @@ import { CoreTextUtilsProvider } from '@providers/utils/text'; }) export class CoreCourseUnsupportedModulePage { module: any; + courseId: number; constructor(navParams: NavParams, private translate: TranslateService, private textUtils: CoreTextUtilsProvider) { this.module = navParams.get('module') || {}; + this.courseId = navParams.get('courseId'); } /** * Expand the description. */ expandDescription(): void { - this.textUtils.expandText(this.translate.instant('core.description'), this.module.description); + this.textUtils.expandText(this.translate.instant('core.description'), this.module.description, undefined, undefined, + [], true, 'module', this.module.id, this.courseId); } } diff --git a/src/core/course/providers/default-module.ts b/src/core/course/providers/default-module.ts index c69e280a6..bfa297f11 100644 --- a/src/core/course/providers/default-module.ts +++ b/src/core/course/providers/default-module.ts @@ -55,7 +55,7 @@ export class CoreCourseModuleDefaultHandler implements CoreCourseModuleHandler { event.preventDefault(); event.stopPropagation(); - navCtrl.push('CoreCourseUnsupportedModulePage', { module: module }, options); + navCtrl.push('CoreCourseUnsupportedModulePage', { module: module, courseId: courseId }, options); } }; diff --git a/src/core/course/providers/helper.ts b/src/core/course/providers/helper.ts index 30b0e0dff..f4b2f8bcb 100644 --- a/src/core/course/providers/helper.ts +++ b/src/core/course/providers/helper.ts @@ -38,6 +38,7 @@ import { CoreConstants } from '@core/constants'; import { CoreSite } from '@classes/site'; import { CoreLoggerProvider } from '@providers/logger'; import * as moment from 'moment'; +import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; /** * Prefetch info of a module. @@ -108,16 +109,28 @@ export class CoreCourseHelperProvider { protected courseDwnPromises: { [s: string]: { [id: number]: Promise } } = {}; protected logger; - constructor(private courseProvider: CoreCourseProvider, private domUtils: CoreDomUtilsProvider, - private moduleDelegate: CoreCourseModuleDelegate, private prefetchDelegate: CoreCourseModulePrefetchDelegate, - private filepoolProvider: CoreFilepoolProvider, private sitesProvider: CoreSitesProvider, - private textUtils: CoreTextUtilsProvider, private timeUtils: CoreTimeUtilsProvider, - private utils: CoreUtilsProvider, private translate: TranslateService, private loginHelper: CoreLoginHelperProvider, - private courseOptionsDelegate: CoreCourseOptionsDelegate, private siteHomeProvider: CoreSiteHomeProvider, - private eventsProvider: CoreEventsProvider, private fileHelper: CoreFileHelperProvider, - private appProvider: CoreAppProvider, private fileProvider: CoreFileProvider, private injector: Injector, - private coursesProvider: CoreCoursesProvider, private courseOffline: CoreCourseOfflineProvider, - loggerProvider: CoreLoggerProvider) { + constructor(private courseProvider: CoreCourseProvider, + private domUtils: CoreDomUtilsProvider, + private moduleDelegate: CoreCourseModuleDelegate, + private prefetchDelegate: CoreCourseModulePrefetchDelegate, + private filepoolProvider: CoreFilepoolProvider, + private sitesProvider: CoreSitesProvider, + private textUtils: CoreTextUtilsProvider, + private timeUtils: CoreTimeUtilsProvider, + private utils: CoreUtilsProvider, + private translate: TranslateService, + private loginHelper: CoreLoginHelperProvider, + private courseOptionsDelegate: CoreCourseOptionsDelegate, + private siteHomeProvider: CoreSiteHomeProvider, + private eventsProvider: CoreEventsProvider, + private fileHelper: CoreFileHelperProvider, + private appProvider: CoreAppProvider, + private fileProvider: CoreFileProvider, + private injector: Injector, + private coursesProvider: CoreCoursesProvider, + private courseOffline: CoreCourseOfflineProvider, + loggerProvider: CoreLoggerProvider, + private filterHelper: CoreFilterHelperProvider) { this.logger = loggerProvider.getInstance('CoreCourseHelperProvider'); } @@ -1270,6 +1283,8 @@ export class CoreCourseHelperProvider { promises.push(this.courseProvider.getActivitiesCompletionStatus(course.id)); } + promises.push(this.filterHelper.getFilters('course', course.id)); + return this.utils.allPromises(promises); }).then(() => { // Download success, mark the course as downloaded. diff --git a/src/core/courses/components/course-list-item/core-courses-course-list-item.html b/src/core/courses/components/course-list-item/core-courses-course-list-item.html index a56a02b9b..e594ff06b 100644 --- a/src/core/courses/components/course-list-item/core-courses-course-list-item.html +++ b/src/core/courses/components/course-list-item/core-courses-course-list-item.html @@ -1,6 +1,6 @@ -

+

diff --git a/src/core/courses/components/course-progress/core-courses-course-progress.html b/src/core/courses/components/course-progress/core-courses-course-progress.html index 985d92008..ed72a738e 100644 --- a/src/core/courses/components/course-progress/core-courses-course-progress.html +++ b/src/core/courses/components/course-progress/core-courses-course-progress.html @@ -4,10 +4,10 @@
-

+

- +

diff --git a/src/core/courses/pages/categories/categories.html b/src/core/courses/pages/categories/categories.html index e24c372bb..0952bb4ef 100644 --- a/src/core/courses/pages/categories/categories.html +++ b/src/core/courses/pages/categories/categories.html @@ -1,6 +1,6 @@ - + @@ -10,10 +10,10 @@ -

+

- +
@@ -21,7 +21,7 @@
-

+

{{category.coursecount}}
diff --git a/src/core/courses/pages/course-preview/course-preview.html b/src/core/courses/pages/course-preview/course-preview.html index e379c0b21..f84814ab6 100644 --- a/src/core/courses/pages/course-preview/course-preview.html +++ b/src/core/courses/pages/course-preview/course-preview.html @@ -1,6 +1,6 @@ - + @@ -15,13 +15,13 @@
-

-

+

+

{{course.startdate * 1000 | coreFormatDate:"strftimedatefullshort" }} - {{course.enddate * 1000 | coreFormatDate:"strftimedatefullshort" }}

- + @@ -36,8 +36,8 @@
- : - + : +
diff --git a/src/core/courses/pages/dashboard/dashboard.html b/src/core/courses/pages/dashboard/dashboard.html index 4f030b26f..401379077 100644 --- a/src/core/courses/pages/dashboard/dashboard.html +++ b/src/core/courses/pages/dashboard/dashboard.html @@ -1,6 +1,6 @@ - +
diff --git a/src/core/user/pages/profile/profile.html b/src/core/user/pages/profile/profile.html index fae5a9edd..fcda7fd09 100644 --- a/src/core/user/pages/profile/profile.html +++ b/src/core/user/pages/profile/profile.html @@ -1,6 +1,6 @@ - + {{ title }} @@ -13,11 +13,11 @@ -

-

+

{{ user.fullname }}

+

{{ user.address }}

{{ 'core.user.roles' | translate}}{{'core.labelsep' | translate}} - + {{ user.roles }}

diff --git a/src/core/viewer/pages/text/text.html b/src/core/viewer/pages/text/text.html index 56fc902a9..410063705 100644 --- a/src/core/viewer/pages/text/text.html +++ b/src/core/viewer/pages/text/text.html @@ -10,7 +10,7 @@ - + diff --git a/src/core/viewer/pages/text/text.ts b/src/core/viewer/pages/text/text.ts index 6ab1e7bf3..6c8c1b6f8 100644 --- a/src/core/viewer/pages/text/text.ts +++ b/src/core/viewer/pages/text/text.ts @@ -30,6 +30,10 @@ export class CoreViewerTextPage { component: string; // Component to use in format-text. componentId: string | number; // Component ID to use in format-text. files: any[]; // List of files. + filter: boolean; // Whether to filter the text. + contextLevel: string; // The context level. + instanceId: number; // The instance ID related to the context. + courseId: number; // Course ID the text belongs to. It can be used to improve performance with filters. constructor(private viewCtrl: ViewController, params: NavParams, textUtils: CoreTextUtilsProvider) { this.title = params.get('title'); @@ -37,6 +41,10 @@ export class CoreViewerTextPage { this.component = params.get('component'); this.componentId = params.get('componentId'); this.files = params.get('files'); + this.filter = params.get('filter'); + this.contextLevel = params.get('contextLevel'); + this.instanceId = params.get('instanceId'); + this.courseId = params.get('courseId'); } /** diff --git a/src/directives/format-text.ts b/src/directives/format-text.ts index a723f2116..cffef5187 100644 --- a/src/directives/format-text.ts +++ b/src/directives/format-text.ts @@ -30,10 +30,14 @@ import { CoreLinkDirective } from '../directives/link'; import { CoreExternalContentDirective } from '../directives/external-content'; import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper'; import { CoreSplitViewComponent } from '@components/split-view/split-view'; +import { CoreFilterProvider } from '@core/filter/providers/filter'; +import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; /** * Directive to format text rendered. It renders the HTML and treats all links and media, using CoreLinkDirective - * and CoreExternalContentDirective. + * and CoreExternalContentDirective. It also applies filters if needed. + * + * Please use this directive if your text needs to be filtered or it can contain links or media (images, audio, video). * * Example usage: * @@ -55,6 +59,11 @@ export class CoreFormatTextDirective implements OnChanges { @Input() fullOnClick?: boolean | string; // Whether it should open a new page with the full contents on click. @Input() fullTitle?: string; // Title to use in full view. Defaults to "Description". @Input() highlight?: string; // Text to highlight. + @Input() filter?: boolean | string; // Whether to filter the text. If not defined, true if contextLevel and instanceId are set. + @Input() contextLevel?: string; // The context level of the text. + @Input() contextInstanceId?: number; // The instance ID related to the context. + @Input() courseId?: number; // Course ID the text belongs to. It can be used to improve performance with filters. + @Input() wsNotFiltered?: boolean | string; // If true it means the WS didn't filter the text for some reason. @Output() afterRender?: EventEmitter; // Called when the data is rendered. protected element: HTMLElement; @@ -67,7 +76,8 @@ export class CoreFormatTextDirective implements OnChanges { private filepoolProvider: CoreFilepoolProvider, private appProvider: CoreAppProvider, private contentLinksHelper: CoreContentLinksHelperProvider, @Optional() private navCtrl: NavController, @Optional() private content: Content, @Optional() private svComponent: CoreSplitViewComponent, - private iframeUtils: CoreIframeUtilsProvider, private eventsProvider: CoreEventsProvider) { + private iframeUtils: CoreIframeUtilsProvider, private eventsProvider: CoreEventsProvider, + private filterProvider: CoreFilterProvider, private filterHelper: CoreFilterHelperProvider) { this.element = element.nativeElement; this.element.classList.add('opacity-hide'); // Hide contents until they're treated. this.afterRender = new EventEmitter(); @@ -275,8 +285,10 @@ export class CoreFormatTextDirective implements OnChanges { return; } else { // Open a new state with the contents. + const filter = this.utils.isTrueOrOne(this.filter); + this.textUtils.expandText(this.fullTitle || this.translate.instant('core.description'), this.text, - this.component, this.componentId); + this.component, this.componentId, undefined, filter, this.contextLevel, this.contextInstanceId, this.courseId); } } @@ -363,9 +375,27 @@ export class CoreFormatTextDirective implements OnChanges { }).then((siteInstance: CoreSite) => { site = siteInstance; - // Apply format text function. - return this.textUtils.formatText(this.text, this.utils.isTrueOrOne(this.clean), - this.utils.isTrueOrOne(this.singleLine), undefined, this.highlight); + if (this.contextLevel == 'course' && this.contextInstanceId <= 0) { + this.contextInstanceId = site.getSiteHomeId(); + } + + this.filter = typeof this.filter == 'undefined' ? !!(this.contextLevel && this.contextInstanceId) : !!this.filter; + + const options = { + clean: this.utils.isTrueOrOne(this.clean), + singleLine: this.utils.isTrueOrOne(this.singleLine), + highlight: this.highlight, + courseId: this.courseId, + wsNotFiltered: this.utils.isTrueOrOne(this.wsNotFiltered) + }; + + if (this.filter) { + return this.filterHelper.getFiltersAndFormatText(this.text, this.contextLevel, this.contextInstanceId, options, + site.getId()); + } else { + return this.filterProvider.formatText(this.text, options); + } + }).then((formatted) => { const div = document.createElement('div'), canTreatVimeo = site && site.isVersionGreaterEqualThan(['3.3.4', '3.4']), @@ -425,7 +455,6 @@ export class CoreFormatTextDirective implements OnChanges { }); videos.forEach((video) => { - this.treatVideoFilters(video, navCtrl); this.treatMedia(video); }); @@ -549,40 +578,6 @@ export class CoreFormatTextDirective implements OnChanges { this.showMoreDisplayed = false; } - /** - * Treat video filters. Currently only treating youtube video using video JS. - * - * @param el Video element. - * @param navCtrl NavController to use. - */ - protected treatVideoFilters(video: HTMLElement, navCtrl: NavController): void { - // Treat Video JS Youtube video links and translate them to iframes. - if (!video.classList.contains('video-js')) { - return; - } - - const data = this.textUtils.parseJSON(video.getAttribute('data-setup') || video.getAttribute('data-setup-lazy') || '{}'), - youtubeData = data.techOrder && data.techOrder[0] && data.techOrder[0] == 'youtube' && - this.parseYoutubeUrl(data.sources && data.sources[0] && data.sources[0].src); - - if (!youtubeData || !youtubeData.videoId) { - return; - } - - const iframe = document.createElement('iframe'); - iframe.id = video.id; - iframe.src = 'https://www.youtube.com/embed/' + youtubeData.videoId; // Don't apply other params to align with Moodle web. - iframe.setAttribute('frameborder', '0'); - iframe.setAttribute('allowfullscreen', '1'); - iframe.width = '100%'; - iframe.height = '300'; - - // Replace video tag by the iframe. - video.parentNode.replaceChild(iframe, video); - - this.iframeUtils.treatFrame(iframe, false, navCtrl); - } - /** * Add media adapt class and apply CoreExternalContentDirective to the media element and its sources and tracks. * @@ -693,54 +688,4 @@ export class CoreFormatTextDirective implements OnChanges { this.iframeUtils.treatFrame(iframe, false, navCtrl); } - - /** - * Parse a YouTube URL. - * Based on Youtube.parseUrl from Moodle media/player/videojs/amd/src/Youtube-lazy.js - * - * @param url URL of the video. - */ - protected parseYoutubeUrl(url: string): {videoId: string, listId?: string, start?: number} { - const result = { - videoId: null, - listId: null, - start: null - }; - - if (!url) { - return result; - } - - url = this.textUtils.decodeHTML(url); - - // Get the video ID. - let match = url.match(/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/); - - if (match && match[2].length === 11) { - result.videoId = match[2]; - } - - // Now get the playlist (if any). - match = url.match(/[?&]list=([^#\&\?]+)/); - - if (match && match[1]) { - result.listId = match[1]; - } - - // Now get the start time (if any). - match = url.match(/[?&]start=(\d+)/); - - if (match && match[1]) { - result.start = parseInt(match[1], 10); - } else { - // No start param, but it could have a time param. - match = url.match(/[?&]t=(\d+h)?(\d+m)?(\d+s)?/); - if (match) { - result.start = (match[1] ? parseInt(match[1], 10) * 3600 : 0) + (match[2] ? parseInt(match[2], 10) * 60 : 0) + - (match[3] ? parseInt(match[3], 10) : 0); - } - } - - return result; - } } diff --git a/src/providers/events.ts b/src/providers/events.ts index 2371b7fc5..5d1557ed8 100644 --- a/src/providers/events.ts +++ b/src/providers/events.ts @@ -62,6 +62,8 @@ export class CoreEventsProvider { static SEND_ON_ENTER_CHANGED = 'send_on_enter_changed'; static MAIN_MENU_OPEN = 'main_menu_open'; static SELECT_COURSE_TAB = 'select_course_tab'; + static WS_CACHE_INVALIDATED = 'ws_cache_invalidated'; + static SITE_STORAGE_DELETED = 'site_storage_deleted'; protected logger; protected observables: { [s: string]: Subject } = {}; diff --git a/src/providers/sites.ts b/src/providers/sites.ts index 5616f3dd2..d3e1ecba8 100644 --- a/src/providers/sites.ts +++ b/src/providers/sites.ts @@ -113,6 +113,11 @@ export interface CoreSiteBasicInfo { * Badge to display in the site. */ badge?: number; + + /** + * Site home ID. + */ + siteHomeId?: number; } /** @@ -1130,7 +1135,8 @@ export class CoreSitesProvider { siteUrl: site.siteUrl, fullName: siteInfo && siteInfo.fullname, siteName: CoreConfigConstants.sitename ? CoreConfigConstants.sitename : siteInfo && siteInfo.sitename, - avatar: siteInfo && siteInfo.userpictureurl + avatar: siteInfo && siteInfo.userpictureurl, + siteHomeId: siteInfo && siteInfo.siteid || 1 }; formattedSites.push(basicInfo); } diff --git a/src/providers/utils/text.ts b/src/providers/utils/text.ts index 9a6b7f005..9a244b6f7 100644 --- a/src/providers/utils/text.ts +++ b/src/providers/utils/text.ts @@ -349,15 +349,24 @@ export class CoreTextUtilsProvider { * @param component Component to link the embedded files to. * @param componentId An ID to use in conjunction with the component. * @param files List of files to display along with the text. + * @param filter Whether the text should be filtered. + * @param contextLevel The context level. + * @param instanceId The instance ID related to the context. + * @param courseId Course ID the text belongs to. It can be used to improve performance with filters. */ - expandText(title: string, text: string, component?: string, componentId?: string | number, files?: any[]): void { + expandText(title: string, text: string, component?: string, componentId?: string | number, files?: any[], + filter?: boolean, contextLevel?: string, instanceId?: number, courseId?: number): void { if (text.length > 0) { const params: any = { title: title, content: text, component: component, componentId: componentId, - files: files + files: files, + filter: filter, + contextLevel: contextLevel, + instanceId: instanceId, + courseId: courseId }; // Open a modal with the contents. @@ -398,6 +407,7 @@ export class CoreTextUtilsProvider { * @param shortenLength Number of characters to shorten the text. * @param highlight Text to highlight. * @return Promise resolved with the formatted text. + * @deprecated since 3.8.0. Please use CoreFilterProvider.formatText instead. */ formatText(text: string, clean?: boolean, singleLine?: boolean, shortenLength?: number, highlight?: string): Promise { return this.treatMultilangTags(text).then((formatted) => { @@ -732,6 +742,7 @@ export class CoreTextUtilsProvider { * * @param text The text to be treated. * @return Promise resolved with the formatted text. + * @deprecated since 3.8.0. Now this is handled by AddonFilterMultilangHandler. */ treatMultilangTags(text: string): Promise { if (!text || typeof text != 'string') {