File

app/dxa/dxa-entity/views/cad-download/cad-download.component.ts

Implements

OnInit OnDestroy

Metadata

selector [cad-download]
styleUrls ./cad-download.component.scss
templateUrl ./cad-download.component.html

Index

Properties
Methods
Inputs
Outputs
HostBindings

Constructor

constructor(http: HttpClient, sanitizer: DomSanitizer, labelService: LabelService, constants: ConstantsService)
Parameters :
Name Type Optional
http HttpClient No
sanitizer DomSanitizer No
labelService LabelService No
constants ConstantsService No

Inputs

designation
Type : string

Outputs

available
Type : EventEmitter<boolean>

HostBindings

attr.id
Default value : `${this.constants.COMPONENT_ID_PREFIX}-cad-download`
class

Methods

Private cadFormatListener
cadFormatListener()

Listens to CAD format selection boxes and makes sure max one is selected.

Returns : void
Public downloadCAD
downloadCAD()

Download ZIP file containing CAD file of chosen format.

Returns : void
Public downloadPDF
downloadPDF()

Download PDF of current designation.

Returns : void
Private downloadZIP
downloadZIP(url: string, type?: string)
Parameters :
Name Type Optional
url string No
type string Yes
Returns : void
Private getCadFormats
getCadFormats()

Get all available CAD formats from CADENAS.

Returns : void
Private getCadModel
getCadModel()

Get URL to show CAD 3D Model

Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
Public selectConfig
selectConfig(configName, configValue)

Update CAD 3D model preview when selecting a configuration

Parameters :
Name Optional
configName No
configValue No
Returns : void
Public setView
setView(view)
Parameters :
Name Optional
view No
Returns : void

Properties

Private Readonly CAD_CONF_URL
Type : string
Default value : 'https://www.partserver.de/cadqualifier.asp?firm=skf'
cad2D
Default value : new FormControl()
cad3DNative
Default value : new FormControl()
cad3DNeutral
Default value : new FormControl()
cadConfigBack
Type : string
cadConfigIntro
Type : string
cadConfigNext
Type : string
cadDownload2D
Type : []
Default value : []
cadDownload3DNative
Type : []
Default value : []
cadDownload3DNeutral
Type : []
Default value : []
cadDownloadButton
Decorators :
@ViewChild('cadDownload')
cadDownloadButtonTitle
Type : string
cadDownloading
Type : boolean
Private Readonly CADENAS_URL
Type : string
Default value : 'https://webapi.partcommunity.com/cgi-bin/cgi2pview.exe'
cadFormatNotChosen
Type : string
cadFormatsIntro
Type : string
cadModelUrl
Type : SafeResourceUrl
cadSectionTitle
Type : string
configOptions
Type : []
Default value : []
downloadMessageBody
Type : string
downloadMessageTitle
Type : string
Private Readonly MIDENT_DESIGNATION_URL
Type : string
Default value : 'https://webassistants.partcommunity.com/23d-libs/skf/mapping/get_mident_index_designation.vbb'
parser
Default value : new DOMParser()
part
Type : string
pdfDownloadButton
Decorators :
@ViewChild('pdfDownload')
pdfDownloadButtonTitle
Type : string
pdfDownloading
Type : boolean
select2Dtitle
Type : string
selectDefaultValue
Type : string
selectNative3Dtitle
Type : string
selectNeutral3Dtitle
Type : string
subscriptions
Type : []
Default value : []
view
Type : "CONFIG" | "FORMAT"
Default value : 'FORMAT'
import { Component, OnInit, Input, HostBinding, Output, EventEmitter, OnDestroy, ViewChild } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
import { FormControl } from '@angular/forms';
import { retryWhen, delay } from 'rxjs/operators';
import { LabelService } from 'src/app/core/services/label-service/label-service.service';
import { ConstantsService } from 'src/app/shared/constants/constants.service';

@Component({
	selector: '[cad-download]',
	templateUrl: './cad-download.component.html',
	styleUrls: ['./cad-download.component.scss']
})
export class CadDownloadComponent implements OnInit, OnDestroy {

	@Input() designation: string;
	@Output() available: EventEmitter<boolean> = new EventEmitter();

