From 772864245e42b80f368377d978d4b1d293865dfe Mon Sep 17 00:00:00 2001 From: Alfonso Salces Date: Fri, 31 Mar 2023 14:42:01 +0200 Subject: [PATCH] MOBILE-4292 multilang2: Create new multilang filter --- src/addons/filter/filter.module.ts | 2 + .../filter/multilang2/multilang2.module.ts | 29 +++++ .../services/handlers/multilang2.ts | 104 ++++++++++++++++++ .../user-profile-field/user-profile-field.ts | 7 ++ src/core/services/utils/dom.ts | 2 + 5 files changed, 144 insertions(+) create mode 100644 src/addons/filter/multilang2/multilang2.module.ts create mode 100644 src/addons/filter/multilang2/services/handlers/multilang2.ts diff --git a/src/addons/filter/filter.module.ts b/src/addons/filter/filter.module.ts index 308b41ec0..4fe2e84f4 100644 --- a/src/addons/filter/filter.module.ts +++ b/src/addons/filter/filter.module.ts @@ -25,6 +25,7 @@ import { AddonFilterGlossaryModule } from './glossary/glossary.module'; import { AddonFilterMathJaxLoaderModule } from './mathjaxloader/mathjaxloader.module'; import { AddonFilterMediaPluginModule } from './mediaplugin/mediaplugin.module'; import { AddonFilterMultilangModule } from './multilang/multilang.module'; +import { AddonFilterMultilang2Module } from './multilang2/multilang2.module'; import { AddonFilterTexModule } from './tex/tex.module'; import { AddonFilterTidyModule } from './tidy/tidy.module'; import { AddonFilterUrlToLinkModule } from './urltolink/urltolink.module'; @@ -42,6 +43,7 @@ import { AddonFilterUrlToLinkModule } from './urltolink/urltolink.module'; AddonFilterMathJaxLoaderModule, AddonFilterMediaPluginModule, AddonFilterMultilangModule, + AddonFilterMultilang2Module, AddonFilterTexModule, AddonFilterTidyModule, AddonFilterUrlToLinkModule, diff --git a/src/addons/filter/multilang2/multilang2.module.ts b/src/addons/filter/multilang2/multilang2.module.ts new file mode 100644 index 000000000..50e799063 --- /dev/null +++ b/src/addons/filter/multilang2/multilang2.module.ts @@ -0,0 +1,29 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { APP_INITIALIZER, NgModule } from '@angular/core'; + +import { CoreFilterDelegate } from '@features/filter/services/filter-delegate'; +import { AddonFilterMultilang2Handler } from './services/handlers/multilang2'; + +@NgModule({ + providers: [ + { + provide: APP_INITIALIZER, + multi: true, + useValue: () => CoreFilterDelegate.registerHandler(AddonFilterMultilang2Handler.instance), + }, + ], +}) +export class AddonFilterMultilang2Module {} diff --git a/src/addons/filter/multilang2/services/handlers/multilang2.ts b/src/addons/filter/multilang2/services/handlers/multilang2.ts new file mode 100644 index 000000000..1060b9f6d --- /dev/null +++ b/src/addons/filter/multilang2/services/handlers/multilang2.ts @@ -0,0 +1,104 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Injectable } from '@angular/core'; + +import { CoreLang } from '@services/lang'; +import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; +import { makeSingleton } from '@singletons'; + +/** + * Handler to support the Multilang filter. + */ +@Injectable({ providedIn: 'root' }) +export class AddonFilterMultilang2HandlerService extends CoreFilterDefaultHandler { + + name = 'AddonFilterMultilang2Handler'; + filterName = 'multilang2'; + replacementDone = false; + + /** + * This function filters the received text based on the language + * tags embedded in the text, and the current user language or + * 'other', if present. + * + * @param text The text to filter. + * @returns string The filtered text for this multilang block. + */ + async filter(text: string): Promise { + if (text.indexOf('mlang') === -1) { + return text; + } + + const currentLang = await CoreLang.getCurrentLanguage(); + this.replacementDone = false; + const parentLanguage = CoreLang.getParentLanguage(currentLang); + + const search = /{\s*mlang\s+((?:[a-z0-9_-]+)(?:\s*,\s*[a-z0-9_-]+\s*)*)\s*}(.*?){\s*mlang\s*}/gim; + const result = text.replace( + search, + (subString, language, content) => this.replaceLangs(currentLang, [subString, language, content], parentLanguage), + ); + + if (result === null) { + return text; // Error during regex processing, keep original text. + } + + if (this.replacementDone) { + return result; + } + + const result2 = text.replace( + search, + (subString, language, content) => this.replaceLangs('other', [subString, language, content], parentLanguage), + ); + + return result2 ?? text; + } + + /** + * This function filters the current block of multilang tag. If + * any of the tag languages (or their parent languages) match the + * specified filtering language, it returns the text of the + * block. Otherwise it returns an empty string. + * + * @param replaceLang A string that specifies the language used to filter the matches. + * @param langBlock An array containing the matching captured pieces of the + * regular expression. They are the languages of the tag, and the text associated with those languages. + * @param parentLanguage A string that contains the parent language. + * + * @returns replaced string. + */ + protected replaceLangs(replaceLang: string, langBlock: string[], parentLanguage: string | undefined): string { + // Normalize languages. + const blockLangs = (langBlock[1] ?? '').replace(/ /g, '').replace(/_/g, '-').toLowerCase().split(','); + const blockText = langBlock[2] ?? ''; + + for (const blockLang of blockLangs) { + /* We don't check for empty values of blockLang as they simply don't + * match any language and they don't produce any errors or warnings. + */ + if (blockLang === replaceLang || parentLanguage === blockLang) { + this.replacementDone = true; + + return blockText; + } + } + + return ''; + } + +} + +export const AddonFilterMultilang2Handler = makeSingleton(AddonFilterMultilang2HandlerService); diff --git a/src/core/features/user/components/user-profile-field/user-profile-field.ts b/src/core/features/user/components/user-profile-field/user-profile-field.ts index e6e9ce874..21d4de6cd 100644 --- a/src/core/features/user/components/user-profile-field/user-profile-field.ts +++ b/src/core/features/user/components/user-profile-field/user-profile-field.ts @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { AddonFilterMultilangHandler } from '@addons/filter/multilang/services/handlers/multilang'; +import { AddonFilterMultilang2Handler } from '@addons/filter/multilang2/services/handlers/multilang2'; import { Component, Input, OnInit, Type } from '@angular/core'; import { FormGroup } from '@angular/forms'; @@ -51,6 +53,11 @@ export class CoreUserProfileFieldComponent implements OnInit { this.componentClass = await CoreUserProfileFieldDelegate.getComponent(this.field, this.signup); + if ('param1' in this.field && this.field.param1) { + this.field.param1 = await AddonFilterMultilangHandler.filter( this.field.param1); + this.field.param1 = await AddonFilterMultilang2Handler.filter( this.field.param1); + } + this.data.field = this.field; this.data.edit = CoreUtils.isTrueOrOne(this.edit); if (this.edit) { diff --git a/src/core/services/utils/dom.ts b/src/core/services/utils/dom.ts index 57f430892..729a3ab30 100644 --- a/src/core/services/utils/dom.ts +++ b/src/core/services/utils/dom.ts @@ -58,6 +58,7 @@ import { CoreSiteError } from '@classes/errors/siteerror'; import { CoreUserSupport } from '@features/user/services/support'; import { CoreErrorInfoComponent } from '@components/error-info/error-info'; import { CorePlatform } from '@services/platform'; +import { AddonFilterMultilang2Handler } from '@addons/filter/multilang2/services/handlers/multilang2'; /* * "Utils" service with helper functions for UI, DOM elements and HTML code. @@ -1170,6 +1171,7 @@ export class CoreDomUtilsProvider { if (hasHTMLTags && !CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('3.7')) { // Treat multilang. options.message = await AddonFilterMultilangHandler.filter( options.message); + options.message = await AddonFilterMultilang2Handler.filter( options.message); } const alertId = Md5.hashAsciiStr((options.header || '') + '#' + (options.message || ''));