MOBILE-4616 chore: Move html mode classes to CoreHTMLClasses

main
Pau Ferrer Ocaña 2024-07-19 15:54:15 +02:00
parent 323ccc8c76
commit b0c494ee51
23 changed files with 141 additions and 95 deletions

View File

@ -69,7 +69,7 @@ jobs:
cat circular-dependencies cat circular-dependencies
lines=$(cat circular-dependencies | wc -l) lines=$(cat circular-dependencies | wc -l)
echo "Total circular dependencies: $lines" echo "Total circular dependencies: $lines"
test $lines -eq 131 test $lines -eq 130
- name: JavaScript code compatibility - name: JavaScript code compatibility
run: | run: |
npx check-es-compat www/*.js --polyfills="\{Array,String,TypedArray\}.prototype.at,Object.hasOwn" npx check-es-compat www/*.js --polyfills="\{Array,String,TypedArray\}.prototype.at,Object.hasOwn"

View File

@ -33,7 +33,7 @@ import {
} from '../../services/bigbluebuttonbn'; } from '../../services/bigbluebuttonbn';
import { ADDON_MOD_BBB_COMPONENT } from '../../constants'; import { ADDON_MOD_BBB_COMPONENT } from '../../constants';
import { CoreLoadings } from '@services/loadings'; import { CoreLoadings } from '@services/loadings';
import { convertHTMLToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
/** /**
* Component that displays a Big Blue Button activity. * Component that displays a Big Blue Button activity.
@ -148,7 +148,7 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo
this.recordings = recordingsTable.parsedData.map(recordingData => { this.recordings = recordingsTable.parsedData.map(recordingData => {
const details: RecordingDetail[] = []; const details: RecordingDetail[] = [];
const playbacksEl = convertHTMLToHTMLElement(String(recordingData.playback)); const playbacksEl = convertTextToHTMLElement(String(recordingData.playback));
const playbacks: RecordingPlayback[] = Array.from(playbacksEl.querySelectorAll('a')).map(playbackAnchor => ({ const playbacks: RecordingPlayback[] = Array.from(playbacksEl.querySelectorAll('a')).map(playbackAnchor => ({
name: playbackAnchor.textContent ?? '', name: playbackAnchor.textContent ?? '',
url: playbackAnchor.href, url: playbackAnchor.href,
@ -165,7 +165,7 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo
value = CoreTimeUtils.userDate(Number(value), 'core.strftimedaydate'); value = CoreTimeUtils.userDate(Number(value), 'core.strftimedaydate');
} else if (columnData.allowHTML && typeof value === 'string') { } else if (columnData.allowHTML && typeof value === 'string') {
// If the HTML is empty, don't display it. // If the HTML is empty, don't display it.
const valueElement = convertHTMLToHTMLElement(value); const valueElement = convertTextToHTMLElement(value);
if (!valueElement.querySelector('img') && (valueElement.textContent ?? '').trim() === '') { if (!valueElement.querySelector('img') && (valueElement.textContent ?? '').trim() === '') {
return; return;
} }

View File

@ -18,7 +18,7 @@ import { CoreModuleHandlerBase } from '@features/course/classes/module-base-hand
import { CoreCourseModuleData } from '@features/course/services/course-helper'; import { CoreCourseModuleData } from '@features/course/services/course-helper';
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { convertHTMLToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { ADDON_MOD_FOLDER_PAGE_NAME } from '../../constants'; import { ADDON_MOD_FOLDER_PAGE_NAME } from '../../constants';
@ -58,7 +58,7 @@ export class AddonModFolderModuleHandlerService extends CoreModuleHandlerBase im
if (module.description) { if (module.description) {
// Module description can contain the folder contents if it's inline, remove it. // Module description can contain the folder contents if it's inline, remove it.
const descriptionElement = convertHTMLToHTMLElement(module.description); const descriptionElement = convertTextToHTMLElement(module.description);
Array.from(descriptionElement.querySelectorAll('.foldertree, .folderbuttons, .tertiary-navigation')) Array.from(descriptionElement.querySelectorAll('.foldertree, .folderbuttons, .tertiary-navigation'))
.forEach(element => element.remove()); .forEach(element => element.remove());

View File

@ -28,7 +28,7 @@ import {
import { CoreTime } from '@singletons/time'; import { CoreTime } from '@singletons/time';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { AddonModLessonPageSubtype } from '../constants'; import { AddonModLessonPageSubtype } from '../constants';
import { convertHTMLToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
/** /**
* Helper service that provides some features for quiz. * Helper service that provides some features for quiz.
@ -47,7 +47,7 @@ export class AddonModLessonHelperProvider {
* @returns Formatted data. * @returns Formatted data.
*/ */
formatActivityLink(activityLink: string): AddonModLessonActivityLink { formatActivityLink(activityLink: string): AddonModLessonActivityLink {
const element = convertHTMLToHTMLElement(activityLink); const element = convertTextToHTMLElement(activityLink);
const anchor = element.querySelector('a'); const anchor = element.querySelector('a');
if (!anchor) { if (!anchor) {
@ -77,7 +77,7 @@ export class AddonModLessonHelperProvider {
buttonText: '', buttonText: '',
content: '', content: '',
}; };
const element = convertHTMLToHTMLElement(html); const element = convertTextToHTMLElement(html);
// Search the input button. // Search the input button.
const button = <HTMLInputElement> element.querySelector('input[type="button"]'); const button = <HTMLInputElement> element.querySelector('input[type="button"]');
@ -101,7 +101,7 @@ export class AddonModLessonHelperProvider {
*/ */
getPageButtonsFromHtml(html: string): AddonModLessonPageButton[] { getPageButtonsFromHtml(html: string): AddonModLessonPageButton[] {
const buttons: AddonModLessonPageButton[] = []; const buttons: AddonModLessonPageButton[] = [];
const element = convertHTMLToHTMLElement(html); const element = convertTextToHTMLElement(html);
// Get the container of the buttons if it exists. // Get the container of the buttons if it exists.
let buttonsContainer = element.querySelector('.branchbuttoncontainer'); let buttonsContainer = element.querySelector('.branchbuttoncontainer');
@ -153,7 +153,7 @@ export class AddonModLessonHelperProvider {
*/ */
getPageContentsFromPageData(data: AddonModLessonGetPageDataWSResponse): string { getPageContentsFromPageData(data: AddonModLessonGetPageDataWSResponse): string {
// Search the page contents inside the whole page HTML. Use data.pagecontent because it's filtered. // Search the page contents inside the whole page HTML. Use data.pagecontent because it's filtered.
const element = convertHTMLToHTMLElement(data.pagecontent || ''); const element = convertTextToHTMLElement(data.pagecontent || '');
const contents = element.querySelector('.contents'); const contents = element.querySelector('.contents');
if (contents) { if (contents) {
@ -179,7 +179,7 @@ export class AddonModLessonHelperProvider {
* @returns Question data. * @returns Question data.
*/ */
getQuestionFromPageData(questionForm: FormGroup, pageData: AddonModLessonGetPageDataWSResponse): AddonModLessonQuestion { getQuestionFromPageData(questionForm: FormGroup, pageData: AddonModLessonGetPageDataWSResponse): AddonModLessonQuestion {
const element = convertHTMLToHTMLElement(pageData.pagecontent || ''); const element = convertTextToHTMLElement(pageData.pagecontent || '');
// Get the container of the question answers if it exists. // Get the container of the question answers if it exists.
const fieldContainer = <HTMLElement> element.querySelector('.fcontainer'); const fieldContainer = <HTMLElement> element.querySelector('.fcontainer');
@ -464,7 +464,7 @@ export class AddonModLessonHelperProvider {
* @returns Object with the data to render the answer. If the answer doesn't require any parsing, return a string with the HTML. * @returns Object with the data to render the answer. If the answer doesn't require any parsing, return a string with the HTML.
*/ */
getQuestionPageAnswerDataFromHtml(html: string): AddonModLessonAnswerData { getQuestionPageAnswerDataFromHtml(html: string): AddonModLessonAnswerData {
const element = convertHTMLToHTMLElement(html); const element = convertTextToHTMLElement(html);
// Check if it has a checkbox. // Check if it has a checkbox.
let input = element.querySelector<HTMLInputElement>('input[type="checkbox"][name*="answer"]'); let input = element.querySelector<HTMLInputElement>('input[type="checkbox"][name*="answer"]');
@ -589,7 +589,7 @@ export class AddonModLessonHelperProvider {
* @returns Feedback without the question text. * @returns Feedback without the question text.
*/ */
removeQuestionFromFeedback(html: string): string { removeQuestionFromFeedback(html: string): string {
const element = convertHTMLToHTMLElement(html); const element = convertTextToHTMLElement(html);
// Remove the question text. // Remove the question text.
CoreDomUtils.removeElement(element, '.generalbox:not(.feedback):not(.correctanswer)'); CoreDomUtils.removeElement(element, '.generalbox:not(.feedback):not(.correctanswer)');

View File

@ -18,7 +18,7 @@ import { CoreSite } from '@classes/sites/site';
import { CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseCommonModWSOptions } from '@features/course/services/course';
import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreCourseLogHelper } from '@features/course/services/log-helper';
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites'; import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
import { convertHTMLToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
import { CoreText } from '@singletons/text'; import { CoreText } from '@singletons/text';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws'; import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
@ -164,7 +164,7 @@ export class AddonModLessonProvider {
if (page.answerdata && !this.answerPageIsQuestion(page)) { if (page.answerdata && !this.answerPageIsQuestion(page)) {
// It isn't a question page, but it can be an end of branch, etc. Check if the first answer has a button. // It isn't a question page, but it can be an end of branch, etc. Check if the first answer has a button.
if (page.answerdata.answers && page.answerdata.answers[0]) { if (page.answerdata.answers && page.answerdata.answers[0]) {
const element = convertHTMLToHTMLElement(page.answerdata.answers[0][0]); const element = convertTextToHTMLElement(page.answerdata.answers[0][0]);
return !!element.querySelector('input[type="button"]'); return !!element.querySelector('input[type="button"]');
} }

View File

@ -42,7 +42,7 @@ import { CoreGroups } from '@services/groups';
import { CoreTimeUtils } from '@services/utils/time'; import { CoreTimeUtils } from '@services/utils/time';
import { CoreModals } from '@services/modals'; import { CoreModals } from '@services/modals';
import { CoreLoadings } from '@services/loadings'; import { CoreLoadings } from '@services/loadings';
import { convertHTMLToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
/** /**
* Helper service that provides some features for quiz. * Helper service that provides some features for quiz.
@ -302,7 +302,7 @@ export class AddonModQuizHelperProvider {
* @returns Question's mark. * @returns Question's mark.
*/ */
getQuestionMarkFromHtml(html: string): string | undefined { getQuestionMarkFromHtml(html: string): string | undefined {
const element = convertHTMLToHTMLElement(html); const element = convertTextToHTMLElement(html);
return CoreDomUtils.getContentsOfElement(element, '.grade'); return CoreDomUtils.getContentsOfElement(element, '.grade');
} }

View File

@ -29,7 +29,7 @@ import {
} from '@features/question/services/question'; } from '@features/question/services/question';
import { CoreQuestionDelegate } from '@features/question/services/question-delegate'; import { CoreQuestionDelegate } from '@features/question/services/question-delegate';
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites'; import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
import { convertHTMLToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
import { CoreTimeUtils } from '@services/utils/time'; import { CoreTimeUtils } from '@services/utils/time';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { CoreStatusWithWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws'; import { CoreStatusWithWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
@ -1588,7 +1588,7 @@ export class AddonModQuizProvider {
* @returns Whether it's blocked. * @returns Whether it's blocked.
*/ */
isQuestionBlocked(question: CoreQuestionQuestionParsed): boolean { isQuestionBlocked(question: CoreQuestionQuestionParsed): boolean {
const element = convertHTMLToHTMLElement(question.html); const element = convertTextToHTMLElement(question.html);
return !!element.querySelector('.mod_quiz-blocked_question_warning'); return !!element.querySelector('.mod_quiz-blocked_question_warning');
} }

View File

@ -16,7 +16,7 @@ import { Injectable, Type } from '@angular/core';
import { CoreQuestionQuestionParsed, CoreQuestionsAnswers } from '@features/question/services/question'; import { CoreQuestionQuestionParsed, CoreQuestionsAnswers } from '@features/question/services/question';
import { CoreQuestionHandler } from '@features/question/services/question-delegate'; import { CoreQuestionHandler } from '@features/question/services/question-delegate';
import { convertHTMLToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { AddonQtypeCalculatedComponent } from '../../component/calculated'; import { AddonQtypeCalculatedComponent } from '../../component/calculated';
@ -53,7 +53,7 @@ export class AddonQtypeCalculatedHandlerService implements CoreQuestionHandler {
*/ */
hasSeparateUnitField(question: CoreQuestionQuestionParsed): boolean { hasSeparateUnitField(question: CoreQuestionQuestionParsed): boolean {
if (!question.parsedSettings) { if (!question.parsedSettings) {
const element = convertHTMLToHTMLElement(question.html); const element = convertTextToHTMLElement(question.html);
return !!(element.querySelector('select[name*=unit]') || element.querySelector('input[type="radio"]')); return !!(element.querySelector('select[name*=unit]') || element.querySelector('input[type="radio"]'));
} }

View File

@ -22,7 +22,7 @@ import { CoreQuestionHandler } from '@features/question/services/question-delega
import { CoreQuestionHelper } from '@features/question/services/question-helper'; import { CoreQuestionHelper } from '@features/question/services/question-helper';
import { CoreFileSession } from '@services/file-session'; import { CoreFileSession } from '@services/file-session';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { convertHTMLToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
import { CoreText } from '@singletons/text'; import { CoreText } from '@singletons/text';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { CoreWSFile } from '@services/ws'; import { CoreWSFile } from '@services/ws';
@ -90,7 +90,7 @@ export class AddonQtypeEssayHandlerService implements CoreQuestionHandler {
}; };
} }
const element = convertHTMLToHTMLElement(question.html); const element = convertTextToHTMLElement(question.html);
return { return {
text: !!element.querySelector('textarea[name*=_answer]'), text: !!element.querySelector('textarea[name*=_answer]'),
@ -116,7 +116,7 @@ export class AddonQtypeEssayHandlerService implements CoreQuestionHandler {
* @inheritdoc * @inheritdoc
*/ */
getPreventSubmitMessage(question: CoreQuestionQuestionParsed): string | undefined { getPreventSubmitMessage(question: CoreQuestionQuestionParsed): string | undefined {
const element = convertHTMLToHTMLElement(question.html); const element = convertTextToHTMLElement(question.html);
const uploadFilesSupported = question.responsefileareas !== undefined; const uploadFilesSupported = question.responsefileareas !== undefined;
if (!uploadFilesSupported && element.querySelector('div[id*=filemanager]')) { if (!uploadFilesSupported && element.querySelector('div[id*=filemanager]')) {
@ -293,7 +293,7 @@ export class AddonQtypeEssayHandlerService implements CoreQuestionHandler {
siteId?: string, siteId?: string,
): Promise<void> { ): Promise<void> {
const element = convertHTMLToHTMLElement(question.html); const element = convertTextToHTMLElement(question.html);
const attachmentsInput = <HTMLInputElement> element.querySelector('.attachments input[name*=_attachments]'); const attachmentsInput = <HTMLInputElement> element.querySelector('.attachments input[name*=_attachments]');
// Search the textarea to get its name. // Search the textarea to get its name.
@ -375,7 +375,7 @@ export class AddonQtypeEssayHandlerService implements CoreQuestionHandler {
siteId?: string, siteId?: string,
): Promise<void> { ): Promise<void> {
const element = convertHTMLToHTMLElement(question.html); const element = convertTextToHTMLElement(question.html);
const attachmentsInput = <HTMLInputElement> element.querySelector('.attachments input[name*=_attachments]'); const attachmentsInput = <HTMLInputElement> element.querySelector('.attachments input[name*=_attachments]');
if (attachmentsInput) { if (attachmentsInput) {
@ -454,7 +454,7 @@ export class AddonQtypeEssayHandlerService implements CoreQuestionHandler {
isPlainText = question.parsedSettings.responseformat == 'monospaced' || isPlainText = question.parsedSettings.responseformat == 'monospaced' ||
question.parsedSettings.responseformat == 'plain'; question.parsedSettings.responseformat == 'plain';
} else { } else {
const questionEl = convertHTMLToHTMLElement(question.html); const questionEl = convertTextToHTMLElement(question.html);
isPlainText = !!questionEl.querySelector('.qtype_essay_monospaced') || !!questionEl.querySelector('.qtype_essay_plain'); isPlainText = !!questionEl.querySelector('.qtype_essay_monospaced') || !!questionEl.querySelector('.qtype_essay_plain');
} }

View File

@ -14,7 +14,7 @@
import { Component, AfterViewInit, Input, ContentChild, ViewEncapsulation } from '@angular/core'; import { Component, AfterViewInit, Input, ContentChild, ViewEncapsulation } from '@angular/core';
import { IonInput } from '@ionic/angular'; import { IonInput } from '@ionic/angular';
import { convertHTMLToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { CoreLogger } from '@singletons/logger'; import { CoreLogger } from '@singletons/logger';
@ -84,7 +84,7 @@ export class CoreShowPasswordComponent implements AfterViewInit {
return; return;
} }
const toggle = convertHTMLToHTMLElement('<ion-input-password-toggle slot="end" />'); const toggle = convertTextToHTMLElement('<ion-input-password-toggle slot="end" />');
input.parentElement?.appendChild(toggle.children[0]); input.parentElement?.appendChild(toggle.children[0]);
} }

View File

@ -14,7 +14,7 @@
import { Injectable, Type } from '@angular/core'; import { Injectable, Type } from '@angular/core';
import { convertHTMLToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
import { CoreTagAreaHandler } from '@features/tag/services/tag-area-delegate'; import { CoreTagAreaHandler } from '@features/tag/services/tag-area-delegate';
import { CoreCourseTagAreaComponent } from '../../components/tag-area/tag-area'; import { CoreCourseTagAreaComponent } from '../../components/tag-area/tag-area';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
@ -45,7 +45,7 @@ export class CoreCourseTagAreaHandlerService implements CoreTagAreaHandler {
*/ */
parseContent(content: string): CoreCouseTagItems[] { parseContent(content: string): CoreCouseTagItems[] {
const items: CoreCouseTagItems[] = []; const items: CoreCouseTagItems[] = [];
const element = convertHTMLToHTMLElement(content); const element = convertTextToHTMLElement(content);
Array.from(element.querySelectorAll('div.coursebox')).forEach((coursebox) => { Array.from(element.querySelectorAll('div.coursebox')).forEach((coursebox) => {
const courseId = parseInt(coursebox.getAttribute('data-courseid') || '', 10); const courseId = parseInt(coursebox.getAttribute('data-courseid') || '', 10);

View File

@ -44,7 +44,7 @@ import { CoreCourseHelper } from '@features/course/services/course-helper';
import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
import { CoreCourseAccess } from '@features/course/services/course-options-delegate'; import { CoreCourseAccess } from '@features/course/services/course-options-delegate';
import { CoreLoadings } from '@services/loadings'; import { CoreLoadings } from '@services/loadings';
import { convertHTMLToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
export const GRADES_PAGE_NAME = 'grades'; export const GRADES_PAGE_NAME = 'grades';
export const GRADES_PARTICIPANTS_PAGE_NAME = 'participant-grades'; export const GRADES_PARTICIPANTS_PAGE_NAME = 'participant-grades';
@ -574,7 +574,7 @@ export class CoreGradesHelperProvider {
const modname = module?.[1]; const modname = module?.[1];
if (modname !== undefined) { if (modname !== undefined) {
const modicon = convertHTMLToHTMLElement(text).querySelector('img')?.getAttribute('src') ?? undefined; const modicon = convertTextToHTMLElement(text).querySelector('img')?.getAttribute('src') ?? undefined;
row.itemtype = 'mod'; row.itemtype = 'mod';
row.itemmodule = modname; row.itemmodule = modname;

View File

@ -25,7 +25,7 @@ import { CoreLogger } from '@singletons/logger';
import { CoreQuestionBehaviourButton, CoreQuestionHelper, CoreQuestionQuestion } from '../services/question-helper'; import { CoreQuestionBehaviourButton, CoreQuestionHelper, CoreQuestionQuestion } from '../services/question-helper';
import { ContextLevel } from '@/core/constants'; import { ContextLevel } from '@/core/constants';
import { toBoolean } from '@/core/transforms/boolean'; import { toBoolean } from '@/core/transforms/boolean';
import { convertHTMLToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
/** /**
* Base class for components to render a question. * Base class for components to render a question.
@ -88,7 +88,7 @@ export class CoreQuestionBaseComponent<T extends AddonModQuizQuestion = AddonMod
this.hostElement.classList.add('core-question-container'); this.hostElement.classList.add('core-question-container');
const questionElement = convertHTMLToHTMLElement(this.question.html); const questionElement = convertTextToHTMLElement(this.question.html);
// Extract question text. // Extract question text.
this.question.text = CoreDomUtils.getContentsOfElement(questionElement, '.qtext'); this.question.text = CoreDomUtils.getContentsOfElement(questionElement, '.qtext');
@ -434,7 +434,7 @@ export class CoreQuestionBaseComponent<T extends AddonModQuizQuestion = AddonMod
return; return;
} }
const element = convertHTMLToHTMLElement(this.question.html); const element = convertTextToHTMLElement(this.question.html);
// Get question content. // Get question content.
const content = element.querySelector<HTMLElement>(contentSelector); const content = element.querySelector<HTMLElement>(contentSelector);

View File

@ -31,7 +31,7 @@ import { CoreUrl } from '@singletons/url';
import { ContextLevel } from '@/core/constants'; import { ContextLevel } from '@/core/constants';
import { CoreIonicColorNames } from '@singletons/colors'; import { CoreIonicColorNames } from '@singletons/colors';
import { CoreViewer } from '@features/viewer/services/viewer'; import { CoreViewer } from '@features/viewer/services/viewer';
import { convertHTMLToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
/** /**
* Service with some common functions to handle questions. * Service with some common functions to handle questions.
@ -132,7 +132,7 @@ export class CoreQuestionHelperProvider {
selector = selector || '.im-controls [type="submit"]'; selector = selector || '.im-controls [type="submit"]';
const element = convertHTMLToHTMLElement(question.html); const element = convertTextToHTMLElement(question.html);
// Search the buttons. // Search the buttons.
const buttons = <HTMLInputElement[]> Array.from(element.querySelectorAll(selector)); const buttons = <HTMLInputElement[]> Array.from(element.querySelectorAll(selector));
@ -151,7 +151,7 @@ export class CoreQuestionHelperProvider {
* @returns Wether the certainty is found. * @returns Wether the certainty is found.
*/ */
extractQbehaviourCBM(question: CoreQuestionQuestion): boolean { extractQbehaviourCBM(question: CoreQuestionQuestion): boolean {
const element = convertHTMLToHTMLElement(question.html); const element = convertTextToHTMLElement(question.html);
const labels = Array.from(element.querySelectorAll('.im-controls .certaintychoices label[for*="certainty"]')); const labels = Array.from(element.querySelectorAll('.im-controls .certaintychoices label[for*="certainty"]'));
question.behaviourCertaintyOptions = []; question.behaviourCertaintyOptions = [];
@ -218,7 +218,7 @@ export class CoreQuestionHelperProvider {
* @returns Whether the seen input is found. * @returns Whether the seen input is found.
*/ */
extractQbehaviourSeenInput(question: CoreQuestionQuestion): boolean { extractQbehaviourSeenInput(question: CoreQuestionQuestion): boolean {
const element = convertHTMLToHTMLElement(question.html); const element = convertTextToHTMLElement(question.html);
// Search the "seen" input. // Search the "seen" input.
const seenInput = <HTMLInputElement> element.querySelector('input[type="hidden"][name*=seen]'); const seenInput = <HTMLInputElement> element.querySelector('input[type="hidden"][name*=seen]');
@ -274,7 +274,7 @@ export class CoreQuestionHelperProvider {
* @param attrName Name of the attribute to store the HTML in. * @param attrName Name of the attribute to store the HTML in.
*/ */
protected extractQuestionLastElementNotInContent(question: CoreQuestionQuestion, selector: string, attrName: string): void { protected extractQuestionLastElementNotInContent(question: CoreQuestionQuestion, selector: string, attrName: string): void {
const element = convertHTMLToHTMLElement(question.html); const element = convertTextToHTMLElement(question.html);
const matches = <HTMLElement[]> Array.from(element.querySelectorAll(selector)); const matches = <HTMLElement[]> Array.from(element.querySelectorAll(selector));
// Get the last element and check it's not in the question contents. // Get the last element and check it's not in the question contents.
@ -359,7 +359,7 @@ export class CoreQuestionHelperProvider {
* @returns Object where the keys are the names. * @returns Object where the keys are the names.
*/ */
getAllInputNamesFromHtml(html: string): Record<string, boolean> { getAllInputNamesFromHtml(html: string): Record<string, boolean> {
const element = convertHTMLToHTMLElement('<form>' + html + '</form>'); const element = convertTextToHTMLElement('<form>' + html + '</form>');
const form = <HTMLFormElement> element.children[0]; const form = <HTMLFormElement> element.children[0];
const answers: Record<string, boolean> = {}; const answers: Record<string, boolean> = {};
@ -425,7 +425,7 @@ export class CoreQuestionHelperProvider {
* @returns Attachments. * @returns Attachments.
*/ */
getQuestionAttachmentsFromHtml(html: string): CoreWSFile[] { getQuestionAttachmentsFromHtml(html: string): CoreWSFile[] {
const element = convertHTMLToHTMLElement(html); const element = convertTextToHTMLElement(html);
// Remove the filemanager (area to attach files to a question). // Remove the filemanager (area to attach files to a question).
CoreDomUtils.removeElement(element, 'div[id*=filemanager]'); CoreDomUtils.removeElement(element, 'div[id*=filemanager]');
@ -462,7 +462,7 @@ export class CoreQuestionHelperProvider {
} }
// Search the input holding the sequencecheck. // Search the input holding the sequencecheck.
const element = convertHTMLToHTMLElement(html); const element = convertTextToHTMLElement(html);
const input = <HTMLInputElement> element.querySelector('input[name*=sequencecheck]'); const input = <HTMLInputElement> element.querySelector('input[name*=sequencecheck]');
if (!input || input.name === undefined || input.value === undefined) { if (!input || input.name === undefined || input.value === undefined) {
@ -532,7 +532,7 @@ export class CoreQuestionHelperProvider {
* @returns Validation error message if present. * @returns Validation error message if present.
*/ */
getValidationErrorFromHtml(html: string): string | undefined { getValidationErrorFromHtml(html: string): string | undefined {
const element = convertHTMLToHTMLElement(html); const element = convertTextToHTMLElement(html);
return CoreDomUtils.getContentsOfElement(element, '.validationerror'); return CoreDomUtils.getContentsOfElement(element, '.validationerror');
} }
@ -584,7 +584,7 @@ export class CoreQuestionHelperProvider {
* @param question Question. * @param question Question.
*/ */
loadLocalAnswersInHtml(question: CoreQuestionQuestion): void { loadLocalAnswersInHtml(question: CoreQuestionQuestion): void {
const element = convertHTMLToHTMLElement('<form>' + question.html + '</form>'); const element = convertTextToHTMLElement('<form>' + question.html + '</form>');
const form = <HTMLFormElement> element.children[0]; const form = <HTMLFormElement> element.children[0];
// Search all input elements. // Search all input elements.
@ -759,7 +759,7 @@ export class CoreQuestionHelperProvider {
* @returns Whether the button is found. * @returns Whether the button is found.
*/ */
protected searchBehaviourButton(question: CoreQuestionQuestion, htmlProperty: string, selector: string): boolean { protected searchBehaviourButton(question: CoreQuestionQuestion, htmlProperty: string, selector: string): boolean {
const element = convertHTMLToHTMLElement(question[htmlProperty]); const element = convertTextToHTMLElement(question[htmlProperty]);
const button = element.querySelector<HTMLElement>(selector); const button = element.querySelector<HTMLElement>(selector);
if (!button) { if (!button) {

View File

@ -31,6 +31,7 @@ import { CoreError } from '@classes/errors/error';
import { Observable, Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { CoreErrorHelper } from '@services/error-helper'; import { CoreErrorHelper } from '@services/error-helper';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { CoreHTMLClasses } from '@singletons/html-classes';
/** /**
* Object with space usage and cache entries that can be erased. * Object with space usage and cache entries that can be erased.
@ -433,10 +434,10 @@ export class CoreSettingsHelperProvider {
* @param enable True to enable dark mode, false to disable. * @param enable True to enable dark mode, false to disable.
*/ */
protected toggleDarkMode(enable: boolean = false): void { protected toggleDarkMode(enable: boolean = false): void {
const isDark = CoreDomUtils.hasModeClass('dark'); const isDark = CoreHTMLClasses.hasModeClass('dark');
if (isDark !== enable) { if (isDark !== enable) {
CoreDomUtils.toggleModeClass('dark', enable); CoreHTMLClasses.toggleModeClass('dark', enable);
this.darkModeObservable.next(enable); this.darkModeObservable.next(enable);
CoreApp.setSystemUIColors(); CoreApp.setSystemUIColors();

View File

@ -14,7 +14,7 @@
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { convertHTMLToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
/** /**
* Service with helper functions for tags. * Service with helper functions for tags.
@ -30,7 +30,7 @@ export class CoreTagHelperProvider {
*/ */
parseFeedContent(content: string): CoreTagFeedElement[] { parseFeedContent(content: string): CoreTagFeedElement[] {
const items: CoreTagFeedElement[] = []; const items: CoreTagFeedElement[] = [];
const element = convertHTMLToHTMLElement(content); const element = convertTextToHTMLElement(content);
Array.from(element.querySelectorAll('ul.tag_feed > li')).forEach((itemElement) => { Array.from(element.querySelectorAll('ul.tag_feed > li')).forEach((itemElement) => {
const item: CoreTagFeedElement = { details: [] }; const item: CoreTagFeedElement = { details: [] };

View File

@ -14,7 +14,7 @@
import { Injectable, Type } from '@angular/core'; import { Injectable, Type } from '@angular/core';
import { convertHTMLToHTMLElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement } from '@/core/utils/create-html-element';
import { CoreTagAreaHandler } from '@features/tag/services/tag-area-delegate'; import { CoreTagAreaHandler } from '@features/tag/services/tag-area-delegate';
import { CoreUserTagAreaComponent } from '@features/user/components/tag-area/tag-area'; import { CoreUserTagAreaComponent } from '@features/user/components/tag-area/tag-area';
import { CoreTagFeedElement } from '@features/tag/services/tag-helper'; import { CoreTagFeedElement } from '@features/tag/services/tag-helper';
@ -47,7 +47,7 @@ export class CoreUserTagAreaHandlerService implements CoreTagAreaHandler {
*/ */
parseContent(content: string): CoreUserTagFeedElement[] { parseContent(content: string): CoreUserTagFeedElement[] {
const items: CoreUserTagFeedElement[] = []; const items: CoreUserTagFeedElement[] = [];
const element = convertHTMLToHTMLElement(content); const element = convertTextToHTMLElement(content);
Array.from(element.querySelectorAll('div.user-box')).forEach((userbox: HTMLElement) => { Array.from(element.querySelectorAll('div.user-box')).forEach((userbox: HTMLElement) => {
const avatarLink = userbox.querySelector('a:first-child'); const avatarLink = userbox.querySelector('a:first-child');

View File

@ -58,7 +58,7 @@ import { asyncInstance, AsyncInstance } from '../utils/async-instance';
import { CorePath } from '@singletons/path'; import { CorePath } from '@singletons/path';
import { CorePromisedValue } from '@classes/promised-value'; import { CorePromisedValue } from '@classes/promised-value';
import { CoreAnalytics, CoreAnalyticsEventType } from './analytics'; import { CoreAnalytics, CoreAnalyticsEventType } from './analytics';
import { convertHTMLToHTMLElement } from '../utils/create-html-element'; import { convertTextToHTMLElement } from '../utils/create-html-element';
/* /*
* Factory for handling downloading files and retrieve downloaded files. * Factory for handling downloading files and retrieve downloaded files.
@ -1148,7 +1148,7 @@ export class CoreFilepoolProvider {
extractDownloadableFilesFromHtml(html: string): string[] { extractDownloadableFilesFromHtml(html: string): string[] {
let urls: string[] = []; let urls: string[] = [];
const element = convertHTMLToHTMLElement(html); const element = convertTextToHTMLElement(html);
const elements: AnchorOrMediaElement[] = Array.from(element.querySelectorAll('a, img, audio, video, source, track')); const elements: AnchorOrMediaElement[] = Array.from(element.querySelectorAll('a, img, audio, video, source, track'));
for (let i = 0; i < elements.length; i++) { for (let i = 0; i < elements.length; i++) {

View File

@ -17,7 +17,7 @@ import { CorePlatform } from '@services/platform';
import { Network } from '@awesome-cordova-plugins/network/ngx'; import { Network } from '@awesome-cordova-plugins/network/ngx';
import { NgZone, makeSingleton } from '@singletons'; import { NgZone, makeSingleton } from '@singletons';
import { Observable, Subject, merge } from 'rxjs'; import { Observable, Subject, merge } from 'rxjs';
import { CoreDomUtils } from './utils/dom'; import { CoreHTMLClasses } from '@singletons/html-classes';
export enum CoreNetworkConnection { export enum CoreNetworkConnection {
UNKNOWN = 'unknown', UNKNOWN = 'unknown',
@ -109,24 +109,24 @@ export class CoreNetworkService extends Network {
NgZone.run(() => { NgZone.run(() => {
const isOnline = this.isOnline(); const isOnline = this.isOnline();
const hadOfflineMessage = CoreDomUtils.hasModeClass('core-offline'); const hadOfflineMessage = CoreHTMLClasses.hasModeClass('core-offline');
CoreDomUtils.toggleModeClass('core-offline', !isOnline); CoreHTMLClasses.toggleModeClass('core-offline', !isOnline);
if (isOnline && hadOfflineMessage) { if (isOnline && hadOfflineMessage) {
CoreDomUtils.toggleModeClass('core-online', true); CoreHTMLClasses.toggleModeClass('core-online', true);
setTimeout(() => { setTimeout(() => {
CoreDomUtils.toggleModeClass('core-online', false); CoreHTMLClasses.toggleModeClass('core-online', false);
}, 3000); }, 3000);
} else if (!isOnline) { } else if (!isOnline) {
CoreDomUtils.toggleModeClass('core-online', false); CoreHTMLClasses.toggleModeClass('core-online', false);
} }
}); });
}); });
const isOnline = this.isOnline(); const isOnline = this.isOnline();
CoreDomUtils.toggleModeClass('core-offline', !isOnline); CoreHTMLClasses.toggleModeClass('core-offline', !isOnline);
} }
/** /**

View File

@ -55,7 +55,8 @@ import { CorePopovers, OpenPopoverOptions } from '@services/popovers';
import { CoreViewer } from '@features/viewer/services/viewer'; import { CoreViewer } from '@features/viewer/services/viewer';
import { CoreLoadings } from '@services/loadings'; import { CoreLoadings } from '@services/loadings';
import { CoreErrorHelper, CoreErrorObject } from '@services/error-helper'; import { CoreErrorHelper, CoreErrorObject } from '@services/error-helper';
import { convertHTMLToHTMLElement, CoreTemplateElement } from '@/core/utils/create-html-element'; import { convertTextToHTMLElement, CoreTemplateElement } from '@/core/utils/create-html-element';
import { CoreHTMLClasses } from '@singletons/html-classes';
/* /*
* "Utils" service with helper functions for UI, DOM elements and HTML code. * "Utils" service with helper functions for UI, DOM elements and HTML code.
@ -199,7 +200,7 @@ export class CoreDomUtilsProvider {
* @deprecated since 4.5. Use convertToElement directly instead. * @deprecated since 4.5. Use convertToElement directly instead.
*/ */
convertToElement(html: string): HTMLElement { convertToElement(html: string): HTMLElement {
return convertHTMLToHTMLElement(html); return convertTextToHTMLElement(html);
} }
/** /**
@ -387,7 +388,7 @@ export class CoreDomUtilsProvider {
* @returns Attribute value. * @returns Attribute value.
*/ */
getHTMLElementAttribute(html: string, attribute: string): string | null { getHTMLElementAttribute(html: string, attribute: string): string | null {
return convertHTMLToHTMLElement(html).children[0].getAttribute(attribute); return convertTextToHTMLElement(html).children[0].getAttribute(attribute);
} }
/** /**
@ -648,7 +649,7 @@ export class CoreDomUtilsProvider {
* @returns HTML without the element. * @returns HTML without the element.
*/ */
removeElementFromHtml(html: string, selector: string, removeAll?: boolean): string { removeElementFromHtml(html: string, selector: string, removeAll?: boolean): string {
const element = convertHTMLToHTMLElement(html); const element = convertTextToHTMLElement(html);
if (removeAll) { if (removeAll) {
const selected = element.querySelectorAll(selector); const selected = element.querySelectorAll(selector);
@ -696,7 +697,7 @@ export class CoreDomUtilsProvider {
paths: {[url: string]: string}, paths: {[url: string]: string},
anchorFn?: (anchor: HTMLElement, href: string) => void, anchorFn?: (anchor: HTMLElement, href: string) => void,
): string { ): string {
const element = convertHTMLToHTMLElement(html); const element = convertTextToHTMLElement(html);
// Treat elements with src (img, audio, video, ...). // Treat elements with src (img, audio, video, ...).
const media = Array.from(element.querySelectorAll<HTMLElement>('img, video, audio, source, track, iframe, embed')); const media = Array.from(element.querySelectorAll<HTMLElement>('img, video, audio, source, track, iframe, embed'));
@ -1399,7 +1400,7 @@ export class CoreDomUtilsProvider {
* @returns Same text converted to HTMLCollection. * @returns Same text converted to HTMLCollection.
*/ */
toDom(text: string): HTMLCollection { toDom(text: string): HTMLCollection {
const element = convertHTMLToHTMLElement(text); const element = convertTextToHTMLElement(text);
return element.children; return element.children;
} }
@ -1610,18 +1611,22 @@ export class CoreDomUtilsProvider {
* *
* @param className Class name. * @param className Class name.
* @returns Whether the CSS class is set. * @returns Whether the CSS class is set.
*
* @deprecated since 4.5. Use CoreHTMLClasses.hasModeClass instead.
*/ */
hasModeClass(className: string): boolean { hasModeClass(className: string): boolean {
return document.documentElement.classList.contains(className); return CoreHTMLClasses.hasModeClass(className);
} }
/** /**
* Get active mode CSS classes. * Get active mode CSS classes.
* *
* @returns Mode classes. * @returns Mode classes.
*
* @deprecated since 4.5. Use CoreHTMLClasses.getModeClasses instead.
*/ */
getModeClasses(): string[] { getModeClasses(): string[] {
return Array.from(document.documentElement.classList); return CoreHTMLClasses.getModeClasses();
} }
/** /**
@ -1629,12 +1634,14 @@ export class CoreDomUtilsProvider {
* *
* @param className Class name. * @param className Class name.
* @param enable Whether to add or remove the class. * @param enable Whether to add or remove the class.
*
* @deprecated since 4.5. Use CoreHTMLClasses.toggleModeClass instead.
*/ */
toggleModeClass( toggleModeClass(
className: string, className: string,
enable = false, enable = false,
): void { ): void {
document.documentElement.classList.toggle(className, enable); CoreHTMLClasses.toggleModeClass(className, enable);
} }
} }

View File

@ -14,29 +14,31 @@
import { CoreSiteInfo, CoreSiteInfoResponse } from '@classes/sites/unauthenticated-site'; import { CoreSiteInfo, CoreSiteInfoResponse } from '@classes/sites/unauthenticated-site';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUrl } from './url'; import { CoreUrl } from './url';
import { CoreConstants } from '../constants'; import { CoreConstants } from '../constants';
import { ScrollDetail } from '@ionic/angular'; import { ScrollDetail } from '@ionic/angular';
import { CoreDom } from './dom'; import { CoreDom } from './dom';
const MOODLE_SITE_URL_PREFIX = 'url-';
const MOODLE_VERSION_PREFIX = 'version-';
const MOODLEAPP_VERSION_PREFIX = 'moodleapp-';
const MOODLE_SITE_THEME_PREFIX = 'theme-site-';
/** /**
* Singleton with helper functions to manage HTML classes. * Singleton with helper functions to manage HTML classes.
*/ */
export class CoreHTMLClasses { export class CoreHTMLClasses {
protected static readonly MOODLE_SITE_URL_PREFIX = 'url-';
protected static readonly MOODLE_VERSION_PREFIX = 'version-';
protected static readonly MOODLEAPP_VERSION_PREFIX = 'moodleapp-';
protected static readonly MOODLE_SITE_THEME_PREFIX = 'theme-site-';
/** /**
* Initialize HTML classes. * Initialize HTML classes.
*/ */
static initialize(): void { static initialize(): void {
CoreDomUtils.toggleModeClass('ionic8', true); CoreHTMLClasses.toggleModeClass('ionic8', true);
CoreDomUtils.toggleModeClass('development', CoreConstants.BUILD.isDevelopment); CoreHTMLClasses.toggleModeClass('development', CoreConstants.BUILD.isDevelopment);
CoreHTMLClasses.addVersionClass(MOODLEAPP_VERSION_PREFIX, CoreConstants.CONFIG.versionname.replace('-dev', '')); CoreHTMLClasses.addVersionClass(
CoreHTMLClasses.MOODLEAPP_VERSION_PREFIX,
CoreConstants.CONFIG.versionname.replace('-dev', ''),
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const win = <any> window; const win = <any> window;
@ -72,9 +74,9 @@ export class CoreHTMLClasses {
parts[1] = parts[1] || '0'; parts[1] = parts[1] || '0';
parts[2] = parts[2] || '0'; parts[2] = parts[2] || '0';
CoreDomUtils.toggleModeClass(prefix + parts[0], true); CoreHTMLClasses.toggleModeClass(prefix + parts[0], true);
CoreDomUtils.toggleModeClass(prefix + parts[0] + '-' + parts[1], true); CoreHTMLClasses.toggleModeClass(prefix + parts[0] + '-' + parts[1], true);
CoreDomUtils.toggleModeClass(prefix + parts[0] + '-' + parts[1] + '-' + parts[2], true); CoreHTMLClasses.toggleModeClass(prefix + parts[0] + '-' + parts[1] + '-' + parts[2], true);
} }
/** /**
@ -83,12 +85,12 @@ export class CoreHTMLClasses {
* @param prefixes Prefixes of the class mode to be removed. * @param prefixes Prefixes of the class mode to be removed.
*/ */
protected static removeModeClasses(prefixes: string[]): void { protected static removeModeClasses(prefixes: string[]): void {
for (const modeClass of CoreDomUtils.getModeClasses()) { for (const modeClass of CoreHTMLClasses.getModeClasses()) {
if (!prefixes.some((prefix) => modeClass.startsWith(prefix))) { if (!prefixes.some((prefix) => modeClass.startsWith(prefix))) {
continue; continue;
} }
CoreDomUtils.toggleModeClass(modeClass, false); CoreHTMLClasses.toggleModeClass(modeClass, false);
} }
} }
@ -101,11 +103,11 @@ export class CoreHTMLClasses {
// Add version classes to html tag. // Add version classes to html tag.
this.removeSiteClasses(); this.removeSiteClasses();
this.addVersionClass(MOODLE_VERSION_PREFIX, CoreSites.getReleaseNumber(siteInfo.release || '')); this.addVersionClass(CoreHTMLClasses.MOODLE_VERSION_PREFIX, CoreSites.getReleaseNumber(siteInfo.release || ''));
this.addSiteUrlClass(siteInfo.siteurl); this.addSiteUrlClass(siteInfo.siteurl);
if (siteInfo.theme) { if (siteInfo.theme) {
CoreDomUtils.toggleModeClass(MOODLE_SITE_THEME_PREFIX + siteInfo.theme, true); CoreHTMLClasses.toggleModeClass(CoreHTMLClasses.MOODLE_SITE_THEME_PREFIX + siteInfo.theme, true);
} }
} }
@ -115,7 +117,11 @@ export class CoreHTMLClasses {
static removeSiteClasses(): void { static removeSiteClasses(): void {
// Remove version classes from html tag. // Remove version classes from html tag.
this.removeModeClasses( this.removeModeClasses(
[MOODLE_VERSION_PREFIX, MOODLE_SITE_URL_PREFIX, MOODLE_SITE_THEME_PREFIX], [
CoreHTMLClasses.MOODLE_VERSION_PREFIX,
CoreHTMLClasses.MOODLE_SITE_URL_PREFIX,
CoreHTMLClasses.MOODLE_SITE_THEME_PREFIX,
],
); );
} }
@ -157,7 +163,39 @@ export class CoreHTMLClasses {
static addSiteUrlClass(siteUrl: string): void { static addSiteUrlClass(siteUrl: string): void {
const className = this.urlToClassName(siteUrl); const className = this.urlToClassName(siteUrl);
CoreDomUtils.toggleModeClass(MOODLE_SITE_URL_PREFIX + className, true); CoreHTMLClasses.toggleModeClass(CoreHTMLClasses.MOODLE_SITE_URL_PREFIX + className, true);
}
/**
* Check whether a CSS class indicating an app mode is set.
*
* @param className Class name.
* @returns Whether the CSS class is set.
*/
static hasModeClass(className: string): boolean {
return document.documentElement.classList.contains(className);
}
/**
* Get active mode CSS classes.
*
* @returns Mode classes.
*/
static getModeClasses(): string[] {
return Array.from(document.documentElement.classList);
}
/**
* Toggle a CSS class in the root element used to indicate app modes.
*
* @param className Class name.
* @param enable Whether to add or remove the class.
*/
static toggleModeClass(
className: string,
enable = false,
): void {
document.documentElement.classList.toggle(className, enable);
} }
} }

View File

@ -16,7 +16,7 @@ import { Clipboard, Translate } from '@singletons';
import { CoreToasts } from '@services/toasts'; import { CoreToasts } from '@services/toasts';
import { Locutus } from './locutus'; import { Locutus } from './locutus';
import { CoreError } from '@classes/errors/error'; import { CoreError } from '@classes/errors/error';
import { convertHTMLToHTMLElement } from '../utils/create-html-element'; import { convertTextToHTMLElement } from '../utils/create-html-element';
/** /**
* Singleton with helper functions for text manipulation. * Singleton with helper functions for text manipulation.
@ -190,7 +190,7 @@ export class CoreText {
// First, we use a regexpr. // First, we use a regexpr.
text = text.replace(/(<([^>]+)>)/ig, ''); text = text.replace(/(<([^>]+)>)/ig, '');
// Then, we rely on the browser. We need to wrap the text to be sure is HTML. // Then, we rely on the browser. We need to wrap the text to be sure is HTML.
text = convertHTMLToHTMLElement(text).textContent || ''; text = convertTextToHTMLElement(text).textContent || '';
// Trim text // Trim text
text = options.trim ? text.trim() : text; text = options.trim ? text.trim() : text;
// Recover or remove new lines. // Recover or remove new lines.
@ -229,7 +229,7 @@ export class CoreText {
*/ */
static decodeHTMLEntities(text: string): string { static decodeHTMLEntities(text: string): string {
if (text) { if (text) {
text = convertHTMLToHTMLElement(text).textContent || ''; text = convertTextToHTMLElement(text).textContent || '';
} }
return text; return text;
@ -424,7 +424,7 @@ export class CoreText {
* @returns Processed HTML string. * @returns Processed HTML string.
*/ */
static processHTML(text: string, process: (element: HTMLElement) => unknown): string { static processHTML(text: string, process: (element: HTMLElement) => unknown): string {
const element = convertHTMLToHTMLElement(text); const element = convertTextToHTMLElement(text);
process(element); process(element);

View File

@ -21,7 +21,7 @@ export const CoreTemplateElement: HTMLTemplateElement = document.createElement('
* @param html Text to convert. * @param html Text to convert.
* @returns Element. * @returns Element.
*/ */
export function convertHTMLToHTMLElement(html: string): HTMLElement { export function convertTextToHTMLElement(html: string): HTMLElement {
// Add a div to hold the content, that's the element that will be returned. // Add a div to hold the content, that's the element that will be returned.
CoreTemplateElement.innerHTML = '<div>' + html + '</div>'; CoreTemplateElement.innerHTML = '<div>' + html + '</div>';