MOBILE-3620 filter: Implement filters addons

main
Dani Palou 2020-12-09 12:59:45 +01:00
parent 487933cdc7
commit aa60d8eaeb
31 changed files with 1668 additions and 1 deletions

View File

@ -15,10 +15,12 @@
import { NgModule } from '@angular/core';
import { AddonPrivateFilesModule } from './privatefiles/privatefiles.module';
import { AddonFilterModule } from './filter/filter.module';
@NgModule({
imports: [
AddonPrivateFilesModule,
AddonFilterModule,
],
})
export class AddonsModule {}

View File

@ -0,0 +1,34 @@
// (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 { AddonFilterActivityNamesHandler } from './services/handlers/activitynames';
@NgModule({
declarations: [
],
imports: [
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [AddonFilterActivityNamesHandler],
useFactory: (handler: AddonFilterActivityNamesHandler) => () => CoreFilterDelegate.instance.registerHandler(handler),
},
],
})
export class AddonFilterActivityNamesModule {}

View File

@ -0,0 +1,43 @@
// (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter';
import { CoreFilterFormatTextOptions } from '@features/filter/services/filter';
import { CoreSite } from '@classes/site';
/**
* Handler to support the Activity names filter.
*/
@Injectable({ providedIn: 'root' })
export class AddonFilterActivityNamesHandler extends CoreFilterDefaultHandler {
name = 'AddonFilterActivityNamesHandler';
filterName = 'activitynames';
/**
* 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.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean {
// This filter is handled by Moodle, nothing to do in the app.
return false;
}
}

View File

@ -0,0 +1,34 @@
// (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 { AddonFilterAlgebraHandler } from './services/handlers/algebra';
@NgModule({
declarations: [
],
imports: [
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [AddonFilterAlgebraHandler],
useFactory: (handler: AddonFilterAlgebraHandler) => () => CoreFilterDelegate.instance.registerHandler(handler),
},
],
})
export class AddonFilterAlgebraModule {}

View File

@ -0,0 +1,43 @@
// (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter';
import { CoreFilterFormatTextOptions } from '@features/filter/services/filter';
import { CoreSite } from '@classes/site';
/**
* Handler to support the Algebra notation filter.
*/
@Injectable({ providedIn: 'root' })
export class AddonFilterAlgebraHandler extends CoreFilterDefaultHandler {
name = 'AddonFilterAlgebraHandler';
filterName = 'algebra';
/**
* 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.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean {
// This filter is handled by Moodle, nothing to do in the app.
return false;
}
}

View File

@ -0,0 +1,34 @@
// (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 { AddonFilterCensorHandler } from './services/handlers/censor';
@NgModule({
declarations: [
],
imports: [
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [AddonFilterCensorHandler],
useFactory: (handler: AddonFilterCensorHandler) => () => CoreFilterDelegate.instance.registerHandler(handler),
},
],
})
export class AddonFilterCensorModule {}

View File

@ -0,0 +1,43 @@
// (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter';
import { CoreFilterFormatTextOptions } from '@features/filter/services/filter';
import { CoreSite } from '@classes/site';
/**
* Handler to support the Word censorship filter.
*/
@Injectable({ providedIn: 'root' })
export class AddonFilterCensorHandler extends CoreFilterDefaultHandler {
name = 'AddonFilterCensorHandler';
filterName = 'censor';
/**
* 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.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean {
// This filter is handled by Moodle, nothing to do in the app.
return false;
}
}

View File

@ -0,0 +1,34 @@
// (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 { AddonFilterDataHandler } from './services/handlers/data';
@NgModule({
declarations: [
],
imports: [
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [AddonFilterDataHandler],
useFactory: (handler: AddonFilterDataHandler) => () => CoreFilterDelegate.instance.registerHandler(handler),
},
],
})
export class AddonFilterDataModule {}

View File

@ -0,0 +1,43 @@
// (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter';
import { CoreFilterFormatTextOptions } from '@features/filter/services/filter';
import { CoreSite } from '@classes/site';
/**
* Handler to support the Database auto-link filter.
*/
@Injectable({ providedIn: 'root' })
export class AddonFilterDataHandler extends CoreFilterDefaultHandler {
name = 'AddonFilterDataHandler';
filterName = 'data';
/**
* 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.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean {
// This filter is handled by Moodle, nothing to do in the app.
return false;
}
}

View File

@ -0,0 +1,34 @@
// (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 { AddonFilterDisplayH5PHandler } from './services/handlers/displayh5p';
@NgModule({
declarations: [
],
imports: [
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [AddonFilterDisplayH5PHandler],
useFactory: (handler: AddonFilterDisplayH5PHandler) => () => CoreFilterDelegate.instance.registerHandler(handler),
},
],
})
export class AddonFilterDisplayH5PModule {}

View File

@ -0,0 +1,110 @@
// (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, ViewContainerRef, ComponentFactoryResolver } from '@angular/core';
import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter';
import { CoreFilterFilter, CoreFilterFormatTextOptions } from '@features/filter/services/filter';
// @todo import { CoreH5PPlayerComponent } from '@core/h5p/components/h5p-player/h5p-player';
/**
* Handler to support the Display H5P filter.
*/
@Injectable({ providedIn: 'root' })
export class AddonFilterDisplayH5PHandler extends CoreFilterDefaultHandler {
name = 'AddonFilterDisplayH5PHandler';
filterName = 'displayh5p';
protected template = document.createElement('template'); // A template element to convert HTML to element.
constructor(protected factoryResolver: ComponentFactoryResolver) {
super();
}
/**
* 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, // eslint-disable-line @typescript-eslint/no-unused-vars
options: CoreFilterFormatTextOptions, // eslint-disable-line @typescript-eslint/no-unused-vars
siteId?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
): string | Promise<string> {
this.template.innerHTML = text;
const h5pIframes = <HTMLIFrameElement[]> Array.from(this.template.content.querySelectorAll('iframe.h5p-iframe'));
// Replace all iframes with an empty div that will be treated in handleHtml.
h5pIframes.forEach((iframe) => {
const placeholder = document.createElement('div');
placeholder.classList.add('core-h5p-tmp-placeholder');
placeholder.setAttribute('data-player-src', iframe.src);
iframe.parentElement?.replaceChild(placeholder, iframe);
});
return this.template.innerHTML;
}
/**
* Handle HTML. This function is called after "filter", and it will receive an HTMLElement containing the text that was
* filtered.
*
* @param container The HTML container to handle.
* @param filter The filter.
* @param options Options passed to the filters.
* @param viewContainerRef The ViewContainerRef where the container is.
* @param component Component.
* @param componentId Component ID.
* @param siteId Site ID. If not defined, current site.
* @return If async, promise resolved when done.
*/
handleHtml(
container: HTMLElement, // eslint-disable-line @typescript-eslint/no-unused-vars
filter: CoreFilterFilter, // eslint-disable-line @typescript-eslint/no-unused-vars
options: CoreFilterFormatTextOptions, // eslint-disable-line @typescript-eslint/no-unused-vars
viewContainerRef: ViewContainerRef, // eslint-disable-line @typescript-eslint/no-unused-vars
component?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
componentId?: string | number, // eslint-disable-line @typescript-eslint/no-unused-vars
siteId?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
): void | Promise<void> {
// @todo
// const placeholders = <HTMLElement[]> Array.from(container.querySelectorAll('div.core-h5p-tmp-placeholder'));
// placeholders.forEach((placeholder) => {
// const url = placeholder.getAttribute('data-player-src');
// Create the component to display the player.
// const factory = this.factoryResolver.resolveComponentFactory(CoreH5PPlayerComponent);
// const componentRef = viewContainerRef.createComponent<CoreH5PPlayerComponent>(factory);
// componentRef.instance.src = url;
// componentRef.instance.component = component;
// componentRef.instance.componentId = componentId;
// // Move the component to its right position.
// placeholder.parentElement?.replaceChild(componentRef.instance.elementRef.nativeElement, placeholder);
// });
}
}

View File

@ -0,0 +1,34 @@
// (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 { AddonFilterEmailProtectHandler } from './services/handlers/emailprotect';
@NgModule({
declarations: [
],
imports: [
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [AddonFilterEmailProtectHandler],
useFactory: (handler: AddonFilterEmailProtectHandler) => () => CoreFilterDelegate.instance.registerHandler(handler),
},
],
})
export class AddonFilterEmailProtectModule {}

View File

@ -0,0 +1,43 @@
// (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter';
import { CoreFilterFormatTextOptions } from '@features/filter/services/filter';
import { CoreSite } from '@classes/site';
/**
* Handler to support the Email protection filter.
*/
@Injectable({ providedIn: 'root' })
export class AddonFilterEmailProtectHandler extends CoreFilterDefaultHandler {
name = 'AddonFilterEmailProtectHandler';
filterName = 'emailprotect';
/**
* 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.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean {
// This filter is handled by Moodle, nothing to do in the app.
return false;
}
}

View File

@ -0,0 +1,34 @@
// (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 { AddonFilterEmoticonHandler } from './services/handlers/emoticon';
@NgModule({
declarations: [
],
imports: [
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [AddonFilterEmoticonHandler],
useFactory: (handler: AddonFilterEmoticonHandler) => () => CoreFilterDelegate.instance.registerHandler(handler),
},
],
})
export class AddonFilterEmoticonModule {}

View File

@ -0,0 +1,43 @@
// (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter';
import { CoreFilterFormatTextOptions } from '@features/filter/services/filter';
import { CoreSite } from '@classes/site';
/**
* Handler to support the Emoticon filter.
*/
@Injectable({ providedIn: 'root' })
export class AddonFilterEmoticonHandler extends CoreFilterDefaultHandler {
name = 'AddonFilterEmoticonHandler';
filterName = 'emoticon';
/**
* 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.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean {
// This filter is handled by Moodle, nothing to do in the app.
return false;
}
}

View File

@ -0,0 +1,53 @@
// (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 { NgModule } from '@angular/core';
import { AddonFilterActivityNamesModule } from './activitynames/activitynames.module';
import { AddonFilterAlgebraModule } from './algebra/algebra.module';
import { AddonFilterCensorModule } from './censor/censor.module';
import { AddonFilterDataModule } from './data/data.module';
import { AddonFilterDisplayH5PModule } from './displayh5p/displayh5p.module';
import { AddonFilterEmailProtectModule } from './emailprotect/emailprotect.module';
import { AddonFilterEmoticonModule } from './emoticon/emoticon.module';
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 { AddonFilterTexModule } from './tex/tex.module';
import { AddonFilterTidyModule } from './tidy/tidy.module';
import { AddonFilterUrlToLinkModule } from './urltolink/urltolink.module';
@NgModule({
declarations: [],
imports: [
AddonFilterActivityNamesModule,
AddonFilterAlgebraModule,
AddonFilterCensorModule,
AddonFilterDataModule,
AddonFilterDisplayH5PModule,
AddonFilterEmailProtectModule,
AddonFilterEmoticonModule,
AddonFilterGlossaryModule,
AddonFilterMathJaxLoaderModule,
AddonFilterMediaPluginModule,
AddonFilterMultilangModule,
AddonFilterTexModule,
AddonFilterTidyModule,
AddonFilterUrlToLinkModule,
],
providers: [],
exports: [],
})
export class AddonFilterModule { }

View File

@ -0,0 +1,34 @@
// (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 { AddonFilterGlossaryHandler } from './services/handlers/glossary';
@NgModule({
declarations: [
],
imports: [
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [AddonFilterGlossaryHandler],
useFactory: (handler: AddonFilterGlossaryHandler) => () => CoreFilterDelegate.instance.registerHandler(handler),
},
],
})
export class AddonFilterGlossaryModule {}

View File

@ -0,0 +1,43 @@
// (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter';
import { CoreFilterFormatTextOptions } from '@features/filter/services/filter';
import { CoreSite } from '@classes/site';
/**
* Handler to support the Glossary auto-link filter.
*/
@Injectable({ providedIn: 'root' })
export class AddonFilterGlossaryHandler extends CoreFilterDefaultHandler {
name = 'AddonFilterGlossaryHandler';
filterName = 'glossary';
/**
* 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.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean {
// This filter is handled by Moodle, nothing to do in the app.
return false;
}
}

View File

@ -0,0 +1,38 @@
// (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 { AddonFilterMathJaxLoaderHandler } from './services/handlers/mathjaxloader';
@NgModule({
declarations: [
],
imports: [
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [AddonFilterMathJaxLoaderHandler],
useFactory: (handler: AddonFilterMathJaxLoaderHandler) => async () => {
CoreFilterDelegate.instance.registerHandler(handler);
await handler.initialize();
},
},
],
})
export class AddonFilterMathJaxLoaderModule {}

View File

@ -0,0 +1,410 @@
// (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, ViewContainerRef } from '@angular/core';
import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter';
import { CoreFilterFilter, CoreFilterFormatTextOptions } from '@features/filter/services/filter';
import { CoreLang } from '@services/lang';
import { CoreSites } from '@services/sites';
import { CoreTextUtils } from '@services/utils/text';
import { CoreUtils } from '@services/utils/utils';
import { CoreEvents } from '@singletons/events';
import { CoreSite } from '@classes/site';
/**
* Handler to support the MathJax filter.
*/
@Injectable({ providedIn: 'root' })
export class AddonFilterMathJaxLoaderHandler extends CoreFilterDefaultHandler {
name = 'AddonFilterMathJaxLoaderHandler';
filterName = 'mathjaxloader';
// Default values for MathJax config for sites where we cannot retrieve it.
protected readonly DEFAULT_URL = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js';
protected readonly DEFAULT_CONFIG = `
MathJax.Hub.Config({
extensions: [
"Safe.js",
"tex2jax.js",
"mml2jax.js",
"MathEvents.js",
"MathZoom.js",
"MathMenu.js",
"toMathML.js",
"TeX/noErrors.js",
"TeX/noUndefined.js",
"TeX/AMSmath.js",
"TeX/AMSsymbols.js",
"fast-preview.js",
"AssistiveMML.js",
"[a11y]/accessibility-menu.js"
],
jax: ["input/TeX","input/MathML","output/SVG"],
showMathMenu: false,
errorSettings: { message: ["!"] },
skipStartupTypeset: true,
messageStyle: "none"
});
`;
// List of language codes found in the MathJax/localization/ directory.
protected readonly MATHJAX_LANG_CODES = [
'ar', 'ast', 'bcc', 'bg', 'br', 'ca', 'cdo', 'ce', 'cs', 'cy', 'da', 'de', 'diq', 'en', 'eo', 'es', 'fa',
'fi', 'fr', 'gl', 'he', 'ia', 'it', 'ja', 'kn', 'ko', 'lb', 'lki', 'lt', 'mk', 'nl', 'oc', 'pl', 'pt',
'pt-br', 'qqq', 'ru', 'scn', 'sco', 'sk', 'sl', 'sv', 'th', 'tr', 'uk', 'vi', 'zh-hans', 'zh-hant',
];
// List of explicit mappings and known exceptions (moodle => mathjax).
protected readonly EXPLICIT_MAPPING = {
'zh-tw': 'zh-hant',
'zh-cn': 'zh-hans',
};
protected window: MathJaxWindow = window;
/**
* Initialize MathJax.
*
* @return Promise resolved when done.
*/
async initialize(): Promise<void> {
this.loadJS();
// Update MathJax locale if app language changes.
CoreEvents.on(CoreEvents.LANGUAGE_CHANGED, (lang: string) => {
if (typeof this.window.MathJax == 'undefined') {
return;
}
this.window.MathJax.Hub.Queue(() => {
this.window.MathJax.Localization.setLocale(this.mapLanguageCode(lang));
});
});
// Get the current language.
const lang = await CoreLang.instance.getCurrentLanguage();
// Now call the configure function.
this.window.M!.filter_mathjaxloader!.configure({
mathjaxconfig: this.DEFAULT_CONFIG,
lang: this.mapLanguageCode(lang),
});
}
/**
* 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).
*/
async filter(
text: string,
filter: CoreFilterFilter,
options: CoreFilterFormatTextOptions,
siteId?: string,
): Promise<string> {
const site = await CoreSites.instance.getSite(siteId);
// Don't apply this filter if Moodle is 3.7 or higher and the WS already filtered the content.
if (!options.wsNotFiltered && site.isVersionGreaterEqualThan('3.7')) {
return text;
}
if (text.indexOf('class="filter_mathjaxloader_equation"') != -1) {
// The content seems to have treated mathjax already, don't do it.
return text;
}
// We cannot get the filter settings, so we cannot know if it can be used as a replacement for the TeX filter.
// Assume it cannot (default value).
let hasDisplayOrInline = false;
if (text.match(/\\[[(]/) || text.match(/\$\$/)) {
// Only parse the text if there are mathjax symbols in it.
// The recognized math environments are \[ \] and $$ $$ for display mathematics and \( \) for inline mathematics.
// Wrap display and inline math environments in nolink spans.
const result = this.wrapMathInNoLink(text);
text = result.text;
hasDisplayOrInline = result.changed;
}
if (hasDisplayOrInline) {
return '<span class="filter_mathjaxloader_equation">' + text + '</span>';
}
return text;
}
/**
* Handle HTML. This function is called after "filter", and it will receive an HTMLElement containing the text that was
* filtered.
*
* @param container The HTML container to handle.
* @param filter The filter.
* @param options Options passed to the filters.
* @param viewContainerRef The ViewContainerRef where the container is.
* @param component Component.
* @param componentId Component ID.
* @param siteId Site ID. If not defined, current site.
* @return If async, promise resolved when done.
*/
async handleHtml(
container: HTMLElement,
filter: CoreFilterFilter, // eslint-disable-line @typescript-eslint/no-unused-vars
options: CoreFilterFormatTextOptions, // eslint-disable-line @typescript-eslint/no-unused-vars
viewContainerRef: ViewContainerRef, // eslint-disable-line @typescript-eslint/no-unused-vars
component?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
componentId?: string | number, // eslint-disable-line @typescript-eslint/no-unused-vars
siteId?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
): Promise<void> {
await this.waitForReady();
this.window.M!.filter_mathjaxloader!.typeset(container);
}
/**
* Wrap a portion of the $text inside a no link span. The whole text is then returned.
*
* @param text The text to modify.
* @param start The start index of the substring in text that should be wrapped in the span.
* @param end The end index of the substring in text that should be wrapped in the span.
* @return The whole text with the span inserted around the defined substring.
*/
protected insertSpan(text: string, start: number, end: number): string {
return CoreTextUtils.instance.substrReplace(
text,
'<span class="nolink">' + text.substr(start, end - start + 1) + '</span>',
start,
end - start + 1,
);
}
/**
* Load the JS to make MathJax work in the app. The JS loaded is extracted from Moodle filter's loader JS file.
*/
protected loadJS(): void {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const that = this;
this.window.M = this.window.M || {};
this.window.M.filter_mathjaxloader = this.window.M.filter_mathjaxloader || {
_lang: '', // eslint-disable-line @typescript-eslint/naming-convention
_configured: false, // eslint-disable-line @typescript-eslint/naming-convention
// Add the configuration to the head and set the lang.
configure: function (params: Record<string, unknown>): void {
// Add a js configuration object to the head.
const script = document.createElement('script');
script.type = 'text/x-mathjax-config';
script.text = <string> params.mathjaxconfig;
document.head.appendChild(script);
// Save the lang config until MathJax is actually loaded.
this._lang = <string> params.lang; // eslint-disable-line no-underscore-dangle
},
// Set the correct language for the MathJax menus.
_setLocale: function (): void {
if (!this._configured) { // eslint-disable-line no-underscore-dangle
const lang = this._lang; // eslint-disable-line no-underscore-dangle
if (typeof that.window.MathJax != 'undefined') {
that.window.MathJax.Hub.Queue(() => {
that.window.MathJax.Localization.setLocale(lang);
});
that.window.MathJax.Hub.Configured();
this._configured = true; // eslint-disable-line no-underscore-dangle
}
}
},
// Called by the filter when an equation is found while rendering the page.
typeset: function (container: HTMLElement): void {
if (!this._configured) { // eslint-disable-line no-underscore-dangle
this._setLocale(); // eslint-disable-line no-underscore-dangle
}
if (typeof that.window.MathJax != 'undefined') {
const processDelay = that.window.MathJax.Hub.processSectionDelay;
// Set the process section delay to 0 when updating the formula.
that.window.MathJax.Hub.processSectionDelay = 0;
const equations = Array.from(container.querySelectorAll('.filter_mathjaxloader_equation'));
equations.forEach((node) => {
that.window.MathJax.Hub.Queue(['Typeset', that.window.MathJax.Hub, node]);
});
// Set the delay back to normal after processing.
that.window.MathJax.Hub.processSectionDelay = processDelay;
}
},
};
}
/**
* Perform a mapping of the app language code to the equivalent for MathJax.
*
* @param langCode The app language code.
* @return The MathJax language code.
*/
protected mapLanguageCode(langCode: string): string {
// If defined, explicit mapping takes the highest precedence.
if (this.EXPLICIT_MAPPING[langCode]) {
return this.EXPLICIT_MAPPING[langCode];
}
// If there is exact match, it will be probably right.
if (this.MATHJAX_LANG_CODES.indexOf(langCode) != -1) {
return langCode;
}
// Finally try to find the best matching mathjax pack.
const parts = langCode.split('-');
if (this.MATHJAX_LANG_CODES.indexOf(parts[0]) != -1) {
return parts[0];
}
// No more guessing, use default language.
return CoreLang.instance.getDefaultLanguage();
}
/**
* 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 {
// Only apply the filter if logged in and we're filtering current site.
return !!(site && site.getId() == CoreSites.instance.getCurrentSiteId());
}
/**
* Wait for the MathJax library and our JS object to be loaded.
*
* @param retries Number of times this has been retried.
* @return Promise resolved when ready or if it took too long to load.
*/
protected async waitForReady(retries: number = 0): Promise<void> {
if (this.window.MathJax || retries >= 20) {
// Loaded or too many retries, stop.
return;
}
const deferred = CoreUtils.instance.promiseDefer<void>();
setTimeout(async () => {
try {
await this.waitForReady(retries + 1);
} finally {
deferred.resolve();
}
}, 250);
return deferred.promise;
}
/**
* Find math environments in the $text and wrap them in no link spans
* (<span class="nolink"></span>). If math environments are nested, only
* the outer environment is wrapped in the span.
*
* The recognized math environments are \[ \] and $$ $$ for display
* mathematics and \( \) for inline mathematics.
*
* @param text The text to filter.
* @return Object containing the potentially modified text and a boolean that is true if any changes were made to the text.
*/
protected wrapMathInNoLink(text: string): {text: string; changed: boolean} {
let len = text.length;
let i = 1;
let displayStart = -1;
let displayBracket = false;
let displayDollar = false;
let inlineStart = -1;
let changesDone = false;
// Loop over the $text once.
while (i < len) {
if (displayStart === -1) {
// No display math has started yet.
if (text[i - 1] === '\\') {
if (text[i] === '[') {
// Display mode \[ begins.
displayStart = i - 1;
displayBracket = true;
} else if (text[i] === '(') {
// Inline math \( begins, not nested inside display math.
inlineStart = i - 1;
} else if (text[i] === ')' && inlineStart > -1) {
// Inline math ends, not nested inside display math. Wrap the span around it.
text = this.insertSpan(text, inlineStart, i);
inlineStart = -1; // Reset.
i += 28; // The text length changed due to the <span>.
len += 28;
changesDone = true;
}
} else if (text[i - 1] === '$' && text[i] === '$') {
// Display mode $$ begins.
displayStart = i - 1;
displayDollar = true;
}
} else {
// Display math open.
if ((text[i - 1] === '\\' && text[i] === ']' && displayBracket) ||
(text[i - 1] === '$' && text[i] === '$' && displayDollar)) {
// Display math ends, wrap the span around it.
text = this.insertSpan(text, displayStart, i);
displayStart = -1; // Reset.
displayBracket = false;
displayDollar = false;
i += 28; // The text length changed due to the <span>.
len += 28;
changesDone = true;
}
}
i++;
}
return {
text: text,
changed: changesDone,
};
}
}
type MathJaxWindow = Window & {
MathJax?: any; // eslint-disable-line @typescript-eslint/naming-convention, @typescript-eslint/no-explicit-any
M?: { // eslint-disable-line @typescript-eslint/naming-convention
filter_mathjaxloader?: { // eslint-disable-line @typescript-eslint/naming-convention
_lang: ''; // eslint-disable-line @typescript-eslint/naming-convention
_configured: false; // eslint-disable-line @typescript-eslint/naming-convention
// Add the configuration to the head and set the lang.
configure: (params: Record<string, unknown>) => void;
_setLocale: () => void; // eslint-disable-line @typescript-eslint/naming-convention
typeset: (container: HTMLElement) => void;
};
};
};

View File

@ -0,0 +1,34 @@
// (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 { AddonFilterMediaPluginHandler } from './services/handlers/mediaplugin';
@NgModule({
declarations: [
],
imports: [
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [AddonFilterMediaPluginHandler],
useFactory: (handler: AddonFilterMediaPluginHandler) => () => CoreFilterDelegate.instance.registerHandler(handler),
},
],
})
export class AddonFilterMediaPluginModule {}

View File

@ -0,0 +1,98 @@
// (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter';
import { CoreFilterFilter, CoreFilterFormatTextOptions } from '@features/filter/services/filter';
import { CoreTextUtils } from '@services/utils/text';
import { CoreUrlUtils } from '@services/utils/url';
/**
* Handler to support the Multimedia filter.
*/
@Injectable({ providedIn: 'root' })
export class AddonFilterMediaPluginHandler extends CoreFilterDefaultHandler {
name = 'AddonFilterMediaPluginHandler';
filterName = 'mediaplugin';
protected template = document.createElement('template'); // A template element to convert HTML to element.
/**
* 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, // eslint-disable-line @typescript-eslint/no-unused-vars
options: CoreFilterFormatTextOptions, // eslint-disable-line @typescript-eslint/no-unused-vars
siteId?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
): string | Promise<string> {
this.template.innerHTML = text;
const videos = Array.from(this.template.content.querySelectorAll('video'));
videos.forEach((video) => {
this.treatVideoFilters(video);
});
return this.template.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 dataSetupString = video.getAttribute('data-setup') || video.getAttribute('data-setup-lazy') || '{}';
const data = <VideoDataSetup> CoreTextUtils.instance.parseJSON(dataSetupString, {});
const youtubeUrl = data.techOrder?.[0] == 'youtube' && CoreUrlUtils.instance.getYoutubeEmbedUrl(data.sources?.[0]?.src);
if (!youtubeUrl) {
return;
}
const iframe = document.createElement('iframe');
iframe.id = video.id;
iframe.src = youtubeUrl;
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);
}
}
type VideoDataSetup = {
techOrder?: string[];
sources?: {
src?: string;
}[];
};

View File

@ -0,0 +1,34 @@
// (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 { AddonFilterMultilangHandler } from './services/handlers/multilang';
@NgModule({
declarations: [
],
imports: [
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [AddonFilterMultilangHandler],
useFactory: (handler: AddonFilterMultilangHandler) => () => CoreFilterDelegate.instance.registerHandler(handler),
},
],
})
export class AddonFilterMultilangModule {}

View File

@ -0,0 +1,84 @@
// (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 { CoreFilterFilter, CoreFilterFormatTextOptions } from '@features/filter/services/filter';
import { CoreSite } from '@classes/site';
/**
* Handler to support the Multilang filter.
*/
@Injectable({ providedIn: 'root' })
export class AddonFilterMultilangHandler extends CoreFilterDefaultHandler {
name = 'AddonFilterMultilangHandler';
filterName = 'multilang';
/**
* 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).
*/
async filter(
text: string,
filter: CoreFilterFilter, // eslint-disable-line @typescript-eslint/no-unused-vars
options: CoreFilterFormatTextOptions, // eslint-disable-line @typescript-eslint/no-unused-vars
siteId?: string, // eslint-disable-line @typescript-eslint/no-unused-vars
): Promise<string> {
let language = await CoreLang.instance.getCurrentLanguage();
// 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?.[0]) {
language = matches[0].match(/lang="([a-zA-Z0-9_-]+)"/)?.[1] || language;
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 && !site.isVersionGreaterEqualThan('3.7')));
}
}

View File

@ -0,0 +1,43 @@
// (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter';
import { CoreFilterFormatTextOptions } from '@features/filter/services/filter';
import { CoreSite } from '@classes/site';
/**
* Handler to support the TeX notation filter.
*/
@Injectable({ providedIn: 'root' })
export class AddonFilterTexHandler extends CoreFilterDefaultHandler {
name = 'AddonFilterTexHandler';
filterName = 'tex';
/**
* 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.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean {
// This filter is handled by Moodle, nothing to do in the app.
return false;
}
}

View File

@ -0,0 +1,34 @@
// (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 { AddonFilterTexHandler } from './services/handlers/tex';
@NgModule({
declarations: [
],
imports: [
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [AddonFilterTexHandler],
useFactory: (handler: AddonFilterTexHandler) => () => CoreFilterDelegate.instance.registerHandler(handler),
},
],
})
export class AddonFilterTexModule {}

View File

@ -0,0 +1,43 @@
// (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter';
import { CoreFilterFormatTextOptions } from '@features/filter/services/filter';
import { CoreSite } from '@classes/site';
/**
* Handler to support the HTML tidy filter.
*/
@Injectable({ providedIn: 'root' })
export class AddonFilterTidyHandler extends CoreFilterDefaultHandler {
name = 'AddonFilterTidyHandler';
filterName = 'tidy';
/**
* 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.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean {
// This filter is handled by Moodle, nothing to do in the app.
return false;
}
}

View File

@ -0,0 +1,34 @@
// (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 { AddonFilterTidyHandler } from './services/handlers/tidy';
@NgModule({
declarations: [
],
imports: [
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [AddonFilterTidyHandler],
useFactory: (handler: AddonFilterTidyHandler) => () => CoreFilterDelegate.instance.registerHandler(handler),
},
],
})
export class AddonFilterTidyModule {}

View File

@ -0,0 +1,43 @@
// (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 { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter';
import { CoreFilterFormatTextOptions } from '@features/filter/services/filter';
import { CoreSite } from '@classes/site';
/**
* Handler to support the URL to link and images filter.
*/
@Injectable({ providedIn: 'root' })
export class AddonFilterUrlToLinkHandler extends CoreFilterDefaultHandler {
name = 'AddonFilterUrlToLinkHandler';
filterName = 'urltolink';
/**
* 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.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
shouldBeApplied(options: CoreFilterFormatTextOptions, site?: CoreSite): boolean {
// This filter is handled by Moodle, nothing to do in the app.
return false;
}
}

View File

@ -0,0 +1,34 @@
// (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 { AddonFilterUrlToLinkHandler } from './services/handlers/urltolink';
@NgModule({
declarations: [
],
imports: [
],
providers: [
{
provide: APP_INITIALIZER,
multi: true,
deps: [AddonFilterUrlToLinkHandler],
useFactory: (handler: AddonFilterUrlToLinkHandler) => () => CoreFilterDelegate.instance.registerHandler(handler),
},
],
})
export class AddonFilterUrlToLinkModule {}

View File

@ -255,7 +255,7 @@ export class CoreUrlUtilsProvider {
* @param url URL
* @return Youtube Embed Video URL or null if not found.
*/
getYoutubeEmbedUrl(url: string): string | void {
getYoutubeEmbedUrl(url?: string): string | void {
if (!url) {
return;
}