src/app/group-monitor/booklet/booklet.service.ts
Properties |
Methods |
|
constructor(bs: BackendService)
|
||||||
Parameters :
|
Private Static addBookletStructureInformation | ||||||
addBookletStructureInformation(booklet: Booklet)
|
||||||
Parameters :
Returns :
void
|
getBooklet | ||||||||
getBooklet(bookletName: string)
|
||||||||
Parameters :
Returns :
Observable<Booklet | BookletError>
|
Private Static getBookletSpecies | ||||||
getBookletSpecies(booklet: Booklet)
|
||||||
Parameters :
Returns :
string
|
Private Static parseBookletConfig | ||||||
parseBookletConfig(bookletElement: Element)
|
||||||
Parameters :
Returns :
BookletConfig
|
Private Static parseBookletXml | ||||||
parseBookletXml(xmlString: string)
|
||||||
Parameters :
Returns :
Booklet | BookletError
|
Private Static parseMetadata | ||||||
parseMetadata(bookletElement: Element)
|
||||||
Parameters :
Returns :
BookletMetadata
|
Private Static parseRestrictions | ||||||
parseRestrictions(testletElement: Element)
|
||||||
Parameters :
Returns :
Restrictions
|
Private Static parseTestlet | ||||||
parseTestlet(testletElement: Element)
|
||||||
Parameters :
Returns :
Testlet
|
Private Static parseUnitOrTestlet | ||||||
parseUnitOrTestlet(unitOrTestletElement: Element)
|
||||||
Parameters :
Returns :
Unit | Testlet
|
Private Static xmlCountChildrenOfTagNames | |||||||||
xmlCountChildrenOfTagNames(element: Element, tagNames: string[])
|
|||||||||
Parameters :
Returns :
number
|
Private Static xmlGetChildIfExists | ||||||||||||||||
xmlGetChildIfExists(element: Element, childName: string, isOptional)
|
||||||||||||||||
Parameters :
Returns :
Element
|
Private Static xmlGetChildTextIfExists | ||||||||||||||||
xmlGetChildTextIfExists(element: Element, childName: string, isOptional)
|
||||||||||||||||
Parameters :
Returns :
string
|
booklets |
Type : Observable<Booklet | BookletError>[]
|
Default value : []
|
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { map, shareReplay } from 'rxjs/operators';
import { MainDataService } from '../../maindata.service';
import { BackendService } from '../backend.service';
import {
Booklet, BookletError, BookletMetadata, isUnit, Restrictions, Testlet, Unit
} from '../group-monitor.interfaces';
// eslint-disable-next-line import/extensions
import { BookletConfig } from '../../config/booklet-config';
@Injectable()
export class BookletService {
booklets: Observable<Booklet|BookletError>[] = [];
constructor(
private bs: BackendService
) { }
getBooklet(bookletName = ''): Observable<Booklet|BookletError> {
if (typeof this.booklets[bookletName] !== 'undefined') {
return this.booklets[bookletName];
}
if (bookletName === '') {
this.booklets[bookletName] = of<Booklet|BookletError>({ error: 'missing-id', species: null });
} else {
this.booklets[bookletName] = this.bs.getBooklet(bookletName)
.pipe(
// eslint-disable-next-line max-len
map((response: string|BookletError) => (typeof response === 'string' ? BookletService.parseBookletXml(response) : response)),
shareReplay(1)
);
}
return this.booklets[bookletName];
}
private static parseBookletXml(xmlString: string): Booklet|BookletError {
try {
const domParser = new DOMParser();
const bookletElement = domParser.parseFromString(xmlString, 'text/xml').documentElement;
if (bookletElement.nodeName !== 'Booklet') {
// console.warn('XML-root is not `Booklet`');
return { error: 'xml', species: null };
}
const parsedBooklet: Booklet = {
units: BookletService.parseTestlet(BookletService.xmlGetChildIfExists(bookletElement, 'Units')),
metadata: BookletService.parseMetadata(bookletElement),
config: BookletService.parseBookletConfig(bookletElement),
species: ''
};
BookletService.addBookletStructureInformation(parsedBooklet);
return parsedBooklet;
} catch (error) {
// console.warn('Error reading booklet XML:', error);
return { error: 'xml', species: null };
}
}
private static addBookletStructureInformation(booklet: Booklet): void {
booklet.species = BookletService.getBookletSpecies(booklet);
booklet.units.children
.filter(testletOrUnit => !isUnit(testletOrUnit))
.forEach((block: Testlet, index, blocks) => {
block.blockId = `block ${index + 1}`;
if (index < blocks.length - 1) {
block.nextBlockId = `block ${index + 2}`;
}
});
}
private static getBookletSpecies(booklet: Booklet): string {
return `species: ${booklet.units.children.filter(testletOrUnit => !isUnit(testletOrUnit)).length}`;
}
private static parseBookletConfig(bookletElement: Element): BookletConfig {
const bookletConfigElements = BookletService.xmlGetChildIfExists(bookletElement, 'BookletConfig', true);
const bookletConfig = new BookletConfig();
bookletConfig.setFromKeyValuePairs(MainDataService.getTestConfig());
if (bookletConfigElements) {
bookletConfig.setFromXml(bookletConfigElements[0]);
}
return bookletConfig;
}
private static parseMetadata(bookletElement: Element): BookletMetadata {
const metadataElement = BookletService.xmlGetChildIfExists(bookletElement, 'Metadata');
return {
id: BookletService.xmlGetChildTextIfExists(metadataElement, 'Id'),
label: BookletService.xmlGetChildTextIfExists(metadataElement, 'Label'),
description: BookletService.xmlGetChildTextIfExists(metadataElement, 'Description', true)
};
}
private static parseTestlet(testletElement: Element): Testlet {
return {
id: testletElement.getAttribute('id'),
label: testletElement.getAttribute('label') || '',
restrictions: BookletService.parseRestrictions(testletElement),
children: BookletService.xmlGetDirectChildrenByTagName(testletElement, ['Unit', 'Testlet'])
.map(BookletService.parseUnitOrTestlet),
descendantCount: BookletService.xmlCountChildrenOfTagNames(testletElement, ['Unit'])
};
}
private static parseUnitOrTestlet(unitOrTestletElement: Element): (Unit|Testlet) {
if (unitOrTestletElement.tagName === 'Unit') {
return {
id: unitOrTestletElement.getAttribute('alias') || unitOrTestletElement.getAttribute('id'),
label: unitOrTestletElement.getAttribute('label'),
labelShort: unitOrTestletElement.getAttribute('labelshort')
};
}
return BookletService.parseTestlet(unitOrTestletElement);
}
private static parseRestrictions(testletElement: Element): Restrictions {
const restrictions: Restrictions = {};
const restrictionsElement = BookletService.xmlGetChildIfExists(testletElement, 'Restrictions', true);
if (!restrictionsElement) {
return restrictions;
}
const codeToEnterElement = restrictionsElement.querySelector('CodeToEnter');
if (codeToEnterElement) {
restrictions.codeToEnter = {
code: codeToEnterElement.getAttribute('code'),
message: codeToEnterElement.textContent
};
}
const timeMaxElement = restrictionsElement.querySelector('TimeMax');
if (timeMaxElement) {
restrictions.timeMax = {
minutes: parseFloat(timeMaxElement.getAttribute('minutes'))
};
}
return restrictions;
}
private static xmlGetChildIfExists(element: Element, childName: string, isOptional = false): Element {
const elements = BookletService.xmlGetDirectChildrenByTagName(element, [childName]);
if (!elements.length && !isOptional) {
throw new Error(`Missing field: '${childName}'`);
}
return elements.length ? elements[0] : null;
}
private static xmlGetChildTextIfExists(element: Element, childName: string, isOptional = false): string {
const childElement = BookletService.xmlGetChildIfExists(element, childName, isOptional);
return childElement ? childElement.textContent : '';
}
private static xmlGetDirectChildrenByTagName(element: Element, tagNames: string[]): Element[] {
return [].slice.call(element.childNodes)
.filter((elem: Element) => (elem.nodeType === 1))
.filter((elem: Element) => (tagNames.indexOf(elem.tagName) > -1));
}
private static xmlCountChildrenOfTagNames(element: Element, tagNames: string[]): number {
return element.querySelectorAll(tagNames.join(', ')).length;
}
}