	private readonly MIDENT_DESIGNATION_URL = 'https://webassistants.partcommunity.com/23d-libs/skf/mapping/get_mident_index_designation.vbb';
	private readonly CADENAS_URL = 'https://webapi.partcommunity.com/cgi-bin/cgi2pview.exe';
	private readonly CAD_CONF_URL = 'https://www.partserver.de/cadqualifier.asp?firm=skf';

	cadModelUrl: SafeResourceUrl;
	part: string;
	parser = new DOMParser();
	subscriptions = [];
	cadDownloading: boolean;
	pdfDownloading: boolean;
	view: 'CONFIG' | 'FORMAT' = 'FORMAT';

	cadDownload3DNeutral = [];
	cadDownload3DNative = [];
	cadDownload2D = [];

	configOptions = [];

	cad2D = new FormControl();
	cad3DNative = new FormControl();
	cad3DNeutral = new FormControl();

	// Labels
	cadSectionTitle: string;
	cadFormatsIntro: string;
	selectDefaultValue: string;
	selectNative3Dtitle: string;
	selectNeutral3Dtitle: string;
	select2Dtitle: string;
	cadDownloadButtonTitle: string;
	pdfDownloadButtonTitle: string;
	cadConfigIntro: string;
	cadConfigNext: string;
	cadConfigBack: string;
	cadFormatNotChosen: string;
	downloadMessageTitle: string;
	downloadMessageBody: string;

	@ViewChild('pdfDownload') pdfDownloadButton;
	@ViewChild('cadDownload') cadDownloadButton;

	@HostBinding('class') get class() { return 'space-between'; }
	@HostBinding('attr.id') id = `${this.constants.COMPONENT_ID_PREFIX}-cad-download`;

	constructor(
		private http: HttpClient,
		private sanitizer: DomSanitizer,
		private labelService: LabelService,
		private constants: ConstantsService
	) {}

	ngOnInit() {
		this.labelService.getLabel('cadSectionTitle').then(label => this.cadSectionTitle = label);
		this.labelService.getLabel('cadFormatsIntroText').then(label => this.cadFormatsIntro = label);
		this.labelService.getLabel('cadDefaultValueFormatDropDowns').then(label => this.selectDefaultValue = label);
		this.labelService.getLabel('cadFormatNative3Dtitle').then(label => this.selectNative3Dtitle = label);
		this.labelService.getLabel('cadFormatNeutral3Dtitle').then(label => this.selectNeutral3Dtitle = label);
		this.labelService.getLabel('cadFormat2DandPicturetitle').then(label => this.select2Dtitle = label);
		this.labelService.getLabel('cadDownloadButtonTitle').then(label => this.cadDownloadButtonTitle = label);
		this.labelService.getLabel('cadPdfDownloadButtonTitle').then(label => this.pdfDownloadButtonTitle = label);
		this.labelService.getLabel('cadConfigIntroText').then(label => this.cadConfigIntro = label);
		this.labelService.getLabel('cadConfigNextButtonTitle').then(label => this.cadConfigNext = label);
		this.labelService.getLabel('cadConfigBackButtonTitle').then(label => this.cadConfigBack = label);
		this.labelService.getLabel('cadFormatNotChosen').then(label => this.cadFormatNotChosen = label);
		this.labelService.getLabel('cadDownloadThanksMessageTitle').then(label => this.downloadMessageTitle = label);
		this.labelService.getLabel('cadDownloadThanksMessageText').then(label => this.downloadMessageBody = label);

		this.getCadModel();
		this.getCadFormats();
		this.cadFormatListener();
	}

	ngOnDestroy(): void {
		this.subscriptions.forEach(sub => sub.unsubscribe());
	}

	/** Download ZIP file containing CAD file of chosen format.*/
	public downloadCAD(): void {
		const format = this.cad2D.value || this.cad3DNative.value || this.cad3DNeutral.value;

		// If no format has been chosen, set form to invalid.
		if (!format || format === 'null') {
			this.cad2D.setErrors({
				invalid: true
			});
			this.cad3DNative.setErrors({
				invalid: true
			});
			this.cad3DNeutral.setErrors({
				invalid: true
			});
		} else {
			const ok_url = encodeURIComponent('<%download_xml%>');
			const downloadXMLUrl = `${this.CADENAS_URL}?firm=skf&cgiaction=download&ok_url=${ok_url}&ok_url_type=text&downloadflags=ZIP&part=${this.part}&format=${format}`;
			this.cadDownloading = true;
			this.downloadZIP(downloadXMLUrl, 'cad');
		}
	}

