From b0c494ee51008cc379273c0d1e7cc93e2de8578d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Fri, 19 Jul 2024 15:54:15 +0200 Subject: [PATCH] MOBILE-4616 chore: Move html mode classes to CoreHTMLClasses --- .github/workflows/testing.yml | 2 +- .../bigbluebuttonbn/components/index/index.ts | 6 +- .../mod/folder/services/handlers/module.ts | 4 +- .../mod/lesson/services/lesson-helper.ts | 16 ++-- src/addons/mod/lesson/services/lesson.ts | 4 +- src/addons/mod/quiz/services/quiz-helper.ts | 4 +- src/addons/mod/quiz/services/quiz.ts | 4 +- .../services/handlers/calculated.ts | 4 +- .../qtype/essay/services/handlers/essay.ts | 12 +-- .../components/show-password/show-password.ts | 4 +- .../services/handlers/course-tag-area.ts | 4 +- .../features/grades/services/grades-helper.ts | 4 +- .../classes/base-question-component.ts | 6 +- .../question/services/question-helper.ts | 22 +++--- .../settings/services/settings-helper.ts | 5 +- src/core/features/tag/services/tag-helper.ts | 4 +- .../user/services/handlers/tag-area.ts | 4 +- src/core/services/filepool.ts | 4 +- src/core/services/network.ts | 14 ++-- src/core/services/utils/dom.ts | 25 ++++--- src/core/singletons/html-classes.ts | 74 ++++++++++++++----- src/core/singletons/text.ts | 8 +- src/core/utils/create-html-element.ts | 2 +- 23 files changed, 141 insertions(+), 95 deletions(-) diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index d6c708a28..7f710b31b 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -69,7 +69,7 @@ jobs: cat circular-dependencies lines=$(cat circular-dependencies | wc -l) echo "Total circular dependencies: $lines" - test $lines -eq 131 + test $lines -eq 130 - name: JavaScript code compatibility run: | npx check-es-compat www/*.js --polyfills="\{Array,String,TypedArray\}.prototype.at,Object.hasOwn" diff --git a/src/addons/mod/bigbluebuttonbn/components/index/index.ts b/src/addons/mod/bigbluebuttonbn/components/index/index.ts index 29614ff71..2c3e5d53f 100644 --- a/src/addons/mod/bigbluebuttonbn/components/index/index.ts +++ b/src/addons/mod/bigbluebuttonbn/components/index/index.ts @@ -33,7 +33,7 @@ import { } from '../../services/bigbluebuttonbn'; import { ADDON_MOD_BBB_COMPONENT } from '../../constants'; 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. @@ -148,7 +148,7 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo this.recordings = recordingsTable.parsedData.map(recordingData => { 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 => ({ name: playbackAnchor.textContent ?? '', url: playbackAnchor.href, @@ -165,7 +165,7 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo value = CoreTimeUtils.userDate(Number(value), 'core.strftimedaydate'); } else if (columnData.allowHTML && typeof value === 'string') { // If the HTML is empty, don't display it. - const valueElement = convertHTMLToHTMLElement(value); + const valueElement = convertTextToHTMLElement(value); if (!valueElement.querySelector('img') && (valueElement.textContent ?? '').trim() === '') { return; } diff --git a/src/addons/mod/folder/services/handlers/module.ts b/src/addons/mod/folder/services/handlers/module.ts index 4470e98f5..d0603a298 100644 --- a/src/addons/mod/folder/services/handlers/module.ts +++ b/src/addons/mod/folder/services/handlers/module.ts @@ -18,7 +18,7 @@ import { CoreModuleHandlerBase } from '@features/course/classes/module-base-hand import { CoreCourseModuleData } from '@features/course/services/course-helper'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate'; 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 { ADDON_MOD_FOLDER_PAGE_NAME } from '../../constants'; @@ -58,7 +58,7 @@ export class AddonModFolderModuleHandlerService extends CoreModuleHandlerBase im if (module.description) { // 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')) .forEach(element => element.remove()); diff --git a/src/addons/mod/lesson/services/lesson-helper.ts b/src/addons/mod/lesson/services/lesson-helper.ts index 25e014a1a..1bd5c7397 100644 --- a/src/addons/mod/lesson/services/lesson-helper.ts +++ b/src/addons/mod/lesson/services/lesson-helper.ts @@ -28,7 +28,7 @@ import { import { CoreTime } from '@singletons/time'; import { CoreUtils } from '@services/utils/utils'; 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. @@ -47,7 +47,7 @@ export class AddonModLessonHelperProvider { * @returns Formatted data. */ formatActivityLink(activityLink: string): AddonModLessonActivityLink { - const element = convertHTMLToHTMLElement(activityLink); + const element = convertTextToHTMLElement(activityLink); const anchor = element.querySelector('a'); if (!anchor) { @@ -77,7 +77,7 @@ export class AddonModLessonHelperProvider { buttonText: '', content: '', }; - const element = convertHTMLToHTMLElement(html); + const element = convertTextToHTMLElement(html); // Search the input button. const button = element.querySelector('input[type="button"]'); @@ -101,7 +101,7 @@ export class AddonModLessonHelperProvider { */ getPageButtonsFromHtml(html: string): AddonModLessonPageButton[] { const buttons: AddonModLessonPageButton[] = []; - const element = convertHTMLToHTMLElement(html); + const element = convertTextToHTMLElement(html); // Get the container of the buttons if it exists. let buttonsContainer = element.querySelector('.branchbuttoncontainer'); @@ -153,7 +153,7 @@ export class AddonModLessonHelperProvider { */ getPageContentsFromPageData(data: AddonModLessonGetPageDataWSResponse): string { // 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'); if (contents) { @@ -179,7 +179,7 @@ export class AddonModLessonHelperProvider { * @returns Question data. */ 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. const fieldContainer = 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. */ getQuestionPageAnswerDataFromHtml(html: string): AddonModLessonAnswerData { - const element = convertHTMLToHTMLElement(html); + const element = convertTextToHTMLElement(html); // Check if it has a checkbox. let input = element.querySelector('input[type="checkbox"][name*="answer"]'); @@ -589,7 +589,7 @@ export class AddonModLessonHelperProvider { * @returns Feedback without the question text. */ removeQuestionFromFeedback(html: string): string { - const element = convertHTMLToHTMLElement(html); + const element = convertTextToHTMLElement(html); // Remove the question text. CoreDomUtils.removeElement(element, '.generalbox:not(.feedback):not(.correctanswer)'); diff --git a/src/addons/mod/lesson/services/lesson.ts b/src/addons/mod/lesson/services/lesson.ts index dd07e4ae8..b9dcd4105 100644 --- a/src/addons/mod/lesson/services/lesson.ts +++ b/src/addons/mod/lesson/services/lesson.ts @@ -18,7 +18,7 @@ import { CoreSite } from '@classes/sites/site'; import { CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; 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 { CoreUtils } from '@services/utils/utils'; import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws'; @@ -164,7 +164,7 @@ export class AddonModLessonProvider { 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. 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"]'); } diff --git a/src/addons/mod/quiz/services/quiz-helper.ts b/src/addons/mod/quiz/services/quiz-helper.ts index 1113eb95a..d1461a886 100644 --- a/src/addons/mod/quiz/services/quiz-helper.ts +++ b/src/addons/mod/quiz/services/quiz-helper.ts @@ -42,7 +42,7 @@ import { CoreGroups } from '@services/groups'; import { CoreTimeUtils } from '@services/utils/time'; import { CoreModals } from '@services/modals'; 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. @@ -302,7 +302,7 @@ export class AddonModQuizHelperProvider { * @returns Question's mark. */ getQuestionMarkFromHtml(html: string): string | undefined { - const element = convertHTMLToHTMLElement(html); + const element = convertTextToHTMLElement(html); return CoreDomUtils.getContentsOfElement(element, '.grade'); } diff --git a/src/addons/mod/quiz/services/quiz.ts b/src/addons/mod/quiz/services/quiz.ts index 80cdc81ee..7384b276e 100644 --- a/src/addons/mod/quiz/services/quiz.ts +++ b/src/addons/mod/quiz/services/quiz.ts @@ -29,7 +29,7 @@ import { } from '@features/question/services/question'; import { CoreQuestionDelegate } from '@features/question/services/question-delegate'; 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 { CoreUtils } from '@services/utils/utils'; import { CoreStatusWithWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws'; @@ -1588,7 +1588,7 @@ export class AddonModQuizProvider { * @returns Whether it's blocked. */ isQuestionBlocked(question: CoreQuestionQuestionParsed): boolean { - const element = convertHTMLToHTMLElement(question.html); + const element = convertTextToHTMLElement(question.html); return !!element.querySelector('.mod_quiz-blocked_question_warning'); } diff --git a/src/addons/qtype/calculated/services/handlers/calculated.ts b/src/addons/qtype/calculated/services/handlers/calculated.ts index 5c42adc04..5bc610356 100644 --- a/src/addons/qtype/calculated/services/handlers/calculated.ts +++ b/src/addons/qtype/calculated/services/handlers/calculated.ts @@ -16,7 +16,7 @@ import { Injectable, Type } from '@angular/core'; import { CoreQuestionQuestionParsed, CoreQuestionsAnswers } from '@features/question/services/question'; 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 { makeSingleton } from '@singletons'; import { AddonQtypeCalculatedComponent } from '../../component/calculated'; @@ -53,7 +53,7 @@ export class AddonQtypeCalculatedHandlerService implements CoreQuestionHandler { */ hasSeparateUnitField(question: CoreQuestionQuestionParsed): boolean { if (!question.parsedSettings) { - const element = convertHTMLToHTMLElement(question.html); + const element = convertTextToHTMLElement(question.html); return !!(element.querySelector('select[name*=unit]') || element.querySelector('input[type="radio"]')); } diff --git a/src/addons/qtype/essay/services/handlers/essay.ts b/src/addons/qtype/essay/services/handlers/essay.ts index 517317035..cc8166546 100644 --- a/src/addons/qtype/essay/services/handlers/essay.ts +++ b/src/addons/qtype/essay/services/handlers/essay.ts @@ -22,7 +22,7 @@ import { CoreQuestionHandler } from '@features/question/services/question-delega import { CoreQuestionHelper } from '@features/question/services/question-helper'; import { CoreFileSession } from '@services/file-session'; 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 { CoreUtils } from '@services/utils/utils'; 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 { text: !!element.querySelector('textarea[name*=_answer]'), @@ -116,7 +116,7 @@ export class AddonQtypeEssayHandlerService implements CoreQuestionHandler { * @inheritdoc */ getPreventSubmitMessage(question: CoreQuestionQuestionParsed): string | undefined { - const element = convertHTMLToHTMLElement(question.html); + const element = convertTextToHTMLElement(question.html); const uploadFilesSupported = question.responsefileareas !== undefined; if (!uploadFilesSupported && element.querySelector('div[id*=filemanager]')) { @@ -293,7 +293,7 @@ export class AddonQtypeEssayHandlerService implements CoreQuestionHandler { siteId?: string, ): Promise { - const element = convertHTMLToHTMLElement(question.html); + const element = convertTextToHTMLElement(question.html); const attachmentsInput = element.querySelector('.attachments input[name*=_attachments]'); // Search the textarea to get its name. @@ -375,7 +375,7 @@ export class AddonQtypeEssayHandlerService implements CoreQuestionHandler { siteId?: string, ): Promise { - const element = convertHTMLToHTMLElement(question.html); + const element = convertTextToHTMLElement(question.html); const attachmentsInput = element.querySelector('.attachments input[name*=_attachments]'); if (attachmentsInput) { @@ -454,7 +454,7 @@ export class AddonQtypeEssayHandlerService implements CoreQuestionHandler { isPlainText = question.parsedSettings.responseformat == 'monospaced' || question.parsedSettings.responseformat == 'plain'; } else { - const questionEl = convertHTMLToHTMLElement(question.html); + const questionEl = convertTextToHTMLElement(question.html); isPlainText = !!questionEl.querySelector('.qtype_essay_monospaced') || !!questionEl.querySelector('.qtype_essay_plain'); } diff --git a/src/core/components/show-password/show-password.ts b/src/core/components/show-password/show-password.ts index ad01b6273..12ca321ca 100644 --- a/src/core/components/show-password/show-password.ts +++ b/src/core/components/show-password/show-password.ts @@ -14,7 +14,7 @@ import { Component, AfterViewInit, Input, ContentChild, ViewEncapsulation } from '@angular/core'; 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 { CoreLogger } from '@singletons/logger'; @@ -84,7 +84,7 @@ export class CoreShowPasswordComponent implements AfterViewInit { return; } - const toggle = convertHTMLToHTMLElement(''); + const toggle = convertTextToHTMLElement(''); input.parentElement?.appendChild(toggle.children[0]); } diff --git a/src/core/features/course/services/handlers/course-tag-area.ts b/src/core/features/course/services/handlers/course-tag-area.ts index 93cb1dc5c..e6b1de384 100644 --- a/src/core/features/course/services/handlers/course-tag-area.ts +++ b/src/core/features/course/services/handlers/course-tag-area.ts @@ -14,7 +14,7 @@ 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 { CoreCourseTagAreaComponent } from '../../components/tag-area/tag-area'; import { makeSingleton } from '@singletons'; @@ -45,7 +45,7 @@ export class CoreCourseTagAreaHandlerService implements CoreTagAreaHandler { */ parseContent(content: string): CoreCouseTagItems[] { const items: CoreCouseTagItems[] = []; - const element = convertHTMLToHTMLElement(content); + const element = convertTextToHTMLElement(content); Array.from(element.querySelectorAll('div.coursebox')).forEach((coursebox) => { const courseId = parseInt(coursebox.getAttribute('data-courseid') || '', 10); diff --git a/src/core/features/grades/services/grades-helper.ts b/src/core/features/grades/services/grades-helper.ts index be49fb3fd..e7a6b6632 100644 --- a/src/core/features/grades/services/grades-helper.ts +++ b/src/core/features/grades/services/grades-helper.ts @@ -44,7 +44,7 @@ import { CoreCourseHelper } from '@features/course/services/course-helper'; import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; import { CoreCourseAccess } from '@features/course/services/course-options-delegate'; 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_PARTICIPANTS_PAGE_NAME = 'participant-grades'; @@ -574,7 +574,7 @@ export class CoreGradesHelperProvider { const modname = module?.[1]; 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.itemmodule = modname; diff --git a/src/core/features/question/classes/base-question-component.ts b/src/core/features/question/classes/base-question-component.ts index 34085904c..2c7c13cd5 100644 --- a/src/core/features/question/classes/base-question-component.ts +++ b/src/core/features/question/classes/base-question-component.ts @@ -25,7 +25,7 @@ import { CoreLogger } from '@singletons/logger'; import { CoreQuestionBehaviourButton, CoreQuestionHelper, CoreQuestionQuestion } from '../services/question-helper'; import { ContextLevel } from '@/core/constants'; 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. @@ -88,7 +88,7 @@ export class CoreQuestionBaseComponent(contentSelector); diff --git a/src/core/features/question/services/question-helper.ts b/src/core/features/question/services/question-helper.ts index be8afac1e..736d3a625 100644 --- a/src/core/features/question/services/question-helper.ts +++ b/src/core/features/question/services/question-helper.ts @@ -31,7 +31,7 @@ import { CoreUrl } from '@singletons/url'; import { ContextLevel } from '@/core/constants'; import { CoreIonicColorNames } from '@singletons/colors'; 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. @@ -132,7 +132,7 @@ export class CoreQuestionHelperProvider { selector = selector || '.im-controls [type="submit"]'; - const element = convertHTMLToHTMLElement(question.html); + const element = convertTextToHTMLElement(question.html); // Search the buttons. const buttons = Array.from(element.querySelectorAll(selector)); @@ -151,7 +151,7 @@ export class CoreQuestionHelperProvider { * @returns Wether the certainty is found. */ 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"]')); question.behaviourCertaintyOptions = []; @@ -218,7 +218,7 @@ export class CoreQuestionHelperProvider { * @returns Whether the seen input is found. */ extractQbehaviourSeenInput(question: CoreQuestionQuestion): boolean { - const element = convertHTMLToHTMLElement(question.html); + const element = convertTextToHTMLElement(question.html); // Search the "seen" input. const seenInput = 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. */ protected extractQuestionLastElementNotInContent(question: CoreQuestionQuestion, selector: string, attrName: string): void { - const element = convertHTMLToHTMLElement(question.html); + const element = convertTextToHTMLElement(question.html); const matches = Array.from(element.querySelectorAll(selector)); // 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. */ getAllInputNamesFromHtml(html: string): Record { - const element = convertHTMLToHTMLElement('
' + html + '
'); + const element = convertTextToHTMLElement('
' + html + '
'); const form = element.children[0]; const answers: Record = {}; @@ -425,7 +425,7 @@ export class CoreQuestionHelperProvider { * @returns Attachments. */ getQuestionAttachmentsFromHtml(html: string): CoreWSFile[] { - const element = convertHTMLToHTMLElement(html); + const element = convertTextToHTMLElement(html); // Remove the filemanager (area to attach files to a question). CoreDomUtils.removeElement(element, 'div[id*=filemanager]'); @@ -462,7 +462,7 @@ export class CoreQuestionHelperProvider { } // Search the input holding the sequencecheck. - const element = convertHTMLToHTMLElement(html); + const element = convertTextToHTMLElement(html); const input = element.querySelector('input[name*=sequencecheck]'); if (!input || input.name === undefined || input.value === undefined) { @@ -532,7 +532,7 @@ export class CoreQuestionHelperProvider { * @returns Validation error message if present. */ getValidationErrorFromHtml(html: string): string | undefined { - const element = convertHTMLToHTMLElement(html); + const element = convertTextToHTMLElement(html); return CoreDomUtils.getContentsOfElement(element, '.validationerror'); } @@ -584,7 +584,7 @@ export class CoreQuestionHelperProvider { * @param question Question. */ loadLocalAnswersInHtml(question: CoreQuestionQuestion): void { - const element = convertHTMLToHTMLElement('
' + question.html + '
'); + const element = convertTextToHTMLElement('
' + question.html + '
'); const form = element.children[0]; // Search all input elements. @@ -759,7 +759,7 @@ export class CoreQuestionHelperProvider { * @returns Whether the button is found. */ protected searchBehaviourButton(question: CoreQuestionQuestion, htmlProperty: string, selector: string): boolean { - const element = convertHTMLToHTMLElement(question[htmlProperty]); + const element = convertTextToHTMLElement(question[htmlProperty]); const button = element.querySelector(selector); if (!button) { diff --git a/src/core/features/settings/services/settings-helper.ts b/src/core/features/settings/services/settings-helper.ts index de0febbf4..0936acaca 100644 --- a/src/core/features/settings/services/settings-helper.ts +++ b/src/core/features/settings/services/settings-helper.ts @@ -31,6 +31,7 @@ import { CoreError } from '@classes/errors/error'; import { Observable, Subject } from 'rxjs'; import { CoreErrorHelper } from '@services/error-helper'; import { CoreNavigator } from '@services/navigator'; +import { CoreHTMLClasses } from '@singletons/html-classes'; /** * 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. */ protected toggleDarkMode(enable: boolean = false): void { - const isDark = CoreDomUtils.hasModeClass('dark'); + const isDark = CoreHTMLClasses.hasModeClass('dark'); if (isDark !== enable) { - CoreDomUtils.toggleModeClass('dark', enable); + CoreHTMLClasses.toggleModeClass('dark', enable); this.darkModeObservable.next(enable); CoreApp.setSystemUIColors(); diff --git a/src/core/features/tag/services/tag-helper.ts b/src/core/features/tag/services/tag-helper.ts index da1d45ddf..448dcfd59 100644 --- a/src/core/features/tag/services/tag-helper.ts +++ b/src/core/features/tag/services/tag-helper.ts @@ -14,7 +14,7 @@ import { makeSingleton } from '@singletons'; 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. @@ -30,7 +30,7 @@ export class CoreTagHelperProvider { */ parseFeedContent(content: string): CoreTagFeedElement[] { const items: CoreTagFeedElement[] = []; - const element = convertHTMLToHTMLElement(content); + const element = convertTextToHTMLElement(content); Array.from(element.querySelectorAll('ul.tag_feed > li')).forEach((itemElement) => { const item: CoreTagFeedElement = { details: [] }; diff --git a/src/core/features/user/services/handlers/tag-area.ts b/src/core/features/user/services/handlers/tag-area.ts index 9fae87eaf..4e5c6761f 100644 --- a/src/core/features/user/services/handlers/tag-area.ts +++ b/src/core/features/user/services/handlers/tag-area.ts @@ -14,7 +14,7 @@ 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 { CoreUserTagAreaComponent } from '@features/user/components/tag-area/tag-area'; import { CoreTagFeedElement } from '@features/tag/services/tag-helper'; @@ -47,7 +47,7 @@ export class CoreUserTagAreaHandlerService implements CoreTagAreaHandler { */ parseContent(content: string): CoreUserTagFeedElement[] { const items: CoreUserTagFeedElement[] = []; - const element = convertHTMLToHTMLElement(content); + const element = convertTextToHTMLElement(content); Array.from(element.querySelectorAll('div.user-box')).forEach((userbox: HTMLElement) => { const avatarLink = userbox.querySelector('a:first-child'); diff --git a/src/core/services/filepool.ts b/src/core/services/filepool.ts index 77201627a..e0417317f 100644 --- a/src/core/services/filepool.ts +++ b/src/core/services/filepool.ts @@ -58,7 +58,7 @@ import { asyncInstance, AsyncInstance } from '../utils/async-instance'; import { CorePath } from '@singletons/path'; import { CorePromisedValue } from '@classes/promised-value'; 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. @@ -1148,7 +1148,7 @@ export class CoreFilepoolProvider { extractDownloadableFilesFromHtml(html: string): 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')); for (let i = 0; i < elements.length; i++) { diff --git a/src/core/services/network.ts b/src/core/services/network.ts index 3c8cc18f9..35597f4f5 100644 --- a/src/core/services/network.ts +++ b/src/core/services/network.ts @@ -17,7 +17,7 @@ import { CorePlatform } from '@services/platform'; import { Network } from '@awesome-cordova-plugins/network/ngx'; import { NgZone, makeSingleton } from '@singletons'; import { Observable, Subject, merge } from 'rxjs'; -import { CoreDomUtils } from './utils/dom'; +import { CoreHTMLClasses } from '@singletons/html-classes'; export enum CoreNetworkConnection { UNKNOWN = 'unknown', @@ -109,24 +109,24 @@ export class CoreNetworkService extends Network { NgZone.run(() => { 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) { - CoreDomUtils.toggleModeClass('core-online', true); + CoreHTMLClasses.toggleModeClass('core-online', true); setTimeout(() => { - CoreDomUtils.toggleModeClass('core-online', false); + CoreHTMLClasses.toggleModeClass('core-online', false); }, 3000); } else if (!isOnline) { - CoreDomUtils.toggleModeClass('core-online', false); + CoreHTMLClasses.toggleModeClass('core-online', false); } }); }); const isOnline = this.isOnline(); - CoreDomUtils.toggleModeClass('core-offline', !isOnline); + CoreHTMLClasses.toggleModeClass('core-offline', !isOnline); } /** diff --git a/src/core/services/utils/dom.ts b/src/core/services/utils/dom.ts index 2f677a978..f074d20c8 100644 --- a/src/core/services/utils/dom.ts +++ b/src/core/services/utils/dom.ts @@ -55,7 +55,8 @@ import { CorePopovers, OpenPopoverOptions } from '@services/popovers'; import { CoreViewer } from '@features/viewer/services/viewer'; import { CoreLoadings } from '@services/loadings'; 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. @@ -199,7 +200,7 @@ export class CoreDomUtilsProvider { * @deprecated since 4.5. Use convertToElement directly instead. */ convertToElement(html: string): HTMLElement { - return convertHTMLToHTMLElement(html); + return convertTextToHTMLElement(html); } /** @@ -387,7 +388,7 @@ export class CoreDomUtilsProvider { * @returns Attribute value. */ 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. */ removeElementFromHtml(html: string, selector: string, removeAll?: boolean): string { - const element = convertHTMLToHTMLElement(html); + const element = convertTextToHTMLElement(html); if (removeAll) { const selected = element.querySelectorAll(selector); @@ -696,7 +697,7 @@ export class CoreDomUtilsProvider { paths: {[url: string]: string}, anchorFn?: (anchor: HTMLElement, href: string) => void, ): string { - const element = convertHTMLToHTMLElement(html); + const element = convertTextToHTMLElement(html); // Treat elements with src (img, audio, video, ...). const media = Array.from(element.querySelectorAll('img, video, audio, source, track, iframe, embed')); @@ -1399,7 +1400,7 @@ export class CoreDomUtilsProvider { * @returns Same text converted to HTMLCollection. */ toDom(text: string): HTMLCollection { - const element = convertHTMLToHTMLElement(text); + const element = convertTextToHTMLElement(text); return element.children; } @@ -1610,18 +1611,22 @@ export class CoreDomUtilsProvider { * * @param className Class name. * @returns Whether the CSS class is set. + * + * @deprecated since 4.5. Use CoreHTMLClasses.hasModeClass instead. */ hasModeClass(className: string): boolean { - return document.documentElement.classList.contains(className); + return CoreHTMLClasses.hasModeClass(className); } /** * Get active mode CSS classes. * * @returns Mode classes. + * + * @deprecated since 4.5. Use CoreHTMLClasses.getModeClasses instead. */ getModeClasses(): string[] { - return Array.from(document.documentElement.classList); + return CoreHTMLClasses.getModeClasses(); } /** @@ -1629,12 +1634,14 @@ export class CoreDomUtilsProvider { * * @param className Class name. * @param enable Whether to add or remove the class. + * + * @deprecated since 4.5. Use CoreHTMLClasses.toggleModeClass instead. */ toggleModeClass( className: string, enable = false, ): void { - document.documentElement.classList.toggle(className, enable); + CoreHTMLClasses.toggleModeClass(className, enable); } } diff --git a/src/core/singletons/html-classes.ts b/src/core/singletons/html-classes.ts index ff74fda5b..9803f1e19 100644 --- a/src/core/singletons/html-classes.ts +++ b/src/core/singletons/html-classes.ts @@ -14,29 +14,31 @@ import { CoreSiteInfo, CoreSiteInfoResponse } from '@classes/sites/unauthenticated-site'; import { CoreSites } from '@services/sites'; -import { CoreDomUtils } from '@services/utils/dom'; import { CoreUrl } from './url'; import { CoreConstants } from '../constants'; import { ScrollDetail } from '@ionic/angular'; 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. */ 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. */ static initialize(): void { - CoreDomUtils.toggleModeClass('ionic8', true); - CoreDomUtils.toggleModeClass('development', CoreConstants.BUILD.isDevelopment); - CoreHTMLClasses.addVersionClass(MOODLEAPP_VERSION_PREFIX, CoreConstants.CONFIG.versionname.replace('-dev', '')); + CoreHTMLClasses.toggleModeClass('ionic8', true); + CoreHTMLClasses.toggleModeClass('development', CoreConstants.BUILD.isDevelopment); + CoreHTMLClasses.addVersionClass( + CoreHTMLClasses.MOODLEAPP_VERSION_PREFIX, + CoreConstants.CONFIG.versionname.replace('-dev', ''), + ); // eslint-disable-next-line @typescript-eslint/no-explicit-any const win = window; @@ -72,9 +74,9 @@ export class CoreHTMLClasses { parts[1] = parts[1] || '0'; parts[2] = parts[2] || '0'; - CoreDomUtils.toggleModeClass(prefix + parts[0], true); - CoreDomUtils.toggleModeClass(prefix + parts[0] + '-' + parts[1], true); - CoreDomUtils.toggleModeClass(prefix + parts[0] + '-' + parts[1] + '-' + parts[2], true); + CoreHTMLClasses.toggleModeClass(prefix + parts[0], true); + CoreHTMLClasses.toggleModeClass(prefix + parts[0] + '-' + parts[1], 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. */ 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))) { continue; } - CoreDomUtils.toggleModeClass(modeClass, false); + CoreHTMLClasses.toggleModeClass(modeClass, false); } } @@ -101,11 +103,11 @@ export class CoreHTMLClasses { // Add version classes to html tag. 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); 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 { // Remove version classes from html tag. 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 { 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); } } diff --git a/src/core/singletons/text.ts b/src/core/singletons/text.ts index 9520127a5..482ce044a 100644 --- a/src/core/singletons/text.ts +++ b/src/core/singletons/text.ts @@ -16,7 +16,7 @@ import { Clipboard, Translate } from '@singletons'; import { CoreToasts } from '@services/toasts'; import { Locutus } from './locutus'; 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. @@ -190,7 +190,7 @@ export class CoreText { // First, we use a regexpr. text = text.replace(/(<([^>]+)>)/ig, ''); // 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 text = options.trim ? text.trim() : text; // Recover or remove new lines. @@ -229,7 +229,7 @@ export class CoreText { */ static decodeHTMLEntities(text: string): string { if (text) { - text = convertHTMLToHTMLElement(text).textContent || ''; + text = convertTextToHTMLElement(text).textContent || ''; } return text; @@ -424,7 +424,7 @@ export class CoreText { * @returns Processed HTML string. */ static processHTML(text: string, process: (element: HTMLElement) => unknown): string { - const element = convertHTMLToHTMLElement(text); + const element = convertTextToHTMLElement(text); process(element); diff --git a/src/core/utils/create-html-element.ts b/src/core/utils/create-html-element.ts index 2ce0b29cf..60f98e5c2 100644 --- a/src/core/utils/create-html-element.ts +++ b/src/core/utils/create-html-element.ts @@ -21,7 +21,7 @@ export const CoreTemplateElement: HTMLTemplateElement = document.createElement(' * @param html Text to convert. * @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. CoreTemplateElement.innerHTML = '
' + html + '
';