MOBILE-2491 filter: Implement basic filters

main
Dani Palou 2019-09-20 11:18:36 +02:00
parent 26a3b4a9de
commit 88323319bc
27 changed files with 933 additions and 88 deletions

View File

@ -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);
}
}

View File

@ -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.
}
}

View File

@ -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);
}
}

View File

@ -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.
}
}

View File

@ -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);
}
}

View File

@ -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.
}
}

View File

@ -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);
}
}

View File

@ -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.
}
}

View File

@ -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);
}
}

View File

@ -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.
}
}

View File

@ -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 { }

View File

@ -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);
}
}

View File

@ -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.
}
}

View File

@ -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);
}
}

View File

@ -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<string> {
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;
}
}

View File

@ -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);
}
}

View File

@ -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<boolean>} Whether or not the handler is enabled on a site level.
*/
isEnabled(): boolean | Promise<boolean> {
// 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<string> {
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;
});
}
}

View File

@ -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.
}
}

View File

@ -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);
}
}

View File

@ -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.
}
}

View File

@ -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);
}
}

View File

@ -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.
}
}

View File

@ -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);
}
}

View File

@ -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: [

View File

@ -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<string> {
if (!text) {
return Promise.resolve(text);
if (!text || typeof text != 'string') {
return Promise.resolve('');
}
// Wait for filters to be initialized.

View File

@ -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;
}
}

View File

@ -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<string> {
if (!text || typeof text != 'string') {