From 31caccc39632491b196d99aac0bdedc7039154a9 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Thu, 3 Oct 2019 11:25:58 +0200 Subject: [PATCH] MOBILE-2491 filter: Support wsNotFiltered option and filter in chart --- .../filter/activitynames/providers/handler.ts | 13 +++ src/addon/filter/censor/providers/handler.ts | 13 +++ src/addon/filter/data/providers/handler.ts | 13 +++ .../filter/emailprotect/providers/handler.ts | 13 +++ .../filter/emoticon/providers/handler.ts | 13 +++ .../filter/glossary/providers/handler.ts | 13 +++ .../filter/mediaplugin/providers/handler.ts | 6 +- .../filter/multilang/providers/handler.ts | 78 ++++++++++-------- src/addon/filter/tex/providers/handler.ts | 13 +++ src/addon/filter/tidy/providers/handler.ts | 13 +++ .../filter/urltolink/providers/handler.ts | 13 +++ .../index/addon-mod-choice-index.html | 2 +- .../index/addon-mod-feedback-index.html | 2 +- src/addon/mod/feedback/pages/form/form.html | 8 +- src/components/chart/chart.ts | 82 ++++++++++++++----- src/core/filter/providers/default-filter.ts | 21 ++--- src/core/filter/providers/delegate.ts | 72 +++++++++++----- src/core/filter/providers/filter.ts | 64 ++++++++------- src/directives/format-text.ts | 3 +- 19 files changed, 332 insertions(+), 123 deletions(-) diff --git a/src/addon/filter/activitynames/providers/handler.ts b/src/addon/filter/activitynames/providers/handler.ts index 8e55846bb..025121803 100644 --- a/src/addon/filter/activitynames/providers/handler.ts +++ b/src/addon/filter/activitynames/providers/handler.ts @@ -15,6 +15,8 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; +import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; +import { CoreSite } from '@classes/site'; /** * Handler to support the Activity names filter. @@ -29,4 +31,15 @@ export class AddonFilterActivityNamesHandler extends CoreFilterDefaultHandler { // This filter is handled by Moodle, nothing to do in the app. } + + /** + * Check if the filter should be applied in a certain site based on some filter options. + * + * @param options Options. + * @param site Site. + * @return Whether filter should be applied. + */ + shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { + return false; + } } diff --git a/src/addon/filter/censor/providers/handler.ts b/src/addon/filter/censor/providers/handler.ts index 874d86ef9..018eb368b 100644 --- a/src/addon/filter/censor/providers/handler.ts +++ b/src/addon/filter/censor/providers/handler.ts @@ -15,6 +15,8 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; +import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; +import { CoreSite } from '@classes/site'; /** * Handler to support the Word censorship filter. @@ -29,4 +31,15 @@ export class AddonFilterCensorHandler extends CoreFilterDefaultHandler { // This filter is handled by Moodle, nothing to do in the app. } + + /** + * Check if the filter should be applied in a certain site based on some filter options. + * + * @param options Options. + * @param site Site. + * @return Whether filter should be applied. + */ + shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { + return false; + } } diff --git a/src/addon/filter/data/providers/handler.ts b/src/addon/filter/data/providers/handler.ts index f01cadb1d..e07e2ea4b 100644 --- a/src/addon/filter/data/providers/handler.ts +++ b/src/addon/filter/data/providers/handler.ts @@ -15,6 +15,8 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; +import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; +import { CoreSite } from '@classes/site'; /** * Handler to support the Database auto-link filter. @@ -29,4 +31,15 @@ export class AddonFilterDataHandler extends CoreFilterDefaultHandler { // This filter is handled by Moodle, nothing to do in the app. } + + /** + * Check if the filter should be applied in a certain site based on some filter options. + * + * @param options Options. + * @param site Site. + * @return Whether filter should be applied. + */ + shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { + return false; + } } diff --git a/src/addon/filter/emailprotect/providers/handler.ts b/src/addon/filter/emailprotect/providers/handler.ts index e7971386c..d339f6d33 100644 --- a/src/addon/filter/emailprotect/providers/handler.ts +++ b/src/addon/filter/emailprotect/providers/handler.ts @@ -15,6 +15,8 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; +import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; +import { CoreSite } from '@classes/site'; /** * Handler to support the Email protection filter. @@ -29,4 +31,15 @@ export class AddonFilterEmailProtectHandler extends CoreFilterDefaultHandler { // This filter is handled by Moodle, nothing to do in the app. } + + /** + * Check if the filter should be applied in a certain site based on some filter options. + * + * @param options Options. + * @param site Site. + * @return Whether filter should be applied. + */ + shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { + return false; + } } diff --git a/src/addon/filter/emoticon/providers/handler.ts b/src/addon/filter/emoticon/providers/handler.ts index 39c2ffe33..5523b0780 100644 --- a/src/addon/filter/emoticon/providers/handler.ts +++ b/src/addon/filter/emoticon/providers/handler.ts @@ -15,6 +15,8 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; +import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; +import { CoreSite } from '@classes/site'; /** * Handler to support the Emoticon filter. @@ -29,4 +31,15 @@ export class AddonFilterEmoticonHandler extends CoreFilterDefaultHandler { // This filter is handled by Moodle, nothing to do in the app. } + + /** + * Check if the filter should be applied in a certain site based on some filter options. + * + * @param options Options. + * @param site Site. + * @return Whether filter should be applied. + */ + shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { + return false; + } } diff --git a/src/addon/filter/glossary/providers/handler.ts b/src/addon/filter/glossary/providers/handler.ts index f7e38d553..9ffd6fec4 100644 --- a/src/addon/filter/glossary/providers/handler.ts +++ b/src/addon/filter/glossary/providers/handler.ts @@ -15,6 +15,8 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; +import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; +import { CoreSite } from '@classes/site'; /** * Handler to support the Glossary auto-link filter. @@ -29,4 +31,15 @@ export class AddonFilterGlossaryHandler extends CoreFilterDefaultHandler { // This filter is handled by Moodle, nothing to do in the app. } + + /** + * Check if the filter should be applied in a certain site based on some filter options. + * + * @param options Options. + * @param site Site. + * @return Whether filter should be applied. + */ + shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { + return false; + } } diff --git a/src/addon/filter/mediaplugin/providers/handler.ts b/src/addon/filter/mediaplugin/providers/handler.ts index 29da3de94..d7b91f2be 100644 --- a/src/addon/filter/mediaplugin/providers/handler.ts +++ b/src/addon/filter/mediaplugin/providers/handler.ts @@ -15,7 +15,7 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; -import { CoreFilterFilter } from '@core/filter/providers/filter'; +import { CoreFilterFilter, CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; import { CoreTextUtilsProvider } from '@providers/utils/text'; /** @@ -36,9 +36,11 @@ export class AddonFilterMediaPluginHandler extends CoreFilterDefaultHandler { * @param text The text to filter. * @param filter The filter. * @param options Options passed to the filters. + * @param siteId Site ID. If not defined, current site. * @return Filtered text (or promise resolved with the filtered text). */ - filter(text: string, filter: CoreFilterFilter, options: any): string | Promise { + filter(text: string, filter: CoreFilterFilter, options: CoreFilterFormatTextOptions, siteId?: string) + : string | Promise { const div = document.createElement('div'); div.innerHTML = text; diff --git a/src/addon/filter/multilang/providers/handler.ts b/src/addon/filter/multilang/providers/handler.ts index e689d9769..0b8d25d35 100644 --- a/src/addon/filter/multilang/providers/handler.ts +++ b/src/addon/filter/multilang/providers/handler.ts @@ -16,8 +16,9 @@ import { Injectable } from '@angular/core'; import { CoreSitesProvider } from '@providers/sites'; import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; -import { CoreFilterFilter } from '@core/filter/providers/filter'; +import { CoreFilterFilter, CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; import { CoreLangProvider } from '@providers/lang'; +import { CoreSite } from '@classes/site'; /** * Handler to support the Multilang filter. @@ -32,50 +33,61 @@ export class AddonFilterMultilangHandler extends CoreFilterDefaultHandler { super(); } - /** - * Whether or not 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 { - // In Moodle versions older than 3.7, some specific content can be received unfiltered. Filter it in the app. - const currentSite = this.sitesProvider.getCurrentSite(); - - return !currentSite.isVersionGreaterEqualThan('3.7'); - } - /** * Filter some text. * * @param text The text to filter. * @param filter The filter. * @param options Options passed to the filters. + * @param siteId Site ID. If not defined, current site. * @return Filtered text (or promise resolved with the filtered text). */ - filter(text: string, filter: CoreFilterFilter, options: any): string | Promise { + filter(text: string, filter: CoreFilterFilter, options: CoreFilterFormatTextOptions, siteId?: string) + : string | Promise { - return this.langProvider.getCurrentLanguage().then((language) => { - // Match the current language. - const anyLangRegEx = /<(?:lang|span)[^>]+lang="[a-zA-Z0-9_-]+"[^>]*>(.*?)<\/(?:lang|span)>/g; - let currentLangRegEx = new RegExp('<(?:lang|span)[^>]+lang="' + language + '"[^>]*>(.*?)<\/(?:lang|span)>', 'g'); + return this.sitesProvider.getSite(siteId).then((site) => { - if (!text.match(currentLangRegEx)) { - // Current lang not found. Try to find the first language. - const matches = text.match(anyLangRegEx); - if (matches && matches[0]) { - language = matches[0].match(/lang="([a-zA-Z0-9_-]+)"/)[1]; - currentLangRegEx = new RegExp('<(?:lang|span)[^>]+lang="' + language + '"[^>]*>(.*?)<\/(?:lang|span)>', 'g'); - } else { - // No multi-lang tag found, stop. - return text; - } + // Don't apply this filter if Moodle is 3.7 or higher and the WS already filtered the content. + if (!this.shouldBeApplied(options, site)) { + return text; } - // Extract contents of current language. - text = text.replace(currentLangRegEx, '$1'); - // Delete the rest of languages - text = text.replace(anyLangRegEx, ''); - return text; + return this.langProvider.getCurrentLanguage().then((language) => { + // Match the current language. + const anyLangRegEx = /<(?:lang|span)[^>]+lang="[a-zA-Z0-9_-]+"[^>]*>(.*?)<\/(?:lang|span)>/g; + let currentLangRegEx = new RegExp('<(?:lang|span)[^>]+lang="' + language + '"[^>]*>(.*?)<\/(?:lang|span)>', 'g'); + + if (!text.match(currentLangRegEx)) { + // Current lang not found. Try to find the first language. + const matches = text.match(anyLangRegEx); + if (matches && matches[0]) { + language = matches[0].match(/lang="([a-zA-Z0-9_-]+)"/)[1]; + currentLangRegEx = new RegExp('<(?:lang|span)[^>]+lang="' + language + '"[^>]*>(.*?)<\/(?:lang|span)>', + 'g'); + } else { + // No multi-lang tag found, stop. + return text; + } + } + // Extract contents of current language. + text = text.replace(currentLangRegEx, '$1'); + // Delete the rest of languages + text = text.replace(anyLangRegEx, ''); + + return text; + }); }); } + + /** + * Check if the filter should be applied in a certain site based on some filter options. + * + * @param options Options. + * @param site Site. + * @return Whether filter should be applied. + */ + shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { + // The filter should be applied if site is older than 3.7 or the WS didn't filter the text. + return options.wsNotFiltered || !site.isVersionGreaterEqualThan('3.7'); + } } diff --git a/src/addon/filter/tex/providers/handler.ts b/src/addon/filter/tex/providers/handler.ts index a02e8e7c7..d29302a0d 100644 --- a/src/addon/filter/tex/providers/handler.ts +++ b/src/addon/filter/tex/providers/handler.ts @@ -15,6 +15,8 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; +import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; +import { CoreSite } from '@classes/site'; /** * Handler to support the TeX notation filter. @@ -29,4 +31,15 @@ export class AddonFilterTexHandler extends CoreFilterDefaultHandler { // This filter is handled by Moodle, nothing to do in the app. } + + /** + * Check if the filter should be applied in a certain site based on some filter options. + * + * @param options Options. + * @param site Site. + * @return Whether filter should be applied. + */ + shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { + return false; + } } diff --git a/src/addon/filter/tidy/providers/handler.ts b/src/addon/filter/tidy/providers/handler.ts index e0fff232d..6ce6a6287 100644 --- a/src/addon/filter/tidy/providers/handler.ts +++ b/src/addon/filter/tidy/providers/handler.ts @@ -15,6 +15,8 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; +import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; +import { CoreSite } from '@classes/site'; /** * Handler to support the HTML tidy filter. @@ -29,4 +31,15 @@ export class AddonFilterTidyHandler extends CoreFilterDefaultHandler { // This filter is handled by Moodle, nothing to do in the app. } + + /** + * Check if the filter should be applied in a certain site based on some filter options. + * + * @param options Options. + * @param site Site. + * @return Whether filter should be applied. + */ + shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { + return false; + } } diff --git a/src/addon/filter/urltolink/providers/handler.ts b/src/addon/filter/urltolink/providers/handler.ts index d23c392b3..311a0c2c5 100644 --- a/src/addon/filter/urltolink/providers/handler.ts +++ b/src/addon/filter/urltolink/providers/handler.ts @@ -15,6 +15,8 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; +import { CoreFilterFormatTextOptions } from '@core/filter/providers/filter'; +import { CoreSite } from '@classes/site'; /** * Handler to support the URL to link and images filter. @@ -29,4 +31,15 @@ export class AddonFilterUrlToLinkHandler extends CoreFilterDefaultHandler { // This filter is handled by Moodle, nothing to do in the app. } + + /** + * Check if the filter should be applied in a certain site based on some filter options. + * + * @param options Options. + * @param site Site. + * @return Whether filter should be applied. + */ + shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { + return false; + } } diff --git a/src/addon/mod/choice/components/index/addon-mod-choice-index.html b/src/addon/mod/choice/components/index/addon-mod-choice-index.html index cf16a7b02..f4c0d5ac2 100644 --- a/src/addon/mod/choice/components/index/addon-mod-choice-index.html +++ b/src/addon/mod/choice/components/index/addon-mod-choice-index.html @@ -73,7 +73,7 @@ {{ 'addon.mod_choice.resultsnotsynced' | translate }} - + diff --git a/src/addon/mod/feedback/components/index/addon-mod-feedback-index.html b/src/addon/mod/feedback/components/index/addon-mod-feedback-index.html index f57fb1633..f1713c694 100644 --- a/src/addon/mod/feedback/components/index/addon-mod-feedback-index.html +++ b/src/addon/mod/feedback/components/index/addon-mod-feedback-index.html @@ -162,7 +162,7 @@ - +

{{ 'addon.mod_feedback.average' | translate }}: {{item.average | number : '1.2-2'}}

diff --git a/src/addon/mod/feedback/pages/form/form.html b/src/addon/mod/feedback/pages/form/form.html index 0339e939a..a1c3a8a63 100644 --- a/src/addon/mod/feedback/pages/form/form.html +++ b/src/addon/mod/feedback/pages/form/form.html @@ -23,7 +23,7 @@
-

+

@@ -38,20 +38,20 @@ - + - + - + diff --git a/src/components/chart/chart.ts b/src/components/chart/chart.ts index 8d67b8853..cd310d47e 100644 --- a/src/components/chart/chart.ts +++ b/src/components/chart/chart.ts @@ -14,6 +14,8 @@ import { Component, Input, OnDestroy, OnInit, ElementRef, OnChanges, ViewChild } from '@angular/core'; import { Chart } from 'chart.js'; +import { CoreFilterProvider } from '@core/filter/providers/filter'; +import { CoreUtilsProvider } from '@providers/utils/utils'; /** * This component shows a chart using chart.js. @@ -44,13 +46,15 @@ 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() 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) { } /** * Component being initialized. @@ -86,17 +90,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 +113,49 @@ 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, + wsNotFiltered: this.utils.isTrueOrOne(this.wsNotFiltered) + }; + + return this.filterProvider.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/core/filter/providers/default-filter.ts b/src/core/filter/providers/default-filter.ts index d339a4c8d..77abe1443 100644 --- a/src/core/filter/providers/default-filter.ts +++ b/src/core/filter/providers/default-filter.ts @@ -14,7 +14,8 @@ import { Injectable } from '@angular/core'; import { CoreFilterHandler } from './delegate'; -import { CoreFilterFilter } from './filter'; +import { CoreFilterFilter, CoreFilterFormatTextOptions } from './filter'; +import { CoreSite } from '@classes/site'; /** * Default handler used when the module doesn't have a specific implementation. @@ -34,9 +35,11 @@ export class CoreFilterDefaultHandler implements CoreFilterHandler { * @param text The text to filter. * @param filter The filter. * @param options Options passed to the filters. + * @param siteId Site ID. If not defined, current site. * @return Filtered text (or promise resolved with the filtered text). */ - filter(text: string, filter: CoreFilterFilter, options: any): string | Promise { + filter(text: string, filter: CoreFilterFilter, options: CoreFilterFormatTextOptions, siteId?: string) + : string | Promise { return text; } @@ -50,15 +53,13 @@ export class CoreFilterDefaultHandler implements CoreFilterHandler { } /** - * Setup the filter to be used. + * Check if the filter should be applied in a certain site based on some filter options. * - * Please notice this method iwill be called for each piece of text being filtered, so it is responsible - * for controlling its own execution cardinality. - * - * @param filter The filter. - * @return Promise resolved when done, or nothing if it's synchronous. + * @param options Options. + * @param site Site. + * @return Whether filter should be applied. */ - setup(filter: CoreFilterFilter): void | Promise { - // Nothing to do. + shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean { + return true; } } diff --git a/src/core/filter/providers/delegate.ts b/src/core/filter/providers/delegate.ts index 4fd742262..3fa27c298 100644 --- a/src/core/filter/providers/delegate.ts +++ b/src/core/filter/providers/delegate.ts @@ -16,9 +16,10 @@ import { Injectable } from '@angular/core'; import { CoreEventsProvider } from '@providers/events'; import { CoreLoggerProvider } from '@providers/logger'; import { CoreSitesProvider } from '@providers/sites'; -import { CoreFilterFilter } from './filter'; +import { CoreFilterFilter, CoreFilterFormatTextOptions } from './filter'; import { CoreFilterDefaultHandler } from './default-filter'; import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; +import { CoreSite } from '@classes/site'; /** * Interface that all filter handlers must implement. @@ -35,20 +36,19 @@ export interface CoreFilterHandler extends CoreDelegateHandler { * @param text The text to filter. * @param filter The filter. * @param options Options passed to the filters. + * @param siteId Site ID. If not defined, current site. * @return Filtered text (or promise resolved with the filtered text). */ - filter(text: string, filter: CoreFilterFilter, options: any): string | Promise; + filter(text: string, filter: CoreFilterFilter, options: CoreFilterFormatTextOptions, siteId?: string): string | Promise; /** - * Setup the filter to be used. + * Check if the filter should be applied in a certain site based on some filter options. * - * Please notice this method iwill be called for each piece of text being filtered, so it is responsible - * for controlling its own execution cardinality. - * - * @param filter The filter. - * @return Promise resolved when done, or nothing if it's synchronous. + * @param options Options. + * @param site Site. + * @return Whether filter should be applied. */ - setup(filter: CoreFilterFilter): void | Promise; + shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean; } /** @@ -71,12 +71,10 @@ export class CoreFilterDelegate extends CoreDelegate { * @param filters Filters to apply. * @param options Options passed to the filters. * @param skipFilters Names of filters that shouldn't be applied. + * @param siteId Site ID. If not defined, current site. * @return Promise resolved with the filtered text. */ - filterText(text: string, filters: CoreFilterFilter[], options?: any, skipFilters?: string[]): Promise { - if (!text || typeof text != 'string') { - return Promise.resolve(''); - } + filterText(text: string, filters: CoreFilterFilter[], options?: any, skipFilters?: string[], siteId?: string): Promise { // Wait for filters to be initialized. return this.handlersInitPromise.then(() => { @@ -98,7 +96,7 @@ export class CoreFilterDelegate extends CoreDelegate { } promise = promise.then((text) => { - return this.executeFunctionOnEnabled(filter.filter, 'filter', [text, filter, options]); + return this.executeFunctionOnEnabled(filter.filter, 'filter', [text, filter, options, siteId]); }); }); @@ -138,18 +136,48 @@ export class CoreFilterDelegate extends CoreDelegate { } /** - * Setup filters to be applied to some content. + * Check if at least 1 filter should be applied in a certain site and with certain options. * - * @param filters Filters to apply. - * @return Promise resolved when done. + * @param filter Filter to check. + * @param options Options passed to the filters. + * @param site Site. If not defined, current site. + * @return {Promise} Promise resolved with true: whether the filter should be applied. */ - setupFilters(filters: CoreFilterFilter[]): Promise { - const promises: Promise[] = []; + shouldBeApplied(filters: CoreFilterFilter[], options: CoreFilterFormatTextOptions, site?: CoreSite): Promise { + // Wait for filters to be initialized. + return this.handlersInitPromise.then(() => { + const promises = []; + let shouldBeApplied = false; - filters.forEach((filter) => { - promises.push(this.executeFunctionOnEnabled(filter.filter, 'setup', [filter])); + filters.forEach((filter) => { + promises.push(this.shouldFilterBeApplied(filter, options, site).then((applied) => { + if (applied) { + shouldBeApplied = applied; + } + })); + }); + + return Promise.all(promises).then(() => { + return shouldBeApplied; + }); }); + } - return Promise.all(promises); + /** + * Check whether a filter should be applied in a certain site and with certain options. + * + * @param filter Filter to check. + * @param options Options passed to the filters. + * @param site Site. If not defined, current site. + * @return {Promise} Promise resolved with true: whether the filter should be applied. + */ + protected shouldFilterBeApplied(filter: CoreFilterFilter, options: CoreFilterFormatTextOptions, site?: CoreSite) + : Promise { + + if (!this.hasHandler(filter.filter, true)) { + return Promise.resolve(false); + } + + return Promise.resolve(this.executeFunctionOnEnabled(filter.filter, 'shouldBeApplied', [options, site])); } } diff --git a/src/core/filter/providers/filter.ts b/src/core/filter/providers/filter.ts index 9e6752d12..ca8e77078 100644 --- a/src/core/filter/providers/filter.ts +++ b/src/core/filter/providers/filter.ts @@ -29,8 +29,6 @@ export class CoreFilterProvider { protected ROOT_CACHE_KEY = 'mmFilter:'; protected logger; - protected FILTERS_NOT_TREATED = ['activitynames', 'censor', 'data', 'emailprotect', 'emoticon', 'glossary', 'tex', 'tidy', - 'urltolink']; constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, @@ -71,9 +69,11 @@ export class CoreFilterProvider { * @param text The text to be formatted. * @param options Formatting options. * @param filters The filters to apply. Required if filter is set to true. + * @param siteId Site ID. If not defined, current site. * @return Promise resolved with the formatted text. */ - formatText(text: string, options?: CoreFilterFormatTextOptions, filters?: CoreFilterFilter[]): Promise { + formatText(text: string, options?: CoreFilterFormatTextOptions, filters?: CoreFilterFilter[], siteId?: string) + : Promise { if (!text || typeof text != 'string') { // No need to do any filters and cleaning. @@ -95,12 +95,10 @@ export class CoreFilterProvider { options.filter = false; } - // @todo: Setup? - let promise: Promise; if (options.filter) { - promise = this.filterDelegate.filterText(text, filters, options); + promise = this.filterDelegate.filterText(text, filters, options, [], siteId); } else { promise = Promise.resolve(text); } @@ -250,17 +248,18 @@ export class CoreFilterProvider { } /** - * Get filters and format text. + * Get the filters in a certain context, performing some checks like the site version. + * It's recommended to use this function instead of canGetAvailableInContext because this function will check if + * it's really needed to call the WS. * - * @param text Text to filter. * @param contextLevel The context level. * @param instanceId Instance ID related to the context. * @param options Options for format text. * @param siteId Site ID. If not defined, current site. - * @return Promise resolved with the formatted text. + * @return Promise resolved with the filters. */ - getFiltersAndFormatText(text: string, contextLevel: string, instanceId: number, options?: CoreFilterFormatTextOptions, - siteId?: string): Promise { + getFilters(contextLevel: string, instanceId: number, options?: CoreFilterFormatTextOptions, siteId?: string) + : Promise { options.contextLevel = contextLevel; options.instanceId = instanceId; @@ -275,7 +274,7 @@ export class CoreFilterProvider { } // Check if site has any filter to treat. - return this.siteHasFiltersToTreat(siteId).then((hasFilters) => { + return this.siteHasFiltersToTreat(options, siteId).then((hasFilters) => { if (hasFilters) { options.filter = true; @@ -286,8 +285,24 @@ export class CoreFilterProvider { }).catch(() => { return []; }); - }).then((filters) => { - return this.formatText(text, options, filters); + }); + } + + /** + * Get filters and format text. + * + * @param text Text to filter. + * @param contextLevel The context level. + * @param instanceId Instance ID related to the context. + * @param options Options for format text. + * @param siteId Site ID. If not defined, current site. + * @return Promise resolved with the formatted text. + */ + getFiltersAndFormatText(text: string, contextLevel: string, instanceId: number, options?: CoreFilterFormatTextOptions, + siteId?: string): Promise { + + return this.getFilters(contextLevel, instanceId, options, siteId).then((filters) => { + return this.formatText(text, options, filters, siteId); }); } @@ -331,29 +346,19 @@ export class CoreFilterProvider { /** * Check if site has available any filter that should be treated by the app. * + * @param options Options passed to the filters. * @param siteId Site ID. If not defined, current site. * @return Promise resolved with boolean: whether it has filters to treat. */ - siteHasFiltersToTreat(siteId?: string): Promise { + siteHasFiltersToTreat(options?: CoreFilterFormatTextOptions, siteId?: string): Promise { + options = options || {}; + return this.sitesProvider.getSite(siteId).then((site) => { // Get filters at site level. return this.getAvailableInContext('system', site.getSiteHomeId(), site.getId()).then((filters) => { - for (let i = 0; i < filters.length; i++) { - const filter = filters[i]; - - if (this.FILTERS_NOT_TREATED.indexOf(filter.filter) != -1) { - continue; - } - - if (this.filterDelegate.hasHandler(filter.filter, true)) { - // There is a filter to treat and is enabled. - return true; - } - } - - return false; + return this.filterDelegate.shouldBeApplied(filters, options, site); }); }); } @@ -390,4 +395,5 @@ export type CoreFilterFormatTextOptions = { singleLine?: boolean; // If true then new lines will be removed (all the text in a single line). shortenLength?: number; // Number of characters to shorten the text. highlight?: string; // Text to highlight. + wsNotFiltered?: boolean; // If true it means the WS didn't filter the text for some reason. }; diff --git a/src/directives/format-text.ts b/src/directives/format-text.ts index e9c78ec04..644812107 100644 --- a/src/directives/format-text.ts +++ b/src/directives/format-text.ts @@ -61,6 +61,7 @@ export class CoreFormatTextDirective implements OnChanges { @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() 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; @@ -382,7 +383,7 @@ export class CoreFormatTextDirective implements OnChanges { clean: this.utils.isTrueOrOne(this.clean), singleLine: this.utils.isTrueOrOne(this.singleLine), highlight: this.highlight, - filter: this.filter + wsNotFiltered: this.utils.isTrueOrOne(this.wsNotFiltered) }; if (this.filter) {