	/** Download PDF of current designation. */
	public downloadPDF() {
		const ok_url = encodeURIComponent('<%download_xml%>');
		const downloadXMLUrl = `${this.CADENAS_URL}?firm=skf&cgiaction=download&ok_url=${ok_url}&ok_url_type=text&downloadflags=ZIP&part=${this.part}&format=PDFDATASHEET`;
		this.pdfDownloading = true;
		this.downloadZIP(downloadXMLUrl, 'pdf');
	}

	private downloadZIP(url: string, type?: string) {

		// Fetch URL to download.xml, where the name of the generated ZIP file can be found.
		this.http.get(url, { responseType: 'text' }).toPromise().then(downloadUrl => {

			let headers = new HttpHeaders();
			headers = headers.append('Content-Type', 'text/xml');
			headers = headers.append('Accept', 'text/xml');

			// Get file name of the generated ZIP.
			this.http.get(downloadUrl, { headers: headers, responseType: 'text' as 'text' }).pipe(
				retryWhen(errors => errors.pipe(delay(1500)))	// CADENAS file generation might take a couple of seconds, retry until it succeedes.
			).toPromise().then(res => {
				const xmlDoc = this.parser.parseFromString(res, 'text/xml');
				const zipFile = xmlDoc.getElementsByTagName('ZIPFILE')[0].textContent;
				downloadUrl = downloadUrl.replace('download.xml', zipFile);

				// Create temporary a tag to open zip file in browser.
				const downloadLink = document.createElement('a');
				downloadLink.href = downloadUrl;
				document.body.appendChild(downloadLink);
				downloadLink.click();
				downloadLink.parentNode.removeChild(downloadLink);	// Remove tag after zip file has opened.

				// Reset loading spinners
				this.pdfDownloading = false;
				this.cadDownloading = false;

				if (type === 'cad') {
					this.cadDownloadButton.open();
				} else if (type === 'pdf') {
					this.pdfDownloadButton.open();
				}

			},
			error => {
				console.error('ERROR: Zip file could not be generated.');
			});
		});
	}

	/** Get all available CAD formats from CADENAS. */
	private getCadFormats(): void {
		this.http.get(this.CAD_CONF_URL, { responseType: 'text' }).toPromise().then(
			res => {
				const xmlDoc = this.parser.parseFromString(res, 'text/xml');
				const formats = xmlDoc.querySelectorAll('format');

				// Loop through XML and fill CAD download config dropdowns.
				formats.forEach(format => {
					const cad = format.getAttribute('cad');
					const name = format.getElementsByTagName('name')[0].textContent;
					const version = format.getElementsByTagName('version')[0].textContent;
					const qualifier = format.getElementsByTagName('qualifier')[0].textContent;
					const nameText = version ? `${name} (${version})` : name;

					// Check CAD type and put in right array.
					if (cad === '2d') {
						this.cadDownload2D.push({ name: nameText, value: qualifier });
					} else if (cad === '3d') {
						const type = format.getAttribute('type');

						if (type === 'neutral') {
							this.cadDownload3DNeutral.push({ name: nameText, value: qualifier });
						}
						else if (type === 'native') {
							this.cadDownload3DNative.push({ name: nameText, value: qualifier });
						}
					}
				});
			},
			error => {
				console.error('ERROR: CAD formats failed');
			}
		);
	}

