File

app/dxa/dxa-fields/rich-text-field/rich-text-field.component.ts

Implements

OnInit

Metadata

selector rich-text-field
styleUrls ./rich-text-field.component.scss
templateUrl ./rich-text-field.component.html

Index

Properties
Methods
Inputs

Constructor

constructor(modalService: NgbModal, http: HttpClient, util: UtilService, publicationService: PublicationService, idGenerator: IdGeneratorService, expandService: ExpandService)
Parameters :
Name Type Optional
modalService NgbModal No
http HttpClient No
util UtilService No
publicationService PublicationService No
idGenerator IdGeneratorService No
expandService ExpandService No

Inputs

body
textColor
Type : string

Methods

Public anchorClick
anchorClick(event, templateRef)
Parameters :
Name Optional
event No
templateRef No
Returns : boolean
ngOnInit
ngOnInit()
Returns : void
Private openModal
openModal(templateRef)
Parameters :
Name Optional
templateRef No
Returns : void
Private resolveColor
resolveColor()
Returns : RichTextColor

Properties

color
Type : RichTextColor
Default value : 'text-darker-green-grey'
id
Default value : this.idGenerator.getId()
modalContentSrc
Type : string
modalContentText
Type : string
Default value : ''
modalType
Type : "IMAGE" | "TABLE"
tableData
Type : TabelData
import { Component, OnInit, Input } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { HttpClient } from '@angular/common/http';
import { UtilService } from 'src/app/core/services/util-service/util.service';
import { PublicationService } from 'src/app/core/services/publication-service/publication.service';
import { IdGeneratorService } from 'src/app/core/services/id-generator.service';
import { ExpandService } from '../../../core/services/expand-service/expand.service';

type RichTextColor =  'text-white' | 'text-darker-green-grey';
interface TabelData {
	body;
	footer;
}

@Component({
	selector: 'rich-text-field',
	templateUrl: './rich-text-field.component.html',
	styleUrls: ['./rich-text-field.component.scss']
})
export class RichTextFieldComponent implements OnInit {

	@Input() body;
	@Input() textColor: string;

	color: RichTextColor = 'text-darker-green-grey';

	/*
		This id is used to have a unique (hopefully) name for the modal window
		to not cause issue if multiple modal links are added on the same page
	*/
	id = this.idGenerator.getId();

	// These two are set when a user clicks on a link that should open a modal
	modalContentSrc: string;
	modalContentText = '';
	modalType: 'IMAGE' | 'TABLE';
	tableData: TabelData;

	constructor(
		private modalService: NgbModal,
		private http: HttpClient,
		private util: UtilService,
		private publicationService: PublicationService,
		private idGenerator: IdGeneratorService,
		private expandService: ExpandService
	) { }

	ngOnInit() {
		this.color = this.resolveColor();
	}

	// Handles anchor refs and scrolls to the linked element.
	public anchorClick(event, templateRef) {
		const href = event.target.getAttribute('href');

		// handle only hrefs to internal links
		if ( href && href.charAt(0) === '#') {

			const anchor = href.substring(1);
			const element = document.getElementById(anchor);
			
			if (element) {
				const card = element.closest('.card');
				
				// For body text expandable we need to open the accordion before scrolling.
				if (card) {
					const cardHeader = card.querySelector('.card-header');
					const accordionId = cardHeader.getAttribute('id').replace('-header', '');
					this.expandService.openAccordion(accordionId);
				}
				
				element.scrollIntoView({ behavior: 'smooth' });
			}
			return false;
		}


		const tagThatWasClicked = event.target.closest('.modal-window');
		if (tagThatWasClicked !== null) {
			// Don't follow the link that was clicked
			event.preventDefault();
			this.modalContentSrc = tagThatWasClicked.href;

			// If href contains tcm-id, set modal type to Table, otherwise Image
			if (this.modalContentSrc.startsWith('tcm:')) {
				this.modalType = 'TABLE';
				this.modalContentSrc = this.modalContentSrc.split('-')[1];
				// Get table data
				this.http.get(`/content${this.publicationService.getPublicationPath()}/dynamicComponent?itemId=${this.modalContentSrc}`).toPromise().then(res => {
					this.tableData = {
						body: this.util.extract(res, 'Content', 'table'),
						footer: this.util.extract(res, 'Content', 'footnotes')
					};

					this.modalContentText = tagThatWasClicked.text + ' - ' + (this.util.extract(res, 'Content', 'title') || '');
				});
			} else {
				this.modalType = 'IMAGE';
				this.modalContentText = tagThatWasClicked.text + ' - ' + tagThatWasClicked.title;
			}

			this.openModal(templateRef);
		}

	}

	// Passed the template ref that is set the html template
	private openModal(templateRef): void  {
		this.modalService.open(templateRef, { windowClass: 'modal-60-percent', size: 'lg', centered: true });
	}

	private resolveColor(): RichTextColor {
		switch (this.textColor) {
			case 'white': return 'text-white';
			case 'darker-green-grey': return 'text-darker-green-grey';
		}
		return 'text-darker-green-grey';
	}

}
<div [ngClass]="['content', color]" *ngIf="body">
	<div (click)="anchorClick($event, id)" [innerHTML]="body | safeHTML"></div>
