diff --git a/src/core/constants.ts b/src/core/constants.ts index f30b24a3d49..32b5ac3dbfe 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -125,6 +125,13 @@ export const enum LMSBadgeStyle { INFO = 'info', } +export enum CoreLinkOpenMethod { + APP = 'app', + INAPPBROWSER = 'inappbrowser', + BROWSER = 'browser', + EMBEDDED = 'embedded', +} + /** * Static class to contain all the core constants. */ diff --git a/src/core/directives/external-content.ts b/src/core/directives/external-content.ts index 04d608f272e..34faf945424 100644 --- a/src/core/directives/external-content.ts +++ b/src/core/directives/external-content.ts @@ -32,7 +32,7 @@ import { CoreLogger } from '@singletons/logger'; import { CoreError } from '@classes/errors/error'; import { CoreSite } from '@classes/sites/site'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; -import { DownloadStatus } from '../constants'; +import { CoreLinkOpenMethod, DownloadStatus } from '../constants'; import { CoreNetwork } from '@services/network'; import { Translate } from '@singletons'; import { AsyncDirective } from '@classes/async-directive'; @@ -370,7 +370,7 @@ export class CoreExternalContentDirective implements AfterViewInit, OnChanges, O const tagName = this.element.tagName; const openIn = tagName === 'A' && this.element.getAttribute('data-open-in'); - if (openIn === 'app' || openIn === 'browser') { + if (openIn === CoreLinkOpenMethod.APP || openIn === CoreLinkOpenMethod.BROWSER) { // The file is meant to be opened in browser or InAppBrowser, don't use the downloaded URL because it won't work. if (!site.isSitePluginFileUrl(url)) { return url; diff --git a/src/core/directives/format-text.ts b/src/core/directives/format-text.ts index 38d184c710b..824172f65b6 100644 --- a/src/core/directives/format-text.ts +++ b/src/core/directives/format-text.ts @@ -53,7 +53,7 @@ import { MediaElementController } from '@classes/element-controllers/MediaElemen import { FrameElement, FrameElementController } from '@classes/element-controllers/FrameElementController'; import { CoreUrl } from '@singletons/url'; import { CoreIcons } from '@singletons/icons'; -import { ContextLevel } from '../constants'; +import { ContextLevel, CoreLinkOpenMethod } from '../constants'; import { CoreWait } from '@singletons/wait'; import { toBoolean } from '../transforms/boolean'; import { CoreViewer } from '@features/viewer/services/viewer'; @@ -839,7 +839,7 @@ export class CoreFormatTextDirective implements OnDestroy, AsyncDirective { // Try to convert the URL to absolute if needed. url = CoreUrl.toAbsoluteURL(site.getURL(), url); const confirmMessage = element.dataset.appUrlConfirm; - const openInApp = element.dataset.openIn === 'app'; + const openInApp = element.dataset.openIn === CoreLinkOpenMethod.APP; const refreshOnResume = element.dataset.appUrlResumeAction === 'refresh'; if (confirmMessage) { diff --git a/src/core/directives/link.ts b/src/core/directives/link.ts index 35127cf9bd9..2d33131c915 100644 --- a/src/core/directives/link.ts +++ b/src/core/directives/link.ts @@ -19,7 +19,7 @@ import { CoreFileHelper } from '@services/file-helper'; import { CoreSites } from '@services/sites'; import { CoreUrl } from '@singletons/url'; import { CoreOpener } from '@singletons/opener'; -import { CoreConstants } from '@/core/constants'; +import { CoreConstants, CoreLinkOpenMethod } from '@/core/constants'; import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper'; import { CoreCustomURLSchemes } from '@services/urlschemes'; import { DomSanitizer } from '@singletons'; @@ -187,8 +187,8 @@ export class CoreLinkDirective implements OnInit { protected async openExternalLink(href: string, openIn?: string | null): Promise { // Priority order is: core-link inApp attribute > forceOpenLinksIn setting > data-open-in HTML attribute. const openInApp = this.inApp ?? - (CoreConstants.CONFIG.forceOpenLinksIn !== 'browser' && - (CoreConstants.CONFIG.forceOpenLinksIn === 'app' || openIn === 'app')); + (CoreConstants.CONFIG.forceOpenLinksIn !== CoreLinkOpenMethod.BROWSER && + (CoreConstants.CONFIG.forceOpenLinksIn === CoreLinkOpenMethod.APP || openIn === CoreLinkOpenMethod.APP)); // Check if we need to auto-login. if (!CoreSites.isLoggedIn()) { diff --git a/src/core/features/mainmenu/components/custom-menu-item/custom-menu-item.html b/src/core/features/mainmenu/components/custom-menu-item/custom-menu-item.html new file mode 100644 index 00000000000..2638afb4859 --- /dev/null +++ b/src/core/features/mainmenu/components/custom-menu-item/custom-menu-item.html @@ -0,0 +1,17 @@ +@if (type() !== 'embedded') { + + +} @else { + + +} diff --git a/src/core/features/mainmenu/components/custom-menu-item/custom-menu-item.ts b/src/core/features/mainmenu/components/custom-menu-item/custom-menu-item.ts new file mode 100644 index 00000000000..b06f5ef9128 --- /dev/null +++ b/src/core/features/mainmenu/components/custom-menu-item/custom-menu-item.ts @@ -0,0 +1,59 @@ +// (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 { CoreLinkOpenMethod } from '@/core/constants'; +import { CoreSharedModule } from '@/core/shared.module'; +import { Component, input } from '@angular/core'; +import { CoreViewer } from '@features/viewer/services/viewer'; + +/** + * Component to display a custom menu item. + */ +@Component({ + selector: 'core-custom-menu-item', + templateUrl: 'custom-menu-item.html', + imports: [ + CoreSharedModule, + ], +}) +export class CoreCustomMenuItemComponent { + + /** + * Type of the item: app, inappbrowser, browser or embedded. + */ + readonly type = input.required(); + + /** + * Url of the item. + */ + readonly url = input.required(); + + /** + * Label to display for the item. + */ + readonly label = input.required(); + + /** + * Name of the icon to display for the item. + */ + readonly icon = input.required(); + + /** + * Open an embedded custom item. + */ + openItem(): void { + CoreViewer.openIframeViewer(this.label(), this.url()); + } + +} diff --git a/src/core/features/mainmenu/components/user-menu/user-menu.html b/src/core/features/mainmenu/components/user-menu/user-menu.html index 4ed6a402233..50debd38e95 100644 --- a/src/core/features/mainmenu/components/user-menu/user-menu.html +++ b/src/core/features/mainmenu/components/user-menu/user-menu.html @@ -67,6 +67,10 @@

} + @for (item of customItems; track item) { + + } + { + this.customItems = await CoreCustomMenu.getUserCustomMenuItems(); + } + /** * Opens User profile page. * diff --git a/src/core/features/mainmenu/pages/more/more.html b/src/core/features/mainmenu/pages/more/more.html index 1bf31c88665..106ced8e88a 100644 --- a/src/core/features/mainmenu/pages/more/more.html +++ b/src/core/features/mainmenu/pages/more/more.html @@ -42,25 +42,9 @@

{{ 'core.more' | translate }}

} }
- - @if (item.type !== 'embedded') { - - - } @else { - - - } - + @for (item of customItems; track item) { + + } @if (showScanQR) {