diff --git a/src/addons/block/activitymodules/components/activitymodules/activitymodules.scss b/src/addons/block/activitymodules/components/activitymodules/activitymodules.scss index c2aba2a65..7f0ff5973 100644 --- a/src/addons/block/activitymodules/components/activitymodules/activitymodules.scss +++ b/src/addons/block/activitymodules/components/activitymodules/activitymodules.scss @@ -1,7 +1,7 @@ :host { core-mod-icon { - background: transparent; margin: 0; - --filter: var(--module-icon-filter); + --padding-start: 0px; + --module-icon-size: 24px; } } diff --git a/src/addons/block/activitymodules/components/activitymodules/addon-block-activitymodules.html b/src/addons/block/activitymodules/components/activitymodules/addon-block-activitymodules.html index ca35ca46c..9f27b55a7 100644 --- a/src/addons/block/activitymodules/components/activitymodules/addon-block-activitymodules.html +++ b/src/addons/block/activitymodules/components/activitymodules/addon-block-activitymodules.html @@ -5,7 +5,7 @@ - + {{ entry.name }} diff --git a/src/addons/block/recentlyaccesseditems/components/recentlyaccesseditems/addon-block-recentlyaccesseditems.html b/src/addons/block/recentlyaccesseditems/components/recentlyaccesseditems/addon-block-recentlyaccesseditems.html index c72044e87..1350d18b1 100644 --- a/src/addons/block/recentlyaccesseditems/components/recentlyaccesseditems/addon-block-recentlyaccesseditems.html +++ b/src/addons/block/recentlyaccesseditems/components/recentlyaccesseditems/addon-block-recentlyaccesseditems.html @@ -15,7 +15,7 @@ + [componentId]="item.cmid" [showAlt]="false" [purpose]="item.purpose" [isBranded]="item.branded" /> {{ item.iconTitle }} diff --git a/src/addons/block/timeline/components/events/addon-block-timeline-events.html b/src/addons/block/timeline/components/events/addon-block-timeline-events.html index 5203463f9..470e99f1a 100644 --- a/src/addons/block/timeline/components/events/addon-block-timeline-events.html +++ b/src/addons/block/timeline/components/events/addon-block-timeline-events.html @@ -22,7 +22,7 @@ {{event.timesort * 1000 | coreFormatDate:"strftimetime24" }} + [modname]="event.modulename" [purpose]="event.purpose" [isBranded]="event.branded" />

diff --git a/src/addons/block/timeline/components/events/events.scss b/src/addons/block/timeline/components/events/events.scss index 68e7378f5..21fae2d8d 100644 --- a/src/addons/block/timeline/components/events/events.scss +++ b/src/addons/block/timeline/components/events/events.scss @@ -23,7 +23,7 @@ h4.core-bold { } core-mod-icon { - --padding: 8px; + --module-legacy-icon-padding: 8px; --margin-end: 0.5rem; --margin-vertical: 0; } diff --git a/src/addons/calendar/components/upcoming-events/addon-calendar-upcoming-events.html b/src/addons/calendar/components/upcoming-events/addon-calendar-upcoming-events.html index 1224e95ef..2f8717d00 100644 --- a/src/addons/calendar/components/upcoming-events/addon-calendar-upcoming-events.html +++ b/src/addons/calendar/components/upcoming-events/addon-calendar-upcoming-events.html @@ -8,7 +8,7 @@ + [componentId]="event.instance" [showAlt]="false" [purpose]="event.purpose" [isBranded]="event.branded" />

- + diff --git a/src/addons/competency/pages/coursecompetencies/coursecompetencies.html b/src/addons/competency/pages/coursecompetencies/coursecompetencies.html index 1547cbb80..e30894d53 100644 --- a/src/addons/competency/pages/coursecompetencies/coursecompetencies.html +++ b/src/addons/competency/pages/coursecompetencies/coursecompetencies.html @@ -119,7 +119,8 @@