	/** Get URL to show CAD 3D Model */
	private getCadModel(): void {
		// Fetch info about MIDENT project path and product ID.
		this.http.get(`${this.MIDENT_DESIGNATION_URL}?designation=${this.designation}`)
			.toPromise().then(
				res => {
					if (res['error']) {
						console.error('ERROR: No CAD model found');
						this.available.emit(false);
						return;
					}
					else {
						this.available.emit(true);
					}

					const projectPath = res['prjPath'];
					const productKey = res['fixName'];
					const productId = encodeURIComponent(res['fixValue']);
					this.part = `{${projectPath}},{${productKey}=${productId}}`;

					// URL for 3D CAD model. Use sanitizer to stop browser from complaining-
					this.cadModelUrl = this.sanitizer.bypassSecurityTrustResourceUrl(`${this.CADENAS_URL}?firm=skf&cgiaction=preview&part=${this.part}`);

					// Check if configurable options exist.
					const configs = res['valueRanges'];

					if (configs) {
						this.setView('CONFIG');

						configs.forEach(config => {
							const configTitle = config['desc'];
							const configValues = [];

							config['varValues'].forEach((value, index) => {
								const varName = config['varNames'][index];

								configValues.push({
									'varName': varName,
									'varValue': value
								});
							});

							this.configOptions.push({
								'name': configTitle,
								'values': configValues
							});
						});
					}
				},
				error => {
					console.error('ERROR: CAD model failed');
				}
		);
	}

	/** Listens to CAD format selection boxes and makes sure max one is selected. */
	private cadFormatListener(): void {
		this.subscriptions.push(this.cad2D.valueChanges.subscribe(() => {
			this.cad3DNative.setValue(null, { emitEvent: false });
			this.cad3DNeutral.setValue(null, { emitEvent: false });
		}));

		this.subscriptions.push(this.cad3DNative.valueChanges.subscribe(() => {
			this.cad2D.setValue(null, { emitEvent: false });
			this.cad3DNeutral.setValue(null, { emitEvent: false });
		}));

		this.subscriptions.push(this.cad3DNeutral.valueChanges.subscribe(() => {
			this.cad3DNative.setValue(null, { emitEvent: false });
			this.cad2D.setValue(null, { emitEvent: false });
		}));
	}

	/** Update CAD 3D model preview when selecting a configuration */
	public selectConfig(configName, configValue): void {

		// If config value is null, remove it from part. Else add it to part.
		if (!configValue.varValue) {
			const partMatch = this.part.match(`,{${configName}=(.*)}`);
			this.part = this.part.replace(partMatch[0], '');
		} else {
			this.part += `,{${configName}=${configValue.varValue}}`;
		}

		// URL for 3D CAD model
		this.cadModelUrl = this.sanitizer.bypassSecurityTrustResourceUrl(`${this.CADENAS_URL}?firm=skf&cgiaction=preview&part=${this.part}`);
	}

