From 88323319bc7287469c4c395b7fac441a31ee554c Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Fri, 20 Sep 2019 11:18:36 +0200 Subject: [PATCH] MOBILE-2491 filter: Implement basic filters --- .../activitynames/activitynames.module.ts | 34 +++++ .../filter/activitynames/providers/handler.ts | 32 ++++ src/addon/filter/censor/censor.module.ts | 34 +++++ src/addon/filter/censor/providers/handler.ts | 32 ++++ src/addon/filter/data/data.module.ts | 34 +++++ src/addon/filter/data/providers/handler.ts | 32 ++++ .../emailprotect/emailprotect.module.ts | 34 +++++ .../filter/emailprotect/providers/handler.ts | 32 ++++ src/addon/filter/emoticon/emoticon.module.ts | 34 +++++ .../filter/emoticon/providers/handler.ts | 32 ++++ src/addon/filter/filter.module.ts | 47 ++++++ src/addon/filter/glossary/glossary.module.ts | 34 +++++ .../filter/glossary/providers/handler.ts | 32 ++++ .../filter/mediaplugin/mediaplugin.module.ts | 34 +++++ .../filter/mediaplugin/providers/handler.ts | 137 ++++++++++++++++++ .../filter/multilang/multilang.module.ts | 34 +++++ .../filter/multilang/providers/handler.ts | 81 +++++++++++ src/addon/filter/tex/providers/handler.ts | 32 ++++ src/addon/filter/tex/tex.module.ts | 34 +++++ src/addon/filter/tidy/providers/handler.ts | 32 ++++ src/addon/filter/tidy/tidy.module.ts | 34 +++++ .../filter/urltolink/providers/handler.ts | 32 ++++ .../filter/urltolink/urltolink.module.ts | 34 +++++ src/app/app.module.ts | 4 +- src/core/filter/providers/delegate.ts | 4 +- src/directives/format-text.ts | 85 ----------- src/providers/utils/text.ts | 1 + 27 files changed, 933 insertions(+), 88 deletions(-) create mode 100644 src/addon/filter/activitynames/activitynames.module.ts create mode 100644 src/addon/filter/activitynames/providers/handler.ts create mode 100644 src/addon/filter/censor/censor.module.ts create mode 100644 src/addon/filter/censor/providers/handler.ts create mode 100644 src/addon/filter/data/data.module.ts create mode 100644 src/addon/filter/data/providers/handler.ts create mode 100644 src/addon/filter/emailprotect/emailprotect.module.ts create mode 100644 src/addon/filter/emailprotect/providers/handler.ts create mode 100644 src/addon/filter/emoticon/emoticon.module.ts create mode 100644 src/addon/filter/emoticon/providers/handler.ts create mode 100644 src/addon/filter/filter.module.ts create mode 100644 src/addon/filter/glossary/glossary.module.ts create mode 100644 src/addon/filter/glossary/providers/handler.ts create mode 100644 src/addon/filter/mediaplugin/mediaplugin.module.ts create mode 100644 src/addon/filter/mediaplugin/providers/handler.ts create mode 100644 src/addon/filter/multilang/multilang.module.ts create mode 100644 src/addon/filter/multilang/providers/handler.ts create mode 100644 src/addon/filter/tex/providers/handler.ts create mode 100644 src/addon/filter/tex/tex.module.ts create mode 100644 src/addon/filter/tidy/providers/handler.ts create mode 100644 src/addon/filter/tidy/tidy.module.ts create mode 100644 src/addon/filter/urltolink/providers/handler.ts create mode 100644 src/addon/filter/urltolink/urltolink.module.ts diff --git a/src/addon/filter/activitynames/activitynames.module.ts b/src/addon/filter/activitynames/activitynames.module.ts new file mode 100644 index 000000000..b3e5d5da7 --- /dev/null +++ b/src/addon/filter/activitynames/activitynames.module.ts @@ -0,0 +1,34 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { IonicModule } from 'ionic-angular'; +import { CoreFilterDelegate } from '@core/filter/providers/delegate'; +import { AddonFilterActivityNamesHandler } from './providers/handler'; + +@NgModule({ + declarations: [ + ], + imports: [ + IonicModule + ], + providers: [ + AddonFilterActivityNamesHandler + ] +}) +export class AddonFilterActivityNamesModule { + constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterActivityNamesHandler) { + filterDelegate.registerHandler(handler); + } +} diff --git a/src/addon/filter/activitynames/providers/handler.ts b/src/addon/filter/activitynames/providers/handler.ts new file mode 100644 index 000000000..8e55846bb --- /dev/null +++ b/src/addon/filter/activitynames/providers/handler.ts @@ -0,0 +1,32 @@ + +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Injectable } from '@angular/core'; +import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; + +/** + * Handler to support the Activity names filter. + */ +@Injectable() +export class AddonFilterActivityNamesHandler extends CoreFilterDefaultHandler { + name = 'AddonFilterActivityNamesHandler'; + filterName = 'activitynames'; + + constructor() { + super(); + + // This filter is handled by Moodle, nothing to do in the app. + } +} diff --git a/src/addon/filter/censor/censor.module.ts b/src/addon/filter/censor/censor.module.ts new file mode 100644 index 000000000..126a7bfb2 --- /dev/null +++ b/src/addon/filter/censor/censor.module.ts @@ -0,0 +1,34 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { IonicModule } from 'ionic-angular'; +import { CoreFilterDelegate } from '@core/filter/providers/delegate'; +import { AddonFilterCensorHandler } from './providers/handler'; + +@NgModule({ + declarations: [ + ], + imports: [ + IonicModule + ], + providers: [ + AddonFilterCensorHandler + ] +}) +export class AddonFilterCensorModule { + constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterCensorHandler) { + filterDelegate.registerHandler(handler); + } +} diff --git a/src/addon/filter/censor/providers/handler.ts b/src/addon/filter/censor/providers/handler.ts new file mode 100644 index 000000000..874d86ef9 --- /dev/null +++ b/src/addon/filter/censor/providers/handler.ts @@ -0,0 +1,32 @@ + +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Injectable } from '@angular/core'; +import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; + +/** + * Handler to support the Word censorship filter. + */ +@Injectable() +export class AddonFilterCensorHandler extends CoreFilterDefaultHandler { + name = 'AddonFilterCensorHandler'; + filterName = 'censor'; + + constructor() { + super(); + + // This filter is handled by Moodle, nothing to do in the app. + } +} diff --git a/src/addon/filter/data/data.module.ts b/src/addon/filter/data/data.module.ts new file mode 100644 index 000000000..1272618d8 --- /dev/null +++ b/src/addon/filter/data/data.module.ts @@ -0,0 +1,34 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { IonicModule } from 'ionic-angular'; +import { CoreFilterDelegate } from '@core/filter/providers/delegate'; +import { AddonFilterDataHandler } from './providers/handler'; + +@NgModule({ + declarations: [ + ], + imports: [ + IonicModule + ], + providers: [ + AddonFilterDataHandler + ] +}) +export class AddonFilterDataModule { + constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterDataHandler) { + filterDelegate.registerHandler(handler); + } +} diff --git a/src/addon/filter/data/providers/handler.ts b/src/addon/filter/data/providers/handler.ts new file mode 100644 index 000000000..f01cadb1d --- /dev/null +++ b/src/addon/filter/data/providers/handler.ts @@ -0,0 +1,32 @@ + +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Injectable } from '@angular/core'; +import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; + +/** + * Handler to support the Database auto-link filter. + */ +@Injectable() +export class AddonFilterDataHandler extends CoreFilterDefaultHandler { + name = 'AddonFilterDataHandler'; + filterName = 'data'; + + constructor() { + super(); + + // This filter is handled by Moodle, nothing to do in the app. + } +} diff --git a/src/addon/filter/emailprotect/emailprotect.module.ts b/src/addon/filter/emailprotect/emailprotect.module.ts new file mode 100644 index 000000000..d746dfc37 --- /dev/null +++ b/src/addon/filter/emailprotect/emailprotect.module.ts @@ -0,0 +1,34 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { IonicModule } from 'ionic-angular'; +import { CoreFilterDelegate } from '@core/filter/providers/delegate'; +import { AddonFilterEmailProtectHandler } from './providers/handler'; + +@NgModule({ + declarations: [ + ], + imports: [ + IonicModule + ], + providers: [ + AddonFilterEmailProtectHandler + ] +}) +export class AddonFilterEmailProtectModule { + constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterEmailProtectHandler) { + filterDelegate.registerHandler(handler); + } +} diff --git a/src/addon/filter/emailprotect/providers/handler.ts b/src/addon/filter/emailprotect/providers/handler.ts new file mode 100644 index 000000000..e7971386c --- /dev/null +++ b/src/addon/filter/emailprotect/providers/handler.ts @@ -0,0 +1,32 @@ + +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Injectable } from '@angular/core'; +import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; + +/** + * Handler to support the Email protection filter. + */ +@Injectable() +export class AddonFilterEmailProtectHandler extends CoreFilterDefaultHandler { + name = 'AddonFilterEmailProtectHandler'; + filterName = 'emailprotect'; + + constructor() { + super(); + + // This filter is handled by Moodle, nothing to do in the app. + } +} diff --git a/src/addon/filter/emoticon/emoticon.module.ts b/src/addon/filter/emoticon/emoticon.module.ts new file mode 100644 index 000000000..5237286f9 --- /dev/null +++ b/src/addon/filter/emoticon/emoticon.module.ts @@ -0,0 +1,34 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { IonicModule } from 'ionic-angular'; +import { CoreFilterDelegate } from '@core/filter/providers/delegate'; +import { AddonFilterEmoticonHandler } from './providers/handler'; + +@NgModule({ + declarations: [ + ], + imports: [ + IonicModule + ], + providers: [ + AddonFilterEmoticonHandler + ] +}) +export class AddonFilterEmoticonModule { + constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterEmoticonHandler) { + filterDelegate.registerHandler(handler); + } +} diff --git a/src/addon/filter/emoticon/providers/handler.ts b/src/addon/filter/emoticon/providers/handler.ts new file mode 100644 index 000000000..39c2ffe33 --- /dev/null +++ b/src/addon/filter/emoticon/providers/handler.ts @@ -0,0 +1,32 @@ + +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Injectable } from '@angular/core'; +import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; + +/** + * Handler to support the Emoticon filter. + */ +@Injectable() +export class AddonFilterEmoticonHandler extends CoreFilterDefaultHandler { + name = 'AddonFilterEmoticonHandler'; + filterName = 'emoticon'; + + constructor() { + super(); + + // This filter is handled by Moodle, nothing to do in the app. + } +} diff --git a/src/addon/filter/filter.module.ts b/src/addon/filter/filter.module.ts new file mode 100644 index 000000000..b20447e06 --- /dev/null +++ b/src/addon/filter/filter.module.ts @@ -0,0 +1,47 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { AddonFilterActivityNamesModule } from './activitynames/activitynames.module'; +import { AddonFilterCensorModule } from './censor/censor.module'; +import { AddonFilterDataModule } from './data/data.module'; +import { AddonFilterEmailProtectModule } from './emailprotect/emailprotect.module'; +import { AddonFilterEmoticonModule } from './emoticon/emoticon.module'; +import { AddonFilterGlossaryModule } from './glossary/glossary.module'; +import { AddonFilterMediaPluginModule } from './mediaplugin/mediaplugin.module'; +import { AddonFilterMultilangModule } from './multilang/multilang.module'; +import { AddonFilterTexModule } from './tex/tex.module'; +import { AddonFilterTidyModule } from './tidy/tidy.module'; +import { AddonFilterUrlToLinkModule } from './urltolink/urltolink.module'; + +@NgModule({ + declarations: [], + imports: [ + AddonFilterActivityNamesModule, + AddonFilterCensorModule, + AddonFilterDataModule, + AddonFilterEmailProtectModule, + AddonFilterEmoticonModule, + AddonFilterGlossaryModule, + AddonFilterMediaPluginModule, + AddonFilterMultilangModule, + AddonFilterTexModule, + AddonFilterTidyModule, + AddonFilterUrlToLinkModule + ], + providers: [ + ], + exports: [] +}) +export class AddonFilterModule { } diff --git a/src/addon/filter/glossary/glossary.module.ts b/src/addon/filter/glossary/glossary.module.ts new file mode 100644 index 000000000..337bffbbc --- /dev/null +++ b/src/addon/filter/glossary/glossary.module.ts @@ -0,0 +1,34 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { IonicModule } from 'ionic-angular'; +import { CoreFilterDelegate } from '@core/filter/providers/delegate'; +import { AddonFilterGlossaryHandler } from './providers/handler'; + +@NgModule({ + declarations: [ + ], + imports: [ + IonicModule + ], + providers: [ + AddonFilterGlossaryHandler + ] +}) +export class AddonFilterGlossaryModule { + constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterGlossaryHandler) { + filterDelegate.registerHandler(handler); + } +} diff --git a/src/addon/filter/glossary/providers/handler.ts b/src/addon/filter/glossary/providers/handler.ts new file mode 100644 index 000000000..f7e38d553 --- /dev/null +++ b/src/addon/filter/glossary/providers/handler.ts @@ -0,0 +1,32 @@ + +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Injectable } from '@angular/core'; +import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; + +/** + * Handler to support the Glossary auto-link filter. + */ +@Injectable() +export class AddonFilterGlossaryHandler extends CoreFilterDefaultHandler { + name = 'AddonFilterGlossaryHandler'; + filterName = 'glossary'; + + constructor() { + super(); + + // This filter is handled by Moodle, nothing to do in the app. + } +} diff --git a/src/addon/filter/mediaplugin/mediaplugin.module.ts b/src/addon/filter/mediaplugin/mediaplugin.module.ts new file mode 100644 index 000000000..2ef135ddd --- /dev/null +++ b/src/addon/filter/mediaplugin/mediaplugin.module.ts @@ -0,0 +1,34 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { IonicModule } from 'ionic-angular'; +import { CoreFilterDelegate } from '@core/filter/providers/delegate'; +import { AddonFilterMediaPluginHandler } from './providers/handler'; + +@NgModule({ + declarations: [ + ], + imports: [ + IonicModule + ], + providers: [ + AddonFilterMediaPluginHandler + ] +}) +export class AddonFilterMediaPluginModule { + constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterMediaPluginHandler) { + filterDelegate.registerHandler(handler); + } +} diff --git a/src/addon/filter/mediaplugin/providers/handler.ts b/src/addon/filter/mediaplugin/providers/handler.ts new file mode 100644 index 000000000..29da3de94 --- /dev/null +++ b/src/addon/filter/mediaplugin/providers/handler.ts @@ -0,0 +1,137 @@ + +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Injectable } from '@angular/core'; +import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; +import { CoreFilterFilter } from '@core/filter/providers/filter'; +import { CoreTextUtilsProvider } from '@providers/utils/text'; + +/** + * Handler to support the Multimedia filter. + */ +@Injectable() +export class AddonFilterMediaPluginHandler extends CoreFilterDefaultHandler { + name = 'AddonFilterMediaPluginHandler'; + filterName = 'mediaplugin'; + + constructor(private textUtils: CoreTextUtilsProvider) { + super(); + } + + /** + * Filter some text. + * + * @param text The text to filter. + * @param filter The filter. + * @param options Options passed to the filters. + * @return Filtered text (or promise resolved with the filtered text). + */ + filter(text: string, filter: CoreFilterFilter, options: any): string | Promise { + + const div = document.createElement('div'); + div.innerHTML = text; + + const videos = Array.from(div.querySelectorAll('video')); + + videos.forEach((video) => { + this.treatVideoFilters(video); + }); + + return div.innerHTML; + } + + /** + * Treat video filters. Currently only treating youtube video using video JS. + * + * @param el Video element. + * @param navCtrl NavController to use. + */ + protected treatVideoFilters(video: HTMLElement): 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); + } + + /** + * Parse a YouTube URL. + * Based on Youtube.parseUrl from Moodle media/player/videojs/amd/src/Youtube-lazy.js + * + * @param url URL of the video. + * @return Data 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/addon/filter/multilang/multilang.module.ts b/src/addon/filter/multilang/multilang.module.ts new file mode 100644 index 000000000..149cdfd0c --- /dev/null +++ b/src/addon/filter/multilang/multilang.module.ts @@ -0,0 +1,34 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { IonicModule } from 'ionic-angular'; +import { CoreFilterDelegate } from '@core/filter/providers/delegate'; +import { AddonFilterMultilangHandler } from './providers/handler'; + +@NgModule({ + declarations: [ + ], + imports: [ + IonicModule + ], + providers: [ + AddonFilterMultilangHandler + ] +}) +export class AddonFilterMultilangModule { + constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterMultilangHandler) { + filterDelegate.registerHandler(handler); + } +} diff --git a/src/addon/filter/multilang/providers/handler.ts b/src/addon/filter/multilang/providers/handler.ts new file mode 100644 index 000000000..e689d9769 --- /dev/null +++ b/src/addon/filter/multilang/providers/handler.ts @@ -0,0 +1,81 @@ + +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Injectable } from '@angular/core'; +import { CoreSitesProvider } from '@providers/sites'; +import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; +import { CoreFilterFilter } from '@core/filter/providers/filter'; +import { CoreLangProvider } from '@providers/lang'; + +/** + * Handler to support the Multilang filter. + */ +@Injectable() +export class AddonFilterMultilangHandler extends CoreFilterDefaultHandler { + name = 'AddonFilterMultilangHandler'; + filterName = 'multilang'; + + constructor(private langProvider: CoreLangProvider, + private sitesProvider: CoreSitesProvider) { + 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. + * @return Filtered text (or promise resolved with the filtered text). + */ + filter(text: string, filter: CoreFilterFilter, options: any): 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'); + + 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; + }); + } +} diff --git a/src/addon/filter/tex/providers/handler.ts b/src/addon/filter/tex/providers/handler.ts new file mode 100644 index 000000000..a02e8e7c7 --- /dev/null +++ b/src/addon/filter/tex/providers/handler.ts @@ -0,0 +1,32 @@ + +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Injectable } from '@angular/core'; +import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; + +/** + * Handler to support the TeX notation filter. + */ +@Injectable() +export class AddonFilterTexHandler extends CoreFilterDefaultHandler { + name = 'AddonFilterTexHandler'; + filterName = 'tex'; + + constructor() { + super(); + + // This filter is handled by Moodle, nothing to do in the app. + } +} diff --git a/src/addon/filter/tex/tex.module.ts b/src/addon/filter/tex/tex.module.ts new file mode 100644 index 000000000..21084238b --- /dev/null +++ b/src/addon/filter/tex/tex.module.ts @@ -0,0 +1,34 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { IonicModule } from 'ionic-angular'; +import { CoreFilterDelegate } from '@core/filter/providers/delegate'; +import { AddonFilterTexHandler } from './providers/handler'; + +@NgModule({ + declarations: [ + ], + imports: [ + IonicModule + ], + providers: [ + AddonFilterTexHandler + ] +}) +export class AddonFilterTexModule { + constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterTexHandler) { + filterDelegate.registerHandler(handler); + } +} diff --git a/src/addon/filter/tidy/providers/handler.ts b/src/addon/filter/tidy/providers/handler.ts new file mode 100644 index 000000000..e0fff232d --- /dev/null +++ b/src/addon/filter/tidy/providers/handler.ts @@ -0,0 +1,32 @@ + +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Injectable } from '@angular/core'; +import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; + +/** + * Handler to support the HTML tidy filter. + */ +@Injectable() +export class AddonFilterTidyHandler extends CoreFilterDefaultHandler { + name = 'AddonFilterTidyHandler'; + filterName = 'tidy'; + + constructor() { + super(); + + // This filter is handled by Moodle, nothing to do in the app. + } +} diff --git a/src/addon/filter/tidy/tidy.module.ts b/src/addon/filter/tidy/tidy.module.ts new file mode 100644 index 000000000..ab0b43098 --- /dev/null +++ b/src/addon/filter/tidy/tidy.module.ts @@ -0,0 +1,34 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { IonicModule } from 'ionic-angular'; +import { CoreFilterDelegate } from '@core/filter/providers/delegate'; +import { AddonFilterTidyHandler } from './providers/handler'; + +@NgModule({ + declarations: [ + ], + imports: [ + IonicModule + ], + providers: [ + AddonFilterTidyHandler + ] +}) +export class AddonFilterTidyModule { + constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterTidyHandler) { + filterDelegate.registerHandler(handler); + } +} diff --git a/src/addon/filter/urltolink/providers/handler.ts b/src/addon/filter/urltolink/providers/handler.ts new file mode 100644 index 000000000..d23c392b3 --- /dev/null +++ b/src/addon/filter/urltolink/providers/handler.ts @@ -0,0 +1,32 @@ + +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Injectable } from '@angular/core'; +import { CoreFilterDefaultHandler } from '@core/filter/providers/default-filter'; + +/** + * Handler to support the URL to link and images filter. + */ +@Injectable() +export class AddonFilterUrlToLinkHandler extends CoreFilterDefaultHandler { + name = 'AddonFilterUrlToLinkHandler'; + filterName = 'urltolink'; + + constructor() { + super(); + + // This filter is handled by Moodle, nothing to do in the app. + } +} diff --git a/src/addon/filter/urltolink/urltolink.module.ts b/src/addon/filter/urltolink/urltolink.module.ts new file mode 100644 index 000000000..afbdbf15c --- /dev/null +++ b/src/addon/filter/urltolink/urltolink.module.ts @@ -0,0 +1,34 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { IonicModule } from 'ionic-angular'; +import { CoreFilterDelegate } from '@core/filter/providers/delegate'; +import { AddonFilterUrlToLinkHandler } from './providers/handler'; + +@NgModule({ + declarations: [ + ], + imports: [ + IonicModule + ], + providers: [ + AddonFilterUrlToLinkHandler + ] +}) +export class AddonFilterUrlToLinkModule { + constructor(filterDelegate: CoreFilterDelegate, handler: AddonFilterUrlToLinkHandler) { + filterDelegate.registerHandler(handler); + } +} diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 740759df7..6f9966fa8 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -148,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 { @@ -290,7 +291,8 @@ export const WP_PROVIDER: any = null; AddonRemoteThemesModule, AddonQbehaviourModule, AddonQtypeModule, - AddonStorageManagerModule + AddonStorageManagerModule, + AddonFilterModule ], bootstrap: [IonicApp], entryComponents: [ diff --git a/src/core/filter/providers/delegate.ts b/src/core/filter/providers/delegate.ts index 4d5913c6a..4fd742262 100644 --- a/src/core/filter/providers/delegate.ts +++ b/src/core/filter/providers/delegate.ts @@ -74,8 +74,8 @@ export class CoreFilterDelegate extends CoreDelegate { * @return Promise resolved with the filtered text. */ filterText(text: string, filters: CoreFilterFilter[], options?: any, skipFilters?: string[]): Promise { - if (!text) { - return Promise.resolve(text); + if (!text || typeof text != 'string') { + return Promise.resolve(''); } // Wait for filters to be initialized. diff --git a/src/directives/format-text.ts b/src/directives/format-text.ts index a723f2116..88fb67c20 100644 --- a/src/directives/format-text.ts +++ b/src/directives/format-text.ts @@ -425,7 +425,6 @@ export class CoreFormatTextDirective implements OnChanges { }); videos.forEach((video) => { - this.treatVideoFilters(video, navCtrl); this.treatMedia(video); }); @@ -549,40 +548,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 +658,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/utils/text.ts b/src/providers/utils/text.ts index 9a6b7f005..262662da6 100644 --- a/src/providers/utils/text.ts +++ b/src/providers/utils/text.ts @@ -732,6 +732,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') {