forked from EVOgeek/Vmeda.Online
		
	MOBILE-4309 format-text: Treat font awesome tags to be rendered
This commit is contained in:
		
							parent
							
								
									b60fd49cec
								
							
						
					
					
						commit
						a7df95fd50
					
				| @ -14,12 +14,10 @@ | |||||||
| 
 | 
 | ||||||
| import { AfterViewInit, Directive, ElementRef, Input, OnChanges, SimpleChange } from '@angular/core'; | import { AfterViewInit, Directive, ElementRef, Input, OnChanges, SimpleChange } from '@angular/core'; | ||||||
| import { CoreLogger } from '@singletons/logger'; | import { CoreLogger } from '@singletons/logger'; | ||||||
| import { Http } from '@singletons'; | import { CoreIcons } from '@singletons/icons'; | ||||||
| import { CoreConstants } from '@/core/constants'; |  | ||||||
| import { CorePromisedValue } from '@classes/promised-value'; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Directive to enable font-awesome 6.3 as ionicons. |  * Directive to enable font-awesome 6.4 as ionicons. | ||||||
|  * Check available icons at https://fontawesome.com/search?o=r&m=free
 |  * Check available icons at https://fontawesome.com/search?o=r&m=free
 | ||||||
|  * |  * | ||||||
|  * Example usage: |  * Example usage: | ||||||
| @ -31,13 +29,6 @@ import { CorePromisedValue } from '@classes/promised-value'; | |||||||
| }) | }) | ||||||
| export class CoreFaIconDirective implements AfterViewInit, OnChanges { | export class CoreFaIconDirective implements AfterViewInit, OnChanges { | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * Object used to store whether icons exist or not during development. |  | ||||||
|      */ |  | ||||||
|     private static readonly DEV_ICONS_STATUS: Record<string, Promise<boolean>> = {}; |  | ||||||
| 
 |  | ||||||
|     protected static aliases?: CorePromisedValue<Record<string, string>>; |  | ||||||
| 
 |  | ||||||
|     @Input() name = ''; |     @Input() name = ''; | ||||||
| 
 | 
 | ||||||
|     protected element: HTMLElement; |     protected element: HTMLElement; | ||||||
| @ -95,19 +86,19 @@ export class CoreFaIconDirective implements AfterViewInit, OnChanges { | |||||||
|         iconName = iconName.substring(parts[0].length + 1); |         iconName = iconName.substring(parts[0].length + 1); | ||||||
| 
 | 
 | ||||||
|         // Set it here to avoid loading unexisting icon paths (svg/iconName) caused by the tick delay of the checkIconAlias promise.
 |         // Set it here to avoid loading unexisting icon paths (svg/iconName) caused by the tick delay of the checkIconAlias promise.
 | ||||||
|         let src = `assets/fonts/${font}/${library}/${iconName}.svg`; |         let src = CoreIcons.getIconSrc(font, library, iconName); | ||||||
|         this.element.setAttribute('src', src); |         this.element.setAttribute('src', src); | ||||||
| 
 | 
 | ||||||
|         if (font === 'font-awesome') { |         if (font === 'font-awesome') { | ||||||
|             const iconNameChecked = await this.checkIconAlias(iconName); |             const { fileName } = await CoreIcons.getFontAwesomeIconFileName(iconName); | ||||||
|             if (iconNameChecked !== iconName) { |             if (fileName !== iconName) { | ||||||
|                 src = `assets/fonts/${font}/${library}/${iconName}.svg`; |                 src = CoreIcons.getIconSrc(font, library, fileName); | ||||||
|                 this.element.setAttribute('src', src); |                 this.element.setAttribute('src', src); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         this.element.classList.add('faicon'); |         this.element.classList.add('faicon'); | ||||||
|         this.validateIcon(this.name, src); |         CoreIcons.validateIcon(this.name, src); | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -135,77 +126,4 @@ export class CoreFaIconDirective implements AfterViewInit, OnChanges { | |||||||
|         this.setIcon(); |         this.setIcon(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * Check icon alias and returns the new icon name. |  | ||||||
|      * |  | ||||||
|      * @param iconName Icon name. |  | ||||||
|      * @returns New icon name. |  | ||||||
|      */ |  | ||||||
|     protected async checkIconAlias(iconName: string): Promise<string> { |  | ||||||
|         const aliases = await CoreFaIconDirective.getIconsAliases(); |  | ||||||
| 
 |  | ||||||
|         if (aliases[iconName]) { |  | ||||||
|             this.logger.error(`Icon ${iconName} is an alias of ${aliases[iconName]}, please use the new name.`); |  | ||||||
| 
 |  | ||||||
|             return aliases[iconName]; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return iconName; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Read the icon aliases json file. |  | ||||||
|      * |  | ||||||
|      * @returns Promise resolved when loaded. |  | ||||||
|      */ |  | ||||||
|     protected static async getIconsAliases(): Promise<Record<string, string>> { |  | ||||||
|         if (CoreFaIconDirective.aliases !== undefined) { |  | ||||||
|             return CoreFaIconDirective.aliases; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         CoreFaIconDirective.aliases = new CorePromisedValue(); |  | ||||||
| 
 |  | ||||||
|         try { |  | ||||||
|             const aliases = await Http.get<Record<string, string>>('assets/fonts/font-awesome/aliases.json', { |  | ||||||
|                 responseType: 'json', |  | ||||||
|             }).toPromise(); |  | ||||||
| 
 |  | ||||||
|             CoreFaIconDirective.aliases.resolve(aliases); |  | ||||||
| 
 |  | ||||||
|             return aliases; |  | ||||||
|         } catch { |  | ||||||
|             CoreFaIconDirective.aliases.resolve({}); |  | ||||||
| 
 |  | ||||||
|             return {}; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Validate that an icon exists, or show warning otherwise (only in development and testing environments). |  | ||||||
|      * |  | ||||||
|      * @param name Icon name. |  | ||||||
|      * @param src Icon source url. |  | ||||||
|      */ |  | ||||||
|     private validateIcon(name: string, src: string): void { |  | ||||||
|         if (!CoreConstants.BUILD.isDevelopment && !CoreConstants.BUILD.isTesting) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (!(src in CoreFaIconDirective.DEV_ICONS_STATUS)) { |  | ||||||
|             CoreFaIconDirective.DEV_ICONS_STATUS[src] = Http.get(src, { responseType: 'text' }) |  | ||||||
|                 .toPromise() |  | ||||||
|                 .then(() => true) |  | ||||||
|                 .catch(() => false); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // eslint-disable-next-line promise/catch-or-return
 |  | ||||||
|         CoreFaIconDirective.DEV_ICONS_STATUS[src].then(exists => { |  | ||||||
|             if (exists) { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             return this.logger.error(`Icon ${name} not found`); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -54,6 +54,7 @@ import { ElementController } from '@classes/element-controllers/ElementControlle | |||||||
| import { MediaElementController } from '@classes/element-controllers/MediaElementController'; | import { MediaElementController } from '@classes/element-controllers/MediaElementController'; | ||||||
| import { FrameElementController } from '@classes/element-controllers/FrameElementController'; | import { FrameElementController } from '@classes/element-controllers/FrameElementController'; | ||||||
| import { CoreUrl } from '@singletons/url'; | import { CoreUrl } from '@singletons/url'; | ||||||
|  | import { CoreIcons } from '@singletons/icons'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Directive to format text rendered. It renders the HTML and treats all links and media, using CoreLinkDirective |  * Directive to format text rendered. It renders the HTML and treats all links and media, using CoreLinkDirective | ||||||
| @ -278,10 +279,10 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec | |||||||
|             button.classList.add('core-image-viewer-icon'); |             button.classList.add('core-image-viewer-icon'); | ||||||
|             button.classList.add('hidden'); |             button.classList.add('hidden'); | ||||||
|             button.setAttribute('aria-label', label); |             button.setAttribute('aria-label', label); | ||||||
|  |             const iconName = 'up-right-and-down-left-from-center'; | ||||||
|  |             const src = CoreIcons.getIconSrc('font-awesome', 'solid', iconName); | ||||||
|             // Add an ion-icon item to apply the right styles, but the ion-icon component won't be executed.
 |             // Add an ion-icon item to apply the right styles, but the ion-icon component won't be executed.
 | ||||||
|             button.innerHTML = '<ion-icon name="fas-up-right-and-down-left-from-center" aria-hidden="true" \ |             button.innerHTML = `<ion-icon name="fas-${iconName}" aria-hidden="true" src="${src}"></ion-icon>`; | ||||||
|                 src="assets/fonts/font-awesome/solid/up-right-and-down-left-from-center.svg">\ |  | ||||||
|             </ion-icon>'; |  | ||||||
| 
 | 
 | ||||||
|             button.addEventListener('click', (e: Event) => { |             button.addEventListener('click', (e: Event) => { | ||||||
|                 e.preventDefault(); |                 e.preventDefault(); | ||||||
| @ -478,6 +479,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec | |||||||
|         const videos = Array.from(div.querySelectorAll('video')); |         const videos = Array.from(div.querySelectorAll('video')); | ||||||
|         const iframes = Array.from(div.querySelectorAll('iframe')); |         const iframes = Array.from(div.querySelectorAll('iframe')); | ||||||
|         const buttons = Array.from(div.querySelectorAll('.button')); |         const buttons = Array.from(div.querySelectorAll('.button')); | ||||||
|  |         const icons = Array.from(div.querySelectorAll('i.fa,i.fas,i.far,i.fab')); | ||||||
|         const elementsWithInlineStyles = Array.from(div.querySelectorAll('*[style]')); |         const elementsWithInlineStyles = Array.from(div.querySelectorAll('*[style]')); | ||||||
|         const stopClicksElements = Array.from(div.querySelectorAll('button,input,select,textarea')); |         const stopClicksElements = Array.from(div.querySelectorAll('button,input,select,textarea')); | ||||||
|         const frames = Array.from(div.querySelectorAll(CoreIframeUtilsProvider.FRAME_TAGS.join(',').replace(/iframe,?/, ''))); |         const frames = Array.from(div.querySelectorAll(CoreIframeUtilsProvider.FRAME_TAGS.join(',').replace(/iframe,?/, ''))); | ||||||
| @ -550,6 +552,11 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec | |||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|  |         // Handle Font Awesome icons to be rendered by the app.
 | ||||||
|  |         icons.forEach((icon) => { | ||||||
|  |             CoreIcons.replaceCSSIcon(icon); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|         // Handle inline styles.
 |         // Handle inline styles.
 | ||||||
|         elementsWithInlineStyles.forEach((el: HTMLElement) => { |         elementsWithInlineStyles.forEach((el: HTMLElement) => { | ||||||
|             // Only add external content for tags that haven't been treated already.
 |             // Only add external content for tags that haven't been treated already.
 | ||||||
|  | |||||||
| @ -26,6 +26,7 @@ import { CoreWSFile } from '@services/ws'; | |||||||
| import { makeSingleton, Translate } from '@singletons'; | import { makeSingleton, Translate } from '@singletons'; | ||||||
| import { CoreQuestion, CoreQuestionProvider, CoreQuestionQuestionParsed, CoreQuestionsAnswers } from './question'; | import { CoreQuestion, CoreQuestionProvider, CoreQuestionQuestionParsed, CoreQuestionsAnswers } from './question'; | ||||||
| import { CoreQuestionDelegate } from './question-delegate'; | import { CoreQuestionDelegate } from './question-delegate'; | ||||||
|  | import { CoreIcons } from '@singletons/icons'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Service with some common functions to handle questions. |  * Service with some common functions to handle questions. | ||||||
| @ -801,12 +802,14 @@ export class CoreQuestionHelperProvider { | |||||||
|             const newIcon: HTMLIonIconElement = document.createElement('ion-icon'); |             const newIcon: HTMLIonIconElement = document.createElement('ion-icon'); | ||||||
| 
 | 
 | ||||||
|             if (correct) { |             if (correct) { | ||||||
|                 newIcon.setAttribute('name', 'fas-check'); |                 const iconName = 'check'; | ||||||
|                 newIcon.setAttribute('src', 'assets/fonts/font-awesome/solid/check.svg'); |                 newIcon.setAttribute('name', `fas-${iconName}`); | ||||||
|  |                 newIcon.setAttribute('src', CoreIcons.getIconSrc('font-awesome', 'solid', iconName)); | ||||||
|                 newIcon.className = 'core-correct-icon ion-color ion-color-success questioncorrectnessicon'; |                 newIcon.className = 'core-correct-icon ion-color ion-color-success questioncorrectnessicon'; | ||||||
|             } else { |             } else { | ||||||
|                 newIcon.setAttribute('name', 'fas-xmark'); |                 const iconName = 'xmark'; | ||||||
|                 newIcon.setAttribute('src', 'assets/fonts/font-awesome/solid/xmark.svg'); |                 newIcon.setAttribute('name', `fas-${iconName}`); | ||||||
|  |                 newIcon.setAttribute('src', CoreIcons.getIconSrc('font-awesome', 'solid', iconName)); | ||||||
|                 newIcon.className = 'core-correct-icon ion-color ion-color-danger questioncorrectnessicon'; |                 newIcon.className = 'core-correct-icon ion-color ion-color-danger questioncorrectnessicon'; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										198
									
								
								src/core/singletons/icons.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								src/core/singletons/icons.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,198 @@ | |||||||
|  | // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||||
|  | //
 | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||||
|  | // you may not use this file except in compliance with the License.
 | ||||||
|  | // You may obtain a copy of the License at
 | ||||||
|  | //
 | ||||||
|  | //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||||
|  | //
 | ||||||
|  | // Unless required by applicable law or agreed to in writing, software
 | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||||
|  | // See the License for the specific language governing permissions and
 | ||||||
|  | // limitations under the License.
 | ||||||
|  | 
 | ||||||
|  | import { Http } from '@singletons'; | ||||||
|  | import { CoreConstants } from '../constants'; | ||||||
|  | import { CoreLogger } from './logger'; | ||||||
|  | import aliases from '@/assets/fonts/font-awesome/aliases.json'; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Singleton with helper functions for icon management. | ||||||
|  |  */ | ||||||
|  | export class CoreIcons { | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Object used to store whether icons exist or not during development. | ||||||
|  |      */ | ||||||
|  |     private static readonly DEV_ICONS_STATUS: Record<string, Promise<boolean>> = {}; | ||||||
|  | 
 | ||||||
|  |     private static readonly ALIASES = { ...aliases } as unknown as Record<string, string>; | ||||||
|  | 
 | ||||||
|  |     protected static logger = CoreLogger.getInstance('CoreIcons'); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Check icon alias and returns the new icon name. | ||||||
|  |      * | ||||||
|  |      * @param icon Icon name. | ||||||
|  |      * @returns New icon name and new library if changed. | ||||||
|  |      */ | ||||||
|  |     static async getFontAwesomeIconFileName(icon: string): Promise<{fileName: string; newLibrary?: string}> { | ||||||
|  |         let newLibrary: string | undefined = undefined; | ||||||
|  |         if (icon.endsWith('-o')) { | ||||||
|  |             newLibrary = 'regular'; | ||||||
|  |             icon = icon.substring(0, icon.length - 2); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (CoreIcons.ALIASES[icon]) { | ||||||
|  |             this.logger.error(`Icon ${icon} is an alias of ${CoreIcons.ALIASES[icon]}, please use the new name.`); | ||||||
|  | 
 | ||||||
|  |             return { newLibrary, fileName: CoreIcons.ALIASES[icon] }; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return { newLibrary, fileName: icon }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Validate that an icon exists, or show warning otherwise (only in development and testing environments). | ||||||
|  |      * | ||||||
|  |      * @param name Icon name. | ||||||
|  |      * @param src Icon source url. | ||||||
|  |      */ | ||||||
|  |     static validateIcon(name: string, src: string): void { | ||||||
|  |         if (!CoreConstants.BUILD.isDevelopment && !CoreConstants.BUILD.isTesting) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (!(src in CoreIcons.DEV_ICONS_STATUS)) { | ||||||
|  |             CoreIcons.DEV_ICONS_STATUS[src] = Http.get(src, { responseType: 'text' }) | ||||||
|  |                 .toPromise() | ||||||
|  |                 .then(() => true) | ||||||
|  |                 .catch(() => false); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // eslint-disable-next-line promise/catch-or-return
 | ||||||
|  |         CoreIcons.DEV_ICONS_STATUS[src].then(exists => { | ||||||
|  |             if (exists) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return this.logger.error(`Icon ${name} not found`); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Replaces an <i> icon that uses CSS by a ion-icon with SVG. | ||||||
|  |      * It supports from 4.7 to 6.4 Font awesome versions. | ||||||
|  |      * But it can fail on 4.7 and 5.x because of the lack of assets. | ||||||
|  |      * | ||||||
|  |      * @param icon Current icon element. | ||||||
|  |      * @returns New icon, already included in the DOM. | ||||||
|  |      */ | ||||||
|  |     static async replaceCSSIcon(icon: Element): Promise<HTMLIonIconElement | undefined> { | ||||||
|  |         let library = 'solid'; | ||||||
|  |         let iconName = ''; | ||||||
|  | 
 | ||||||
|  |         Array.from(icon.classList).forEach(async (className) => { | ||||||
|  |             // Library name of 5.x
 | ||||||
|  |             switch (className) { | ||||||
|  |                 case 'fas': | ||||||
|  |                     library = 'solid'; | ||||||
|  | 
 | ||||||
|  |                     return; | ||||||
|  |                 case 'far': | ||||||
|  |                     library = 'regular'; | ||||||
|  | 
 | ||||||
|  |                     return; | ||||||
|  |                 case 'fab': | ||||||
|  |                     library = 'brands'; | ||||||
|  | 
 | ||||||
|  |                     return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Check fa- style class names.
 | ||||||
|  |             const faPart = className.match(/fa-([a-zA-Z0-9-]+)/); | ||||||
|  |             if (!faPart) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             const firstPart = faPart[1].split('-')[0]; | ||||||
|  | 
 | ||||||
|  |             switch (firstPart) { | ||||||
|  |                 // Class is defining library.
 | ||||||
|  |                 case 'solid': | ||||||
|  |                     library = 'solid'; | ||||||
|  |                     break; | ||||||
|  |                 case 'regular': | ||||||
|  |                 case 'light': | ||||||
|  |                     library = 'regular'; | ||||||
|  |                     break; | ||||||
|  |                 case 'brands': | ||||||
|  |                     library = 'brands'; | ||||||
|  |                     break; | ||||||
|  |                 // Class is defining special cases.
 | ||||||
|  |                 case '2xs': | ||||||
|  |                 case 'xs': | ||||||
|  |                 case 'sm': | ||||||
|  |                 case 'lg': | ||||||
|  |                 case 'xl': | ||||||
|  |                 case '2xl': | ||||||
|  |                 case 'fw': | ||||||
|  |                 case 'sharp': | ||||||
|  |                 case 'rotate': | ||||||
|  |                     return; | ||||||
|  |                 // Class is defining the icon name (fa-ICONNAME).
 | ||||||
|  |                 default: | ||||||
|  |                     iconName = faPart[1]; | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         if (!iconName) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const newIcon = document.createElement('ion-icon'); | ||||||
|  | 
 | ||||||
|  |         Array.from(icon.attributes).forEach(attr => { | ||||||
|  |             newIcon.setAttribute(attr.nodeName, attr.nodeValue || ''); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         if (!newIcon.getAttribute('aria-label') && | ||||||
|  |                 !newIcon.getAttribute('aria-labelledby') && | ||||||
|  |                 !newIcon.getAttribute('title')) { | ||||||
|  |             newIcon.setAttribute('aria-hidden', 'true'); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const { fileName, newLibrary } = await CoreIcons.getFontAwesomeIconFileName(iconName); | ||||||
|  |         if (newLibrary) { | ||||||
|  |             library = newLibrary; | ||||||
|  |         } | ||||||
|  |         iconName = fileName; | ||||||
|  | 
 | ||||||
|  |         const src = CoreIcons.getIconSrc('font-awesome', library, iconName); | ||||||
|  | 
 | ||||||
|  |         newIcon.setAttribute('src', src); | ||||||
|  | 
 | ||||||
|  |         newIcon.classList.add('faicon'); | ||||||
|  |         CoreIcons.validateIcon(iconName, src); | ||||||
|  | 
 | ||||||
|  |         icon.parentElement?.insertBefore(newIcon, icon); | ||||||
|  |         icon.remove(); | ||||||
|  | 
 | ||||||
|  |         return newIcon; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Get icon SVG path. | ||||||
|  |      * | ||||||
|  |      * @param font Font Family. | ||||||
|  |      * @param library Library to use. | ||||||
|  |      * @param icon Icon Name. | ||||||
|  |      * @returns Path. | ||||||
|  |      */ | ||||||
|  |     static getIconSrc(font: string, library: string, icon: string): string { | ||||||
|  |         return `assets/fonts/${font}/${library}/${icon}.svg`; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										84
									
								
								src/core/singletons/tests/icons.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/core/singletons/tests/icons.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | |||||||
|  | // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||||
|  | //
 | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||||
|  | // you may not use this file except in compliance with the License.
 | ||||||
|  | // You may obtain a copy of the License at
 | ||||||
|  | //
 | ||||||
|  | //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||||
|  | //
 | ||||||
|  | // Unless required by applicable law or agreed to in writing, software
 | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||||
|  | // See the License for the specific language governing permissions and
 | ||||||
|  | // limitations under the License.
 | ||||||
|  | 
 | ||||||
|  | import { CoreIcons } from '@singletons/icons'; | ||||||
|  | 
 | ||||||
|  | describe('CoreIcons singleton', () => { | ||||||
|  | 
 | ||||||
|  |     it('replaces CSS icon with the correspondant ion-icon', async () => { | ||||||
|  |         const icon = document.createElement('i'); | ||||||
|  | 
 | ||||||
|  |         // Not an icon
 | ||||||
|  |         icon.className = 'test'; | ||||||
|  |         expect((await CoreIcons.replaceCSSIcon(icon))) | ||||||
|  |             .toEqual(undefined); | ||||||
|  | 
 | ||||||
|  |         icon.className = 'fas fanoicon'; | ||||||
|  |         expect((await CoreIcons.replaceCSSIcon(icon))) | ||||||
|  |             .toEqual(undefined); | ||||||
|  | 
 | ||||||
|  |         icon.className = 'fa-solid fanoicon'; | ||||||
|  |         expect((await CoreIcons.replaceCSSIcon(icon))) | ||||||
|  |             .toEqual(undefined); | ||||||
|  | 
 | ||||||
|  |         // Font awesome 6
 | ||||||
|  |         icon.className = 'fa-solid fa-face-awesome'; | ||||||
|  |         expect((await CoreIcons.replaceCSSIcon(icon))?.getAttribute('src')) | ||||||
|  |             .toEqual('assets/fonts/font-awesome/solid/face-awesome.svg'); | ||||||
|  | 
 | ||||||
|  |         icon.className = 'fa-regular fa-face-awesome'; | ||||||
|  |         expect((await CoreIcons.replaceCSSIcon(icon))?.getAttribute('src')) | ||||||
|  |             .toEqual('assets/fonts/font-awesome/regular/face-awesome.svg'); | ||||||
|  | 
 | ||||||
|  |         icon.className = 'fa-light fa-face-awesome'; | ||||||
|  |         expect((await CoreIcons.replaceCSSIcon(icon))?.getAttribute('src')) | ||||||
|  |             .toEqual('assets/fonts/font-awesome/regular/face-awesome.svg'); | ||||||
|  | 
 | ||||||
|  |         icon.className = 'fa-brands fa-facebook'; | ||||||
|  |         expect((await CoreIcons.replaceCSSIcon(icon))?.getAttribute('src')) | ||||||
|  |             .toEqual('assets/fonts/font-awesome/brands/facebook.svg'); | ||||||
|  | 
 | ||||||
|  |         // Font awesome 5
 | ||||||
|  |         icon.className = 'fas fa-yin-yang'; | ||||||
|  |         expect((await CoreIcons.replaceCSSIcon(icon))?.getAttribute('src')) | ||||||
|  |             .toEqual('assets/fonts/font-awesome/solid/yin-yang.svg'); | ||||||
|  | 
 | ||||||
|  |         icon.className = 'far fa-wrench'; | ||||||
|  |         expect((await CoreIcons.replaceCSSIcon(icon))?.getAttribute('src')) | ||||||
|  |             .toEqual('assets/fonts/font-awesome/regular/wrench.svg'); | ||||||
|  | 
 | ||||||
|  |         icon.className = 'fab fa-youtube'; | ||||||
|  |         expect((await CoreIcons.replaceCSSIcon(icon))?.getAttribute('src')) | ||||||
|  |             .toEqual('assets/fonts/font-awesome/brands/youtube.svg'); | ||||||
|  | 
 | ||||||
|  |         // Font awesome 4.7
 | ||||||
|  |         icon.className = 'fa fa-address-book'; | ||||||
|  |         expect((await CoreIcons.replaceCSSIcon(icon))?.getAttribute('src')) | ||||||
|  |             .toEqual('assets/fonts/font-awesome/solid/address-book.svg'); | ||||||
|  | 
 | ||||||
|  |         icon.className = 'fa fa-address-book-o'; | ||||||
|  |         expect((await CoreIcons.replaceCSSIcon(icon))?.getAttribute('src')) | ||||||
|  |             .toEqual('assets/fonts/font-awesome/regular/address-book.svg'); | ||||||
|  | 
 | ||||||
|  |         // Aliases
 | ||||||
|  |         icon.className = 'fas fa-battery-5'; | ||||||
|  |         expect((await CoreIcons.replaceCSSIcon(icon))?.getAttribute('src')) | ||||||
|  |             .toEqual('assets/fonts/font-awesome/solid/battery-full.svg'); | ||||||
|  | 
 | ||||||
|  |         icon.className = 'fa fa-check-square'; | ||||||
|  |         expect((await CoreIcons.replaceCSSIcon(icon))?.getAttribute('src')) | ||||||
|  |             .toEqual('assets/fonts/font-awesome/solid/square-check.svg'); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  | }); | ||||||
| @ -4,6 +4,7 @@ information provided here is intended especially for developers. | |||||||
| === 4.3.0 === | === 4.3.0 === | ||||||
| 
 | 
 | ||||||
|  - CoreSiteBasicInfo fullName attribute has changed to fullname and avatar to userpictureurl to match user fields. |  - CoreSiteBasicInfo fullName attribute has changed to fullname and avatar to userpictureurl to match user fields. | ||||||
|  |  - Font Awesome icon library has been updated to 6.4.0. But nothing has changed, only version number. | ||||||
| 
 | 
 | ||||||
| === 4.2.0 === | === 4.2.0 === | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user