forked from CIT/Vmeda.Online
		
	MOBILE-3766 more: Allow defining items in config
This commit is contained in:
		
							parent
							
								
									ed2b17cf9b
								
							
						
					
					
						commit
						56112c0f81
					
				@ -15,6 +15,7 @@
 | 
				
			|||||||
/* eslint-disable @typescript-eslint/naming-convention */
 | 
					/* eslint-disable @typescript-eslint/naming-convention */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { CoreColorScheme, CoreZoomLevel } from '@features/settings/services/settings-helper';
 | 
					import { CoreColorScheme, CoreZoomLevel } from '@features/settings/services/settings-helper';
 | 
				
			||||||
 | 
					import { CoreMainMenuLocalizedCustomItem } from '@features/mainmenu/services/mainmenu';
 | 
				
			||||||
import { CoreSitesDemoSiteData } from '@services/sites';
 | 
					import { CoreSitesDemoSiteData } from '@services/sites';
 | 
				
			||||||
import envJson from '@/assets/env.json';
 | 
					import envJson from '@/assets/env.json';
 | 
				
			||||||
import { OpenFileAction } from '@services/utils/utils';
 | 
					import { OpenFileAction } from '@services/utils/utils';
 | 
				
			||||||
@ -175,6 +176,7 @@ export interface EnvironmentConfig {
 | 
				
			|||||||
    displayqronsitescreen?: boolean;
 | 
					    displayqronsitescreen?: boolean;
 | 
				
			||||||
    forceOpenLinksIn: 'app' | 'browser';
 | 
					    forceOpenLinksIn: 'app' | 'browser';
 | 
				
			||||||
    iOSDefaultOpenFileAction?: OpenFileAction;
 | 
					    iOSDefaultOpenFileAction?: OpenFileAction;
 | 
				
			||||||
 | 
					    customMainMenuItems?: CoreMainMenuLocalizedCustomItem[];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface EnvironmentBuild {
 | 
					export interface EnvironmentBuild {
 | 
				
			||||||
 | 
				
			|||||||
@ -15,11 +15,13 @@
 | 
				
			|||||||
import { Injectable } from '@angular/core';
 | 
					import { Injectable } from '@angular/core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { CoreApp } from '@services/app';
 | 
					import { CoreApp } from '@services/app';
 | 
				
			||||||
import { CoreLang } from '@services/lang';
 | 
					import { CoreLang, CoreLangLanguage } from '@services/lang';
 | 
				
			||||||
import { CoreSites } from '@services/sites';
 | 
					import { CoreSites } from '@services/sites';
 | 
				
			||||||
import { CoreConstants } from '@/core/constants';
 | 
					import { CoreConstants } from '@/core/constants';
 | 
				
			||||||
import { CoreMainMenuDelegate, CoreMainMenuHandlerToDisplay } from './mainmenu-delegate';
 | 
					import { CoreMainMenuDelegate, CoreMainMenuHandlerToDisplay } from './mainmenu-delegate';
 | 
				
			||||||
import { makeSingleton } from '@singletons';
 | 
					import { Device, makeSingleton } from '@singletons';
 | 
				
			||||||
 | 
					import { CoreArray } from '@singletons/array';
 | 
				
			||||||
 | 
					import { CoreTextUtils } from '@services/utils/text';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Service that provides some features regarding Main Menu.
 | 
					 * Service that provides some features regarding Main Menu.
 | 
				
			||||||
@ -48,13 +50,28 @@ export class CoreMainMenuProvider {
 | 
				
			|||||||
        return handlers.filter(handler => !handler.onlyInMore).slice(0, this.getNumItems());
 | 
					        return handlers.filter(handler => !handler.onlyInMore).slice(0, this.getNumItems());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get a list of custom menu items.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param siteId Site to get custom items from.
 | 
				
			||||||
 | 
					     * @return List of custom menu items.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    async getCustomMenuItems(siteId?: string): Promise<CoreMainMenuCustomItem[]> {
 | 
				
			||||||
 | 
					        const customItems = await Promise.all([
 | 
				
			||||||
 | 
					            this.getCustomMenuItemsFromSite(siteId),
 | 
				
			||||||
 | 
					            this.getCustomItemsFromConfig(),
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return CoreArray.flatten(customItems);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Get a list of custom menu items for a certain site.
 | 
					     * Get a list of custom menu items for a certain site.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param siteId Site ID. If not defined, current site.
 | 
					     * @param siteId Site ID. If not defined, current site.
 | 
				
			||||||
     * @return List of custom menu items.
 | 
					     * @return List of custom menu items.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    async getCustomMenuItems(siteId?: string): Promise<CoreMainMenuCustomItem[]> {
 | 
					    protected async getCustomMenuItemsFromSite(siteId?: string): Promise<CoreMainMenuCustomItem[]> {
 | 
				
			||||||
        const site = await CoreSites.getSite(siteId);
 | 
					        const site = await CoreSites.getSite(siteId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const itemsString = site.getStoredConfig('tool_mobile_custommenuitems');
 | 
					        const itemsString = site.getStoredConfig('tool_mobile_custommenuitems');
 | 
				
			||||||
@ -148,6 +165,45 @@ export class CoreMainMenuProvider {
 | 
				
			|||||||
        return result.filter((entry) => typeof entry != 'undefined');
 | 
					        return result.filter((entry) => typeof entry != 'undefined');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get a list of custom menu items from config.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return List of custom menu items.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected async getCustomItemsFromConfig(): Promise<CoreMainMenuCustomItem[]> {
 | 
				
			||||||
 | 
					        const items = CoreConstants.CONFIG.customMainMenuItems;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!items) {
 | 
				
			||||||
 | 
					            return [];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const currentLang = await CoreLang.getCurrentLanguage();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const fallbackLang = CoreConstants.CONFIG.default_lang || 'en';
 | 
				
			||||||
 | 
					        const replacements = {
 | 
				
			||||||
 | 
					            devicetype: '',
 | 
				
			||||||
 | 
					            osversion: Device.version,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (CoreApp.isAndroid()) {
 | 
				
			||||||
 | 
					            replacements.devicetype = 'Android';
 | 
				
			||||||
 | 
					        } else if (CoreApp.isIOS()) {
 | 
				
			||||||
 | 
					            replacements.devicetype = 'iPhone or iPad';
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            replacements.devicetype = 'Other';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return items
 | 
				
			||||||
 | 
					            .filter(item => typeof item.label === 'string' || currentLang in item.label || fallbackLang in item.label)
 | 
				
			||||||
 | 
					            .map(item => ({
 | 
				
			||||||
 | 
					                ...item,
 | 
				
			||||||
 | 
					                url: CoreTextUtils.replaceArguments(item.url, replacements, 'uri'),
 | 
				
			||||||
 | 
					                label: typeof item.label === 'string'
 | 
				
			||||||
 | 
					                    ? item.label
 | 
				
			||||||
 | 
					                    : item.label[currentLang] ?? item.label[fallbackLang],
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Get the number of items to be shown on the main menu bar.
 | 
					     * Get the number of items to be shown on the main menu bar.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
@ -264,6 +320,13 @@ export interface CoreMainMenuCustomItem {
 | 
				
			|||||||
    icon: string;
 | 
					    icon: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Custom main menu item with localized text.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type CoreMainMenuLocalizedCustomItem = Omit<CoreMainMenuCustomItem, 'label'> & {
 | 
				
			||||||
 | 
					    label: string | Record<CoreLangLanguage, string>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Map of custom menu items.
 | 
					 * Map of custom menu items.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
				
			|||||||
@ -480,7 +480,7 @@ export class CoreLangProvider {
 | 
				
			|||||||
     * @param lang Language code.
 | 
					     * @param lang Language code.
 | 
				
			||||||
     * @return Promise resolved with the file contents.
 | 
					     * @return Promise resolved with the file contents.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    async readLangFile(lang: string): Promise<Record<string, string>> {
 | 
					    async readLangFile(lang: CoreLangLanguage): Promise<Record<string, string>> {
 | 
				
			||||||
        const observable = Http.get(`assets/lang/${lang}.json`, {
 | 
					        const observable = Http.get(`assets/lang/${lang}.json`, {
 | 
				
			||||||
            responseType: 'json',
 | 
					            responseType: 'json',
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
@ -519,6 +519,11 @@ export class CoreLangProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export const CoreLang = makeSingleton(CoreLangProvider);
 | 
					export const CoreLang = makeSingleton(CoreLangProvider);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Language code. E.g. 'au', 'es', etc.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type CoreLangLanguage = string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Language object has two leves, first per language and second per string key.
 | 
					 * Language object has two leves, first per language and second per string key.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
				
			|||||||
@ -93,4 +93,19 @@ describe('CoreTextUtilsProvider', () => {
 | 
				
			|||||||
        expect(textUtils.matchesGlob('/foo/bar/baz', '/foo/ba?/ba?')).toBe(true);
 | 
					        expect(textUtils.matchesGlob('/foo/bar/baz', '/foo/ba?/ba?')).toBe(true);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('replaces arguments', () => {
 | 
				
			||||||
 | 
					        // Arrange
 | 
				
			||||||
 | 
					        const url = 'http://campus.edu?device={{device}}&version={{version}}';
 | 
				
			||||||
 | 
					        const replacements = {
 | 
				
			||||||
 | 
					            device: 'iPhone or iPad',
 | 
				
			||||||
 | 
					            version: '1.2.3',
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Act
 | 
				
			||||||
 | 
					        const replaced = textUtils.replaceArguments(url, replacements, 'uri');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Assert
 | 
				
			||||||
 | 
					        expect(replaced).toEqual('http://campus.edu?device=iPhone%20or%20iPad&version=1.2.3');
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -731,6 +731,28 @@ export class CoreTextUtilsProvider {
 | 
				
			|||||||
        return text.replace(/[#:/?\\]+/g, '_');
 | 
					        return text.replace(/[#:/?\\]+/g, '_');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Replace {{ARGUMENT}} arguments in the text.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param text Text to treat.
 | 
				
			||||||
 | 
					     * @param replacements Argument values.
 | 
				
			||||||
 | 
					     * @param encoding Encoding to use in values.
 | 
				
			||||||
 | 
					     * @returns Treated text.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    replaceArguments(text: string, replacements: Record<string, string> = {}, encoding?: 'uri'): string {
 | 
				
			||||||
 | 
					        let match;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while ((match = text.match(/\{\{([^}]+)\}\}/))) {
 | 
				
			||||||
 | 
					            const argument = match[1].trim();
 | 
				
			||||||
 | 
					            const value = replacements[argument] ?? '';
 | 
				
			||||||
 | 
					            const encodedValue = encoding ? encodeURIComponent(value) : value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            text = text.replace(`{{${argument}}}`, encodedValue);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return text;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Replace all the new lines on a certain text.
 | 
					     * Replace all the new lines on a certain text.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user