</div>
<ng-template #id let-modal>
	<div [ngClass]="{'catalogue-table': modalType==='TABLE'}">
		<div class="modal-header">
			<h4 class="modal-title"> {{modalContentText}} </h4>
			<button type="button" class="close" aria-label="Close" (click)="modal.dismiss('Cross click')">
				<span >&times;</span>
			</button>
		</div>
		<div class="modal-body">
			<img [src]="modalContentSrc" *ngIf="modalType==='IMAGE'">
			<div class="table-responsive" *ngIf="modalType==='TABLE' && tableData?.body">
				<rich-text-field [body]="tableData.body"></rich-text-field>
			</div>
		</div>
		<div class="modal-footer" *ngIf="modalType==='TABLE' && tableData?.footer">
			<ol class="note-list">
				<li class="d-flex" *ngFor="let footer of tableData.footer; let i=index">
					<span class="mr-1"><sup>{{i+1}})</sup></span>
					<rich-text-field [body]="footer"></rich-text-field>
				</li>
			</ol>
		</div>
	</div>
</ng-template>

./rich-text-field.component.scss

@import "src/app/styles/helpers";

:host .content {
    ::ng-deep {
        font-family: 'SKF Chevin OT Light';
    }

    @include clearfix;

    ::ng-deep img {
        // This is used to override the sizes set by editors in RTFs in tridion
        // We set the max-width to not cause the image to span over the screen width
        // height is unset to keep the image scaled reasonably
        max-width: 100%;
        height: unset !important;
    }

    // This is needed since the html is embedded
    // Make the anchor tag look as if it where a regular link
    ::ng-deep .embeddedAnchor {
            color: $blue;
            &:hover {
                text-decoration: underline;
                color: #0056b3;
            }
    }

    ::ng-deep .small-capital-heading {
        @include font-scale(18, medium);
        font-variant: small-caps;
        font-variant-caps: all-small-caps;
    }

    ::ng-deep {
        .colorful-and-striped {
            border: none !important;

            caption {
                caption-side: top;
                color: $cool-grey;
                @include font-scale(14, uppercase);
            }

            thead tr {
                th, td {
                    border: none;
                    color: $white;
                    background-color: $blue;
                    @include font-scale(14, demibold);

                    & a {
                        color: $light-blue;
                    }
                }

                &:nth-last-child(2) {
                    th, td {
                        border-bottom: 1px solid $dark-blue !important;
                    }
                }

                &:last-child {
                    th, td {
                        border-bottom: 2px solid $dark-blue !important;
                    }
                }
            }

            tbody tr {
                td {
                    border: none;
                    @include font-scale(14, light);
                }

                &:nth-child(odd) {
                    background-color: $off-white;
                }

                &:nth-child(even) {
                    background-color: $white;
                }
            }
        }

        .simple-tables {
            @extend .colorful-and-striped;

            th, td {
                color: inherit;
                background-color: $white !important;

                & a {
                    color: $blue;
                }
            }

            tr {
                background-color: $white !important;
            }

            .thin-table-border {
                border-bottom: 1px solid $cool-grey;
            }

            .thick-table-border {
                border-bottom: 2px solid $cool-grey;
            }
        }

        .no-colors {
            background-color: $off-white;
            border-left: 0px;
            border-right: 0px;

            caption {
                caption-side: top;
                color: $cool-grey;
                @include font-scale(14, uppercase);
            }

            tbody {
                tr {
                    td {
                        height: 24px;
                        @include font-scale(16, light);
                        color: $cool-grey;
                        padding-top: 12px;
                        padding-bottom: 9px;
                        border-left: 0px;
                        border-right: 0px;
                    }
                }

                tr:first-child {
                    border-top: 3px solid;
                    border-top-color: $cool-grey;
                }
            }
        }
    }
}

.text-white {
    ::ng-deep {
        color: white;
        h1 { color: white; }
        h2 { color: white; }
        h3 { color: white; }
        h4 { color: white; }
        h5 { color: white; }
        p  { color: white; }
        a  {
            color: white;
            text-decoration: underline;
        }
    }
}

.text-darker-green-grey {
    ::ng-deep {
        color: $cool-grey;
        h1 {color: $cool-grey;}
        h2 {color: $cool-grey;}
        h3 {color: $cool-grey;}
        h4 {color: $cool-grey;}
        h5 {color: $cool-grey;}
        p  {color: $cool-grey;}
    }
}

// Used for the modal window. Move to global allow global usablity later
.close {
    &:focus {
        outline: none;
    }
}

::ng-deep .modal.modal-60-percent {
    .modal-dialog {
        @include media-breakpoint-up(sm) {
            max-width: 60%;
        }

        @include media-breakpoint-down(sm) {
            max-width: 60%;
            margin: auto;
        }

        @include media-breakpoint-up(xl) {
            max-width: 45%;
        }

    }

    .modal-body {
        img {
            max-width: 100%;
            object-fit: fill;
        }
    }

    .modal-footer {
        justify-content: flex-start;
        align-items: flex-start;
    }

    .modal-content {
        margin: 0 auto;
    }
}

::ng-deep .catalogue-table {
    .modal-header { background-color: $off-white; }
    .modal-body { background-color: $off-white; }
    .modal-footer {
        background-color: $off-white;
        @include font-size(12);
        align-items: flex-start;

        .note-list {
            padding-left: 0;
            list-style: none;
            margin: 0;
        }
    }
}

:host ::ng-deep .caution-text, :host ::ng-deep .warning-text {
    padding: calc-rem(30);
    color: $cool-grey !important;
    margin-bottom: calc-rem(20);

    h2, h3, h4, h5 {
        margin-bottom: 0 !important;
    }

    h5 {
        font-family: 'SKF Chevin OT Light' !important;
        font-weight: 300 !important;
    }

    a {
        color: $blue !important;
        text-decoration: none !important;

        &:hover {
            text-decoration: underline !important;
        }
    }
}

:host ::ng-deep .caution-text {
    background-color: tint($orange, 85%);
    h2, h3, h4, h5 {
        color: $orange !important;
    }
}

:host ::ng-deep .warning-text {
    background-color: tint($red, 85%);

    h2, h3, h4, h5 {
        color: $red !important;
    }
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""