- + diff --git a/src/addons/mod/assign/tests/behat/snapshots/test-basic-usage-of-assignment-activity-in-app-editadd-submission-online-text--add-new-attempt-from-previous-submission--submit-for-grading_8.png b/src/addons/mod/assign/tests/behat/snapshots/test-basic-usage-of-assignment-activity-in-app-editadd-submission-online-text--add-new-attempt-from-previous-submission--submit-for-grading_8.png index 29044218a..9b1bb6e76 100644 Binary files a/src/addons/mod/assign/tests/behat/snapshots/test-basic-usage-of-assignment-activity-in-app-editadd-submission-online-text--add-new-attempt-from-previous-submission--submit-for-grading_8.png and b/src/addons/mod/assign/tests/behat/snapshots/test-basic-usage-of-assignment-activity-in-app-editadd-submission-online-text--add-new-attempt-from-previous-submission--submit-for-grading_8.png differ diff --git a/src/addons/mod/forum/tests/behat/snapshots/test-basic-usage-of-forum-activity-in-app-reply-a-post_9.png b/src/addons/mod/forum/tests/behat/snapshots/test-basic-usage-of-forum-activity-in-app-reply-a-post_9.png index e801c2db6..74563dbfb 100644 Binary files a/src/addons/mod/forum/tests/behat/snapshots/test-basic-usage-of-forum-activity-in-app-reply-a-post_9.png and b/src/addons/mod/forum/tests/behat/snapshots/test-basic-usage-of-forum-activity-in-app-reply-a-post_9.png differ diff --git a/src/addons/notifications/notifications.scss b/src/addons/notifications/notifications.scss index 9dc8d2b0b..120128ebe 100644 --- a/src/addons/notifications/notifications.scss +++ b/src/addons/notifications/notifications.scss @@ -1,17 +1,17 @@ @use "theme/globals" as *; :host { - --extra-icon-size: 16px; - --icon-size: 24px; + --icon-size: 32px; + --core-avatar-size: var(--icon-size); + --extra-icon-size: 12px; ::ng-deep core-user-avatar { - .core-avatar-extra-img, - core-mod-icon { + .core-avatar-extra-img { margin: 0 !important; position: absolute; right: -4px; bottom: -4px; - --padding: 0.2rem; + --module-icon-padding: 0.2rem; } .core-avatar-extra-img { @@ -20,37 +20,34 @@ img { max-width: var(--extra-icon-size); max-height: var(--extra-icon-size); + width: var(--extra-icon-size); + height: var(--extra-icon-size); display: block; } } - - core-mod-icon { - --size: var(--extra-icon-size); - } } div.core-notification-icon { + max-width: var(--icon-size); + max-height: var(--icon-size); img { width: var(--icon-size); - height: var(--icon-size); + height: var(--icon-size); } ion-icon { font-size: var(--icon-size); } - padding: 0.7rem; + padding: 0px; background: var(--background-color); border-radius: var(--radius-xs); - } - - .core-notification-icon { - --module-icon-size: var(--icon-size); @include margin(6px, 8px, 6px, 0px); } .core-notification-img { @include margin(6px, 8px, 6px, 0px); - width: var(--core-avatar-size); - height: var(--core-avatar-size); + width: var(--icon-size); + height: var(--icon-size); object-fit: cover; + border-radius: var(--core-avatar-radius); } } diff --git a/src/addons/notifications/pages/list/list.html b/src/addons/notifications/pages/list/list.html index 3229c1e11..7dc5ec95c 100644 --- a/src/addons/notifications/pages/list/list.html +++ b/src/addons/notifications/pages/list/list.html @@ -41,7 +41,7 @@ [profileUrl]="notification.profileimageurlfrom" [fullname]="notification.userfromfullname" [userId]="notification.useridfrom">
- +
diff --git a/src/addons/notifications/pages/list/list.scss b/src/addons/notifications/pages/list/list.scss index 518d05627..979f8c2d8 100644 --- a/src/addons/notifications/pages/list/list.scss +++ b/src/addons/notifications/pages/list/list.scss @@ -1,6 +1,7 @@ @use "theme/globals" as *; ion-item.addon-notification-item { + ion-label { margin-top: 8px; margin-bottom: 8px; @@ -32,17 +33,6 @@ ion-item.addon-notification-item { align-self: start; margin-top: 16px; } - - --icon-size: 16px; - --extra-icon-size: 12px; - --core-avatar-size: 32px; - - div.core-notification-icon, - core-mod-icon.core-notification-icon { - --padding: 8px; - max-width: var(--core-avatar-size); - max-height: var(--core-avatar-size); - } } .mark-all-as-read { diff --git a/src/addons/notifications/pages/notification/notification.html b/src/addons/notifications/pages/notification/notification.html index b4d6abaff..c6305eda8 100644 --- a/src/addons/notifications/pages/notification/notification.html +++ b/src/addons/notifications/pages/notification/notification.html @@ -16,7 +16,7 @@
- +
diff --git a/src/addons/notifications/pages/notification/notification.scss b/src/addons/notifications/pages/notification/notification.scss index c1c58d5ab..7d6ed4c9c 100644 --- a/src/addons/notifications/pages/notification/notification.scss +++ b/src/addons/notifications/pages/notification/notification.scss @@ -1,6 +1,8 @@ @use "theme/globals" as *; :host { + --icon-size: 44px; + --extra-icon-size: 16px; .core-notification-title { [slot=start] { diff --git a/src/addons/storagemanager/pages/course-storage/course-storage.html b/src/addons/storagemanager/pages/course-storage/course-storage.html index c890ab0dc..5eab17ef1 100644 --- a/src/addons/storagemanager/pages/course-storage/course-storage.html +++ b/src/addons/storagemanager/pages/course-storage/course-storage.html @@ -100,7 +100,8 @@ + [modname]="module.modname" [componentId]="module.instance" [fallbackTranslation]="module.modplural" + [isBranded]="module.branded" />

- -

+ + + + diff --git a/src/core/components/mod-icon/mod-icon.scss b/src/core/components/mod-icon/mod-icon.scss index 5bf78a037..8fe00d913 100644 --- a/src/core/components/mod-icon/mod-icon.scss +++ b/src/core/components/mod-icon/mod-icon.scss @@ -3,70 +3,75 @@ :host { display: inline-block; --size: var(--module-icon-size, 32px); - --padding: var(--module-icon-padding, 8px); + --padding-start: var(--module-icon-padding, 4px); + --padding-top: var(--module-icon-padding, 4px); + --padding-end: var(--module-icon-padding, 4px); + --padding-bottom: var(--module-icon-padding, 4px); --icon-radius: var(--module-icon-radius, var(--radius-xs)); --margin-end: 0px; --margin-vertical: 0px; + min-width: calc(var(--size) + var(--padding-start) + var(--padding-end)); + min-height: calc(var(--size) + var(--padding-top) + var(--padding-bottom)); + margin-top: var(--margin-vertical); margin-bottom: var(--margin-vertical); @include margin-horizontal(null, var(--margin-end)); border-radius: var(--icon-radius); - padding: var(--padding); + @include padding(var(--padding-top), var(--padding-end), var(--padding-bottom), var(--padding-start)); background-color: transparent; line-height: var(--size); - &.version_current { - @each $type, $value in $activity-icon-color-filters { - &.#{$type} { - --filter: var(--activity#{$type}); + --color: var(--text-color); + + &.colorize { + &.version_current { + @each $type, $value in $activity-icon-colors { + &.#{$type} { + --color: var(--activity#{$type}); + } } } - img { - filter: var(--filter, brightness(0) invert(1)); - } - } + &.version_40 { + background-color: var(--gray-100); - &.version_40 { - --size: var(--module-icon-size, 24px); - background-color: $gray-100; + --color: white; - @each $type, $value in $activity-icon-background-colors { - &.#{$type} { - background-color: var(--activity-40-#{$type}); - img { - filter: var(--filter, brightness(0) invert(1)); + @each $type, $value in $activity-icon-background-colors { + &.#{$type} { + background-color: var(--activity-40-#{$type}); } } } } + &.version_40, &.version_legacy { - --size: var(--module-icon-size, 24px); - --filter: none; - background-color: $gray-100; + --size: var(--module-legacy-icon-size, 24px); + --padding-start: var(--module-legacy-icon-padding, 8px); + --padding-top: var(--module-legacy-icon-padding, 8px); + --padding-end: var(--module-legacy-icon-padding, 8px); + --padding-bottom: var(--module-legacy-icon-padding, 8px); } - &.no-filter { - --filter: none !important; + &:not(.branded) { + ::ng-deep svg, + ::ng-deep svg * { + fill: var(--color); + } } -} -img { - width: var(--size); - height: var(--size); - max-width: var(--size); - max-height: var(--size); - min-width: var(--size); - min-height: var(--size); - vertical-align: top; - - &[alt] { - text-indent: -999999px; - white-space: nowrap; - overflow: hidden; + img, + ::ng-deep svg { + width: var(--size); + height: var(--size); + max-width: var(--size); + max-height: var(--size); + min-width: var(--size); + min-height: var(--size); + vertical-align: top; } } diff --git a/src/core/components/mod-icon/mod-icon.ts b/src/core/components/mod-icon/mod-icon.ts index 0318d0d79..8ce84db68 100644 --- a/src/core/components/mod-icon/mod-icon.ts +++ b/src/core/components/mod-icon/mod-icon.ts @@ -16,9 +16,14 @@ import { CoreConstants, ModPurpose } from '@/core/constants'; import { Component, ElementRef, HostBinding, Input, OnChanges, OnInit, SimpleChange } from '@angular/core'; import { CoreCourse } from '@features/course/services/course'; import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; +import { CoreFile } from '@services/file'; +import { CoreFileHelper } from '@services/file-helper'; import { CoreSites } from '@services/sites'; import { CoreTextUtils } from '@services/utils/text'; import { CoreUrlUtils } from '@services/utils/url'; +import { CoreUtils } from '@services/utils/utils'; +import { Http } from '@singletons'; +import { firstValueFrom } from 'rxjs'; const assetsPath = 'assets/img/'; const fallbackModName = 'external-tool'; @@ -39,30 +44,46 @@ const enum IconVersion { }) export class CoreModIconComponent implements OnInit, OnChanges { - @HostBinding('class.no-filter') noFilter = false; - @Input() modname = ''; // The module name. Used also as component if set. @Input() fallbackTranslation = ''; // Fallback translation string if cannot auto translate. @Input() componentId?: number; // Component Id for external icons. @Input() modicon?: string; // Module icon url or local url. @Input() showAlt = true; // Show alt otherwise it's only presentation icon. @Input() purpose: ModPurpose = ModPurpose.MOD_PURPOSE_OTHER; // Purpose of the module. + @Input() @HostBinding('class.colorize') colorize = true; // Colorize the icon. Only applies on 4.0 onwards. + @Input() @HostBinding('class.branded') isBranded?: boolean; // If icon is branded and no colorize will be applied. - icon = ''; + @HostBinding('attr.role') + get getRole(): string | null { + return !this.showAlt ? 'presentation' : null; + } + + @HostBinding('attr.aria-label') + get getAriaLabel(): string { + return this.showAlt ? this.modNameTranslated : ''; + } + + iconUrl = ''; modNameTranslated = ''; - isLocalUrl = true; + isLocalUrl = false; linkIconWithComponent = false; + loaded = false; - @HostBinding('class') iconVersion = 'legacy'; + protected iconVersion: IconVersion = IconVersion.LEGACY_VERSION; + protected purposeClass = ''; + protected element: HTMLElement; - constructor(protected el: ElementRef) { } + constructor(element: ElementRef) { + this.element = element.nativeElement; + } /** * @inheritdoc */ async ngOnInit(): Promise { this.iconVersion = this.getIconVersion(); + this.element.classList.add(this.iconVersion); if (!this.modname && this.modicon) { // Guess module from the icon url. @@ -70,32 +91,9 @@ export class CoreModIconComponent implements OnInit, OnChanges { } this.modNameTranslated = CoreCourse.translateModuleName(this.modname, this.fallbackTranslation); - if (this.iconVersion !== IconVersion.LEGACY_VERSION) { - let purposeClass = - CoreCourseModuleDelegate.supportsFeature( - this.modname || '', - CoreConstants.FEATURE_MOD_PURPOSE, - this.purpose, - ); - - if (this.iconVersion === IconVersion.VERSION_4_0) { - if (purposeClass === ModPurpose.MOD_PURPOSE_INTERACTIVECONTENT) { - // Interactive content was introduced on 4.4, on previous versions CONTENT is used instead. - purposeClass = ModPurpose.MOD_PURPOSE_CONTENT; - } - - if (this.modname === 'lti') { - // LTI had content purpose with 4.0 icons. - purposeClass = ModPurpose.MOD_PURPOSE_CONTENT; - } - } - - if (purposeClass) { - const element: HTMLElement = this.el.nativeElement; - element.classList.add(purposeClass); - } - } + this.setIsBranded(); + this.setPurposeClass(); await this.setIcon(); } @@ -109,12 +107,70 @@ export class CoreModIconComponent implements OnInit, OnChanges { } } + /** + * Sets the isBranded property when undefined. + * + * @returns wether the icon does not need to be filtered. + */ + protected async setIsBranded(): Promise { + if (!this.colorize || this.isBranded !== undefined) { + // It doesn't matter. + return; + } + + // Earlier 4.0, icons were never colorized. + if (this.iconVersion === IconVersion.LEGACY_VERSION) { + this.colorize = false; + + return; + } + + // No icon or local icon (not legacy), colorize it. + if (!this.iconUrl || this.isLocalUrl) { + this.isBranded = false; + + return; + } + + this.iconUrl = CoreTextUtils.decodeHTMLEntities(this.iconUrl); + + // If it's an Moodle Theme icon, check if filtericon is set and use it. + if (this.iconUrl && CoreUrlUtils.isThemeImageUrl(this.iconUrl)) { + const iconParams = CoreUrlUtils.extractUrlParams(this.iconUrl); + if (iconParams['filtericon'] === '1') { + this.isBranded = false; + + return; + } + + // filtericon was introduced in 4.2 and backported to 4.1.3 and 4.0.8. + if (this.modname && !CoreSites.getCurrentSite()?.isVersionGreaterEqualThan(['4.0.8', '4.1.3', '4.2'])) { + // If version is prior to that, check if the url is a module icon and filter it. + if (this.getComponentNameFromIconUrl(this.iconUrl) === this.modname) { + this.isBranded = false; + + return; + } + } + } + + // External icons, or non monologo, do not filter. + this.isBranded = true; + } + /** * Set icon. */ async setIcon(): Promise { - this.icon = this.modicon || this.icon; - this.isLocalUrl = this.icon.startsWith(assetsPath); + this.iconUrl = this.modicon || this.iconUrl; + + if (!this.iconUrl) { + this.loadFallbackIcon(); + + return; + } + + this.isLocalUrl = this.iconUrl.startsWith(assetsPath); // Cache icon if the url is not the theme generic one. // If modname is not set icon won't be cached. @@ -123,62 +179,31 @@ export class CoreModIconComponent implements OnInit, OnChanges { !!this.modname && !!this.componentId && !this.isLocalUrl && - this.getComponentNameFromIconUrl(this.icon) != this.modname; + this.getComponentNameFromIconUrl(this.iconUrl) != this.modname; - this.noFilter = await this.getIconNoFilter(); + await this.setSVGIcon(); } /** * Icon to load on error. */ async loadFallbackIcon(): Promise { + if (this.isLocalUrl) { + return; + } + this.isLocalUrl = true; + this.linkIconWithComponent = false; + const moduleName = !this.modname || CoreCourse.CORE_MODULES.indexOf(this.modname) < 0 ? fallbackModName : this.modname; const path = CoreCourse.getModuleIconsPath(); - this.icon = path + moduleName + '.svg'; - this.noFilter = await this.getIconNoFilter(); - } + this.iconUrl = path + moduleName + '.svg'; - /** - * Returns if the icon does not need to be filtered. - * - * @returns wether the icon does not need to be filtered. - */ - protected async getIconNoFilter(): Promise { - // Earlier 4.0, icons were never filtered. - if (this.iconVersion === IconVersion.LEGACY_VERSION) { - return true; - } - - // No icon or local icon (not legacy), filter it. - if (!this.icon || this.isLocalUrl) { - return await CoreCourseModuleDelegate.moduleIconIsBranded(this.modname); - } - - this.icon = CoreTextUtils.decodeHTMLEntities(this.icon); - - // If it's an Moodle Theme icon, check if filtericon is set and use it. - if (this.icon && CoreUrlUtils.isThemeImageUrl(this.icon)) { - const iconParams = CoreUrlUtils.extractUrlParams(this.icon); - if (iconParams['filtericon'] === '1') { - return false; - } - - // filtericon was introduced in 4.2 and backported to 4.1.3 and 4.0.8. - if (this.modname && !CoreSites.getCurrentSite()?.isVersionGreaterEqualThan(['4.0.8', '4.1.3', '4.2'])) { - // If version is prior to that, check if the url is a module icon and filter it. - if (this.getComponentNameFromIconUrl(this.icon) === this.modname) { - return false; - } - } - } - - // External icons, or non monologo, do not filter. - return true; + await this.setSVGIcon(); } /** @@ -188,7 +213,7 @@ export class CoreModIconComponent implements OnInit, OnChanges { * @returns Guessed modname. */ protected getComponentNameFromIconUrl(iconUrl: string): string { - if (!CoreUrlUtils.isThemeImageUrl(this.icon)) { + if (!CoreUrlUtils.isThemeImageUrl(this.iconUrl)) { // Cannot be guessed. return ''; } @@ -213,6 +238,38 @@ export class CoreModIconComponent implements OnInit, OnChanges { return component; } + /** + * Set the purpose class. + */ + protected setPurposeClass(): void { + if (this.iconVersion === IconVersion.LEGACY_VERSION) { + return; + } + + this.purposeClass = + CoreCourseModuleDelegate.supportsFeature( + this.modname || '', + CoreConstants.FEATURE_MOD_PURPOSE, + this.purpose, + ); + + if (this.iconVersion === IconVersion.VERSION_4_0) { + if (this.purposeClass === ModPurpose.MOD_PURPOSE_INTERACTIVECONTENT) { + // Interactive content was introduced on 4.4, on previous versions CONTENT is used instead. + this.purposeClass = ModPurpose.MOD_PURPOSE_CONTENT; + } + + if (this.modname === 'lti') { + // LTI had content purpose with 4.0 icons. + this.purposeClass = ModPurpose.MOD_PURPOSE_CONTENT; + } + } + + if (this.purposeClass) { + this.element.classList.add(this.purposeClass); + } + } + /** * Get the icon version depending on site version. * @@ -232,4 +289,103 @@ export class CoreModIconComponent implements OnInit, OnChanges { return IconVersion.CURRENT_VERSION; } + /** + * Sets SVG markup for the icon (if the URL is an SVG). + * + * @returns Promise resolved when done. + */ + protected async setSVGIcon(): Promise { + if (this.iconVersion === IconVersion.LEGACY_VERSION) { + this.loaded = true; + + return; + } + + this.loaded = false; + + let mimetype = ''; + let fileContents = ''; + + // Download the icon if it's not local to cache it. + if (!this.isLocalUrl) { + try { + const iconUrl = await CoreFileHelper.downloadFile( + this.iconUrl, + this.linkIconWithComponent ? this.modname : undefined, + this.linkIconWithComponent ? this.componentId : undefined, + ); + if (iconUrl) { + mimetype = await CoreUtils.getMimeTypeFromUrl(iconUrl); + fileContents = await CoreFile.readFile(iconUrl); + } + } catch { + // Ignore errors. + } + } + + try { + + if (!fileContents) { + // Try to download the icon directly (also for local files). + const response = await firstValueFrom(Http.get( + this.iconUrl, + { + observe: 'response', + responseType: 'text', + }, + )); + mimetype = response.headers.get('content-type') || mimetype; + fileContents = response.body || ''; + } + + if (mimetype !== 'image/svg+xml' || !fileContents) { + return; + } + + // Clean the DOM to avoid security issues. + const parser = new DOMParser(); + const doc = parser.parseFromString(fileContents, 'image/svg+xml'); + + // Safety check. + if (doc.documentElement.nodeName !== 'svg') { + return; + } + + // Remove scripts tags. + const scripts = doc.documentElement.getElementsByTagName('script'); + for (let i = scripts.length - 1; i >= 0; i--) { + scripts[i].parentNode?.removeChild(scripts[i]); + } + + // Recursively remove attributes starting with on. + const removeAttributes = (element: Element): void => { + Array.from(element.attributes).forEach((attr) => { + if (attr.name.startsWith('on')) { + element.removeAttribute(attr.name); + } + }); + + Array.from(element.children).forEach((child) => { + removeAttributes(child); + }); + }; + removeAttributes(doc.documentElement); + + // Add viewBox to avoid scaling issues. + if (!doc.documentElement.getAttribute('viewBox')) { + const width = doc.documentElement.getAttribute('width'); + const height = doc.documentElement.getAttribute('height'); + if (width && height) { + doc.documentElement.setAttribute('viewBox', '0 0 '+ width + ' ' + height); + } + } + + this.element.replaceChildren(doc.documentElement); + } catch { + // Ignore errors. + } finally { + this.loaded = true; + } + } + } diff --git a/src/core/features/course/components/module-info/core-course-module-info.html b/src/core/features/course/components/module-info/core-course-module-info.html index b72768c72..eb5ff2400 100644 --- a/src/core/features/course/components/module-info/core-course-module-info.html +++ b/src/core/features/course/components/module-info/core-course-module-info.html @@ -1,6 +1,7 @@ - - + +

diff --git a/src/core/features/course/components/module-info/course-module-info.scss b/src/core/features/course/components/module-info/course-module-info.scss index 013704204..246932f5c 100644 --- a/src/core/features/course/components/module-info/course-module-info.scss +++ b/src/core/features/course/components/module-info/course-module-info.scss @@ -10,8 +10,16 @@ core-mod-icon { align-self: flex-start; - --padding: 4px; @include margin-horizontal(null, 8px); + + --module-icon-padding: 0px; + --module-legacy-icon-padding: 4px; + } + + ion-label.core-module-info-activity-title { + margin-top: 12px; + margin-bottom: 12px; + line-height: 32px; } h1 ion-icon { diff --git a/src/core/features/course/components/module-summary/module-summary.html b/src/core/features/course/components/module-summary/module-summary.html index 1ff9d229d..f1e8cdc70 100644 --- a/src/core/features/course/components/module-summary/module-summary.html +++ b/src/core/features/course/components/module-summary/module-summary.html @@ -15,7 +15,7 @@

+ [fallbackTranslation]="module.modplural" [purpose]="module.purpose" [isBranded]="module.branded" /> {{moduleNameTranslated}}

diff --git a/src/core/features/course/components/module-summary/module-summary.scss b/src/core/features/course/components/module-summary/module-summary.scss index 3594fb7eb..6b2c74d6b 100644 --- a/src/core/features/course/components/module-summary/module-summary.scss +++ b/src/core/features/course/components/module-summary/module-summary.scss @@ -10,16 +10,20 @@ h1 { .core-modulename { text-transform: uppercase; + core-mod-icon { - --padding: 3px; - --size: 10px; - margin: 0; + --module-icon-padding: 0px; + --module-legacy-icon-padding: 2px; + --module-icon-size: 16px; + --module-legacy-icon-size: 12px; + + margin: 0px; } } ion-item ion-label ion-icon { - @include margin-horizontal(0, 4px); + @include margin-horizontal(0px, 4px); vertical-align: text-top; } diff --git a/src/core/features/course/components/module/core-course-module.html b/src/core/features/course/components/module/core-course-module.html index cbcfd1daa..1a296ac1b 100644 --- a/src/core/features/course/components/module/core-course-module.html +++ b/src/core/features/course/components/module/core-course-module.html @@ -8,7 +8,8 @@
+ [componentId]="module.instance" [fallbackTranslation]="module.modplural" [purpose]="module.purpose" + [isBranded]="module.branded" />

+ [modname]="row.itemmodule" [colorize]="false" /> diff --git a/src/core/features/grades/pages/course/course.scss b/src/core/features/grades/pages/course/course.scss index a767571c3..ef6808d2b 100644 --- a/src/core/features/grades/pages/course/course.scss +++ b/src/core/features/grades/pages/course/course.scss @@ -43,10 +43,10 @@ table.core-table.core-grades-table { } core-mod-icon { - --padding: 0px; - --size: 16px; - background: transparent; - --filter: var(--module-icon-filter); + --module-icon-padding: 0px; + --module-legacy-icon-padding: 0px; + --module-icon-size: 16px; + --module-legacy-icon-size: 16px; } ion-icon { diff --git a/src/core/features/search/components/global-search-result/global-search-result.html b/src/core/features/search/components/global-search-result/global-search-result.html index 88238eec1..b1cc66ea8 100644 --- a/src/core/features/search/components/global-search-result/global-search-result.html +++ b/src/core/features/search/components/global-search-result/global-search-result.html @@ -4,8 +4,8 @@