diff --git a/src/themes/qulto/app/item-page/simple/field-components/metadata-values/metadata-values.component.html b/src/themes/qulto/app/item-page/simple/field-components/metadata-values/metadata-values.component.html new file mode 100644 index 00000000000..c09c23f8651 --- /dev/null +++ b/src/themes/qulto/app/item-page/simple/field-components/metadata-values/metadata-values.component.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + {{value}} + + + + + + + + {{value}} + + + + + + {{value}} + + + + + {{value}} + diff --git a/src/themes/qulto/app/item-page/simple/field-components/metadata-values/metadata-values.component.scss b/src/themes/qulto/app/item-page/simple/field-components/metadata-values/metadata-values.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/themes/qulto/app/item-page/simple/field-components/metadata-values/metadata-values.component.ts b/src/themes/qulto/app/item-page/simple/field-components/metadata-values/metadata-values.component.ts new file mode 100644 index 00000000000..a8e93bf2b42 --- /dev/null +++ b/src/themes/qulto/app/item-page/simple/field-components/metadata-values/metadata-values.component.ts @@ -0,0 +1,166 @@ +import { + AsyncPipe, + NgFor, + NgIf, + NgTemplateOutlet, +} from '@angular/common'; +import { + Component, + Inject, + Input, + OnChanges, + SimpleChanges, +} from '@angular/core'; +import { RouterLink } from '@angular/router'; +import { TranslateModule } from '@ngx-translate/core'; + +import { + APP_CONFIG, + AppConfig, +} from '../../../../../../../config/app-config.interface'; +import { environment } from '../../../../../../../environments/environment'; +import { BrowseDefinition } from 'src/app/core/shared/browse-definition.model'; +import { MetadataValue } from 'src/app/core/shared/metadata.models'; +import { hasValue } from 'src/app/shared/empty.util'; +import { MetadataFieldWrapperComponent } from 'src/app/shared/metadata-field-wrapper/metadata-field-wrapper.component'; +import { MarkdownDirective } from 'src/app/shared/utils/markdown.directive'; +import { ImageField } from 'src/app/item-page/simple/field-components/specific-field/image-field'; +import { ResourceType } from 'src/app/core/shared/resource-type'; +import { listableObjectComponent } from 'src/app/shared/object-collection/shared/listable-object/listable-object.decorator'; +import { ViewMode } from 'src/app/core/shared/view-mode.model'; +import { Context } from 'src/app/core/shared/context.model'; + +/** + * This component renders the configured 'values' into the ds-metadata-field-wrapper component. + * It puts the given 'separator' between each two values. + */ +@listableObjectComponent('MetadataValuesComponent', ViewMode.ListElement, Context.Any, 'qulto') +@Component({ + selector: 'ds-metadata-values', + styleUrls: ['./metadata-values.component.scss'], + templateUrl: './metadata-values.component.html', + standalone: true, + imports: [MetadataFieldWrapperComponent, NgFor, NgTemplateOutlet, NgIf, RouterLink, AsyncPipe, TranslateModule, MarkdownDirective], +}) +export class MetadataValuesComponent implements OnChanges { + + constructor( + @Inject(APP_CONFIG) private appConfig: AppConfig, + ) { + } + + /** + * The metadata values to display + */ + @Input() mdValues: MetadataValue[]; + + /** + * The seperator used to split the metadata values (can contain HTML) + */ + @Input() separator: string; + + /** + * The label for this iteration of metadata values + */ + @Input() label: string; + + /** + * Whether the {@link MarkdownDirective} should be used to render these metadata values. + * This will only have effect if {@link MarkdownConfig#enabled} is true. + * Mathjax will only be rendered if {@link MarkdownConfig#mathjax} is true. + */ + @Input() enableMarkdown = false; + + /** + * Whether any valid HTTP(S) URL should be rendered as a link + */ + @Input() urlRegex?; + + /** + * This variable will be true if both {@link environment.markdown.enabled} and {@link enableMarkdown} are true. + */ + renderMarkdown; + + + @Input() browseDefinition?: BrowseDefinition; + + /** + * Optional {@code ImageField} reference that represents an image to be displayed inline. + */ + @Input() img?: ImageField; + + hasValue = hasValue; + + ngOnChanges(changes: SimpleChanges): void { + this.renderMarkdown = !!this.appConfig.markdown.enabled && this.enableMarkdown; + } + + /** + * Does this metadata value have a configured link to a browse definition? + */ + hasBrowseDefinition(): boolean { + console.log('hasBrowseDefinition'); + return hasValue(this.browseDefinition); + } + + /** + * Does this metadata value have a valid URL that should be rendered as a link? + * @param value A MetadataValue being displayed + */ + hasLink(value: MetadataValue): boolean { + console.log('hasLink'); + if (hasValue(this.urlRegex)) { + const pattern = new RegExp(this.urlRegex); + return pattern.test(value.value); + } + return false; + } + + /** + * Return a queryparams object for use in a link, with the key dependent on whether this browse + * definition is metadata browse, or item browse + * @param value the specific metadata value being linked + */ + getQueryParams(value) { + console.log('getQueryParams'); + const queryParams = { value: value }; + // todo: should compare with type instead? + // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison + if (this.browseDefinition.getRenderType() === new ResourceType("startsWith").value) { + return { startsWith: value }; + } + return queryParams; + } + + getBrowseRouteSegment(): string { + console.log('getBrowseRouteSegment'); + if (this.browseDefinition?.id === 'srsc') { + return 'subject'; + } + return this.browseDefinition?.id; + } + + + /** + * Checks if the given link value is an internal link. + * @param linkValue - The link value to check. + * @returns True if the link value starts with the base URL defined in the environment configuration, false otherwise. + */ + hasInternalLink(linkValue: string): boolean { + console.log('hasInternalLink'); + return linkValue.startsWith(environment.ui.baseUrl); + } + + /** + * This method performs a validation and determines the target of the url. + * @returns - Returns the target url. + */ + getLinkAttributes(urlValue: string): { target: string, rel: string } { + console.log('getLinkAttributes'); + if (this.hasInternalLink(urlValue)) { + return { target: '_self', rel: '' }; + } else { + return { target: '_blank', rel: 'noopener noreferrer' }; + } + } +} diff --git a/src/themes/qulto/app/item-page/simple/field-components/specific-field/generic/generic-item-page-field.component.ts b/src/themes/qulto/app/item-page/simple/field-components/specific-field/generic/generic-item-page-field.component.ts new file mode 100644 index 00000000000..3a55e599691 --- /dev/null +++ b/src/themes/qulto/app/item-page/simple/field-components/specific-field/generic/generic-item-page-field.component.ts @@ -0,0 +1,56 @@ +import { AsyncPipe } from '@angular/common'; +import { + Component, + Input, +} from '@angular/core'; + +import { Item } from 'src/app/core/shared/item.model'; +import { MetadataValuesComponent } from '../../metadata-values/metadata-values.component'; +import { ItemPageFieldComponent } from 'src/app/item-page/simple/field-components/specific-field/item-page-field.component'; + +@Component({ + selector: 'ds-generic-item-page-field', + templateUrl: '../item-page-field.component.html', + standalone: true, + imports: [MetadataValuesComponent, AsyncPipe], +}) +/** + * This component can be used to represent metadata on a simple item page. + * It is the most generic way of displaying metadata values + * It expects 4 parameters: The item, a separator, the metadata keys and an i18n key + */ +export class GenericItemPageFieldComponent extends ItemPageFieldComponent { + + /** + * The item to display metadata for + */ + @Input() item: Item; + + /** + * Separator string between multiple values of the metadata fields defined + * @type {string} + */ + @Input() separator: string; + + /** + * Fields (schema.element.qualifier) used to render their values. + */ + @Input() fields: string[]; + + /** + * Label i18n key for the rendered metadata + */ + @Input() label: string; + + /** + * Whether the {@link MarkdownDirective} should be used to render this metadata. + */ + @Input() enableMarkdown = false; + + /** + * Whether any valid HTTP(S) URL should be rendered as a link + */ + @Input() urlRegex?: string; + + +} diff --git a/src/themes/qulto/app/item-page/simple/field-components/specific-field/item-page-field.component.html b/src/themes/qulto/app/item-page/simple/field-components/specific-field/item-page-field.component.html new file mode 100644 index 00000000000..f45d4657a46 --- /dev/null +++ b/src/themes/qulto/app/item-page/simple/field-components/specific-field/item-page-field.component.html @@ -0,0 +1,11 @@ +
+ +
diff --git a/src/themes/qulto/app/item-page/simple/field-components/specific-field/title/item-page-title-field.component.spec.ts b/src/themes/qulto/app/item-page/simple/field-components/specific-field/title/item-page-title-field.component.spec.ts index c8165c6f871..7e3e24d650e 100644 --- a/src/themes/qulto/app/item-page/simple/field-components/specific-field/title/item-page-title-field.component.spec.ts +++ b/src/themes/qulto/app/item-page/simple/field-components/specific-field/title/item-page-title-field.component.spec.ts @@ -13,7 +13,7 @@ import { } from '@ngx-translate/core'; import { TranslateLoaderMock } from '../../../../../../../../app/shared/testing/translate-loader.mock'; -import { MetadataValuesComponent } from '../../../../../../../../app/item-page/field-components/metadata-values/metadata-values.component'; +import { MetadataValuesComponent } from '../../metadata-values/metadata-values.component'; import { mockItemWithMetadataFieldsAndValue } from '../../../../../../../../app/item-page/simple/field-components/specific-field/item-page-field.component.spec'; import { ItemPageTitleFieldComponent } from './item-page-title-field.component'; diff --git a/src/themes/qulto/app/item-page/simple/item-types/publication/publication.component.ts b/src/themes/qulto/app/item-page/simple/item-types/publication/publication.component.ts index 6f2f1482e8b..5291e9d9786 100644 --- a/src/themes/qulto/app/item-page/simple/item-types/publication/publication.component.ts +++ b/src/themes/qulto/app/item-page/simple/item-types/publication/publication.component.ts @@ -22,7 +22,7 @@ import { MiradorViewerComponent } from '../../../../../../../app/item-page/mirad import { ThemedFileSectionComponent } from '../../../../../../../app/item-page/simple/field-components/file-section/themed-file-section.component'; import { ItemPageAbstractFieldComponent } from '../../../../../../../app/item-page/simple/field-components/specific-field/abstract/item-page-abstract-field.component'; import { ItemPageDateFieldComponent } from '../../../../../../../app/item-page/simple/field-components/specific-field/date/item-page-date-field.component'; -import { GenericItemPageFieldComponent } from '../../../../../../../app/item-page/simple/field-components/specific-field/generic/generic-item-page-field.component'; +import { GenericItemPageFieldComponent } from '../../field-components/specific-field/generic/generic-item-page-field.component'; import { ThemedItemPageTitleFieldComponent } from '../../field-components/specific-field/title/themed-item-page-field.component'; import { ItemPageUriFieldComponent } from '../../../../../../../app/item-page/simple/field-components/specific-field/uri/item-page-uri-field.component'; import { ThemedMetadataRepresentationListComponent } from '../../../../../../../app/item-page/simple/metadata-representation-list/themed-metadata-representation-list.component'; diff --git a/src/themes/qulto/eager-theme.module.ts b/src/themes/qulto/eager-theme.module.ts index ad263eeb32e..0d31e90bec2 100644 --- a/src/themes/qulto/eager-theme.module.ts +++ b/src/themes/qulto/eager-theme.module.ts @@ -10,6 +10,7 @@ import { NavbarComponent } from './app/navbar/navbar.component'; import { LangSwitchComponent } from './app/shared/lang-switch/lang-switch.component'; import { CommunityListElementComponent } from './app/shared/object-list/community-list-element/community-list-element.component'; import { PublicationComponent } from './app/item-page/simple/item-types/publication/publication.component'; +import { MetadataValuesComponent } from './app/item-page/simple/field-components/metadata-values/metadata-values.component'; /** @@ -28,7 +29,8 @@ const DECLARATIONS = [ NavbarComponent, FooterComponent, LangSwitchComponent, - PublicationComponent + PublicationComponent, + MetadataValuesComponent ]; @NgModule({ @@ -36,6 +38,7 @@ const DECLARATIONS = [ CommonModule, RootModule, PublicationComponent, + MetadataValuesComponent, ...DECLARATIONS, ], providers: [ diff --git a/src/themes/qulto/lazy-theme.module.ts b/src/themes/qulto/lazy-theme.module.ts index 3172f900cc4..56428c061f8 100644 --- a/src/themes/qulto/lazy-theme.module.ts +++ b/src/themes/qulto/lazy-theme.module.ts @@ -17,6 +17,8 @@ import { HomePageComponent } from './app/home-page/home-page.component'; import { FullItemPageComponent } from './app/item-page/full/full-item-page.component'; import { PublicationComponent } from './app/item-page/simple/item-types/publication/publication.component'; import { ThemedItemPageTitleFieldComponent } from './app/item-page/simple/field-components/specific-field/title/themed-item-page-field.component'; +import { MetadataValuesComponent } from './app/item-page/simple/field-components/metadata-values/metadata-values.component'; +import { GenericItemPageFieldComponent } from './app/item-page/simple/field-components/specific-field/generic/generic-item-page-field.component'; import { LoginPageComponent } from './app/login-page/login-page.component'; import { AuthNavMenuComponent } from './app/shared/auth-nav-menu/auth-nav-menu.component'; import { ObjectListComponent } from './app/shared/object-list/object-list.component'; @@ -48,6 +50,8 @@ const DECLARATIONS = [ NgxGalleryModule, PublicationComponent, ThemedItemPageTitleFieldComponent, + GenericItemPageFieldComponent, + MetadataValuesComponent, ...DECLARATIONS, ], })