	public setView(view) {
		this.view = view;
	}
}
<div class="container">
	<h2 class="title">{{cadSectionTitle}}</h2>
	<div class="row">
		<div class="col-lg-6 cad-model">
			<iframe [src]="cadModelUrl" *ngIf="cadModelUrl"></iframe>
		</div>
		<div class="col-lg-5 offset-lg-1" [hidden]="!(configOptions.length === 0 || view === 'FORMAT')">
			<p class="intro">{{cadFormatsIntro}}</p>
			<form>
				<div class="no-format" *ngIf="cad2D.invalid">
					{{cadFormatNotChosen}}
				</div>
				<div class="form-group">
					<label for="cad2D">{{select2Dtitle}}</label>
					<select class="form-control" id="cad2D" [ngClass]="{'is-invalid': cad2D.invalid}" [formControl]="cad2D">
						<option [value]="null">{{selectDefaultValue}}</option>
						<option *ngFor="let option of cadDownload2D" [value]="option.value">{{option.name}}</option>
					</select>
				</div>
				<div class="form-group">
					<label for="cad3Dneutral">{{selectNeutral3Dtitle}}</label>
					<select class="form-control" [ngClass]="{'is-invalid': cad3DNeutral.invalid}" id="cad3Dneutral" [formControl]="cad3DNeutral">
						<option [value]="null">{{selectDefaultValue}}</option>
						<option *ngFor="let option of cadDownload3DNeutral" [value]="option.value">{{option.name}}</option>
					</select>
				</div>
				<div class="form-group">
					<label for="cad3Dnative">{{selectNative3Dtitle}}</label>
					<select class="form-control" [ngClass]="{'is-invalid': cad3DNative.invalid}" id="cad3Dnative" [formControl]="cad3DNative">
						<option [value]="null">{{selectDefaultValue}}</option>
						<option *ngFor="let option of cadDownload3DNative" [value]="option.value">{{option.name}}</option>
					</select>
				</div>
				<div class="button-wrapper">
					<button type="button" class="btn btn-cool-grey mr-1 mb-1" *ngIf="configOptions.length > 0" (click)="setView('CONFIG')">
						{{cadConfigBack}}
					</button>
					<button type="button" class="btn btn-green mr-1 mb-1" [ngClass]="{'loading': cadDownloading}" (click)="downloadCAD()" #cadDownload="ngbPopover" [ngbPopover]="downloadMessage" [popoverTitle]="popTitle" placement="top" autoClose="inside" triggers="manual">
						<span class="spinner-border spinner-border-sm mr-1 mt-1" role="status" aria-hidden="true" [ngClass]="{'invisible': !cadDownloading}">
							<span class="sr-only">Loading...</span>
						</span>
						<span>{{cadDownloadButtonTitle | uppercase}}</span>
					</button>
					<button type="button" class="btn btn-green mr-1 mb-1" [ngClass]="{'loading': pdfDownloading}" (click)="downloadPDF()" #pdfDownload="ngbPopover" [ngbPopover]="downloadMessage" [popoverTitle]="popTitle" placement="top" autoClose="inside" triggers="manual">
						<span class="spinner-border spinner-border-sm mr-1 mt-1" role="status" aria-hidden="true" [ngClass]="{'invisible': !pdfDownloading}">
							<span class="sr-only">Loading...</span>
						</span>
						<span>{{pdfDownloadButtonTitle | uppercase}}</span>
					</button>
					<ng-template #popTitle>{{downloadMessageTitle}} <i class="icon-nav-close"></i></ng-template>
					<ng-template #downloadMessage>{{downloadMessageBody}}</ng-template>
				</div>
			</form>
		</div>

		<div class="col-lg-5 offset-lg-1 config" [hidden]="!(configOptions.length > 0 && view === 'CONFIG')">
			<div>
				<p class="intro">{{cadFormatsIntro}}</p>
				<div class="config-options" *ngFor="let config of configOptions">
					<h4>{{config.name}}</h4>
					<div class="form-check" *ngFor="let value of config.values; let i=index">
						<input class="form-check-input" type="radio" [id]="config.name + '-' + i" [name]="config.name"
							[value]="value.varValue" (click)="selectConfig(config.name, value)" [checked]="value.varValue == null">
						<label class="form-check-label" [for]="config.name + '-' + i">
							{{value.varName}}
						</label>
					</div>
				</div>
				<button type="button" class="btn btn-green" (click)="setView('FORMAT')">{{cadConfigNext}}</button>
			</div>
		</div>
	</div>
</div>

./cad-download.component.scss

@import "src/app/styles/helpers";
@import "~bootstrap/scss/spinners";

.title {
	margin-bottom: calc-rem(40);
	color: $dark-blue;
}

.cad-model {
	display: flex;
	justify-content: center;

	iframe {
		width: calc-rem(400);
		height: calc-rem(400);
		border: none;
	}

	@include media-breakpoint-down(md) {
		margin-bottom: calc-rem(30);
	}
}

.intro {
	margin-bottom: calc-rem(30);
}

.no-format {
	color: $red;
	@include font-size(14);
	margin-bottom: calc-rem(10);
}

.btn {
	position: relative;
	display: flex;
	flex: 1 1 auto;
	justify-content: center;
	align-items: center;

	&:focus {
		outline: none !important;
		border: none !important;
		box-shadow: none;
	}

	&.loading {
		background-color:rgba(136, 192, 8, 0.3);// #green with 30% opacity
		border-color: rgba(136, 192, 8, 0.3);	// #green with 30% opacity
	}

	.spinner-border {
		position: absolute;
		right: 50%;
		top: 6px;
		color: $blue;
	}	
}

.button-wrapper {
	display: flex;
	margin-top: calc-rem(30);
	flex-wrap: wrap;
}

.config {
	display: flex;
	flex-direction: column;
	justify-content: center;

	.config-options {
		margin-bottom: calc-rem(20);
	}
}

.icon-nav-close{
	float: right;
	cursor: pointer;
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""