app/dxa/dxa-entity/views/cad-download/cad-download.component.ts
selector | [cad-download] |
styleUrls | ./cad-download.component.scss |
templateUrl | ./cad-download.component.html |
Properties |
|
Methods |
|
Inputs |
Outputs |
HostBindings |
constructor(http: HttpClient, sanitizer: DomSanitizer, labelService: LabelService, constants: ConstantsService)
|
|||||||||||||||
Parameters :
|
designation | |
Type : string
|
|
available | |
Type : EventEmitter<boolean>
|
|
attr.id |
Default value : `${this.constants.COMPONENT_ID_PREFIX}-cad-download`
|
class |
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)
|
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 :
Returns :
void
|
Public setView | ||||
setView(view)
|
||||
Parameters :
Returns :
void
|
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;
}