123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- import { Tools } from 'babylonjs';
- import { ViewerConfiguration } from './configuration';
- import { kebabToCamel } from '../helper';
- /**
- * This is the mapper's interface. Implement this function to create your own mapper and register it at the mapper manager
- */
- export interface IMapper {
- map(rawSource: any): ViewerConfiguration;
- }
- /**
- * This is a simple HTML mapper.
- * This mapper parses a single HTML element and returns the configuration from its attributes.
- * it parses numbers and boolean values to the corresponding variable types.
- * The following HTML element:
- * <div test="1" random-flag="true" a.string.object="test"> will result in the following configuration:
- *
- * {
- * test: 1, //a number!
- * randomFlag: boolean, //camelCase and boolean
- * a: {
- * string: {
- * object: "test" //dot-separated object levels
- * }
- * }
- * }
- */
- class HTMLMapper implements IMapper {
- /**
- * Map a specific element and get configuration from it
- * @param element the HTML element to analyze.
- */
- map(element: HTMLElement): ViewerConfiguration {
- let config = {};
- for (let attrIdx = 0; attrIdx < element.attributes.length; ++attrIdx) {
- let attr = element.attributes.item(attrIdx);
- if (!attr) {
- continue;
- }
- // map "object.property" to the right configuration place.
- let split = attr.nodeName.split('.');
- split.reduce((currentConfig, key, idx) => {
- //convert html-style to json-style
- let camelKey = kebabToCamel(key);
- if (idx === split.length - 1) {
- let val: any = attr!.nodeValue; // firefox warns nodeValue is deprecated, but I found no sign of it anywhere.
- if (val === "true") {
- val = true;
- } else if (val === "false") {
- val = false;
- } else {
- var isnum = !isNaN(parseFloat(val)) && isFinite(val);///^\d+$/.test(val);
- if (isnum) {
- let number = parseFloat(val);
- if (!isNaN(number)) {
- val = number;
- }
- }
- }
- currentConfig[camelKey] = val;
- } else {
- currentConfig[camelKey] = currentConfig[camelKey] || {};
- }
- return currentConfig[camelKey];
- }, config);
- }
- return config;
- }
- }
- /**
- * A simple string-to-JSON mapper.
- * This is the main mapper, used to analyze downloaded JSON-Configuration or JSON payload
- */
- class JSONMapper implements IMapper {
- map(rawSource: string) {
- return JSON.parse(rawSource);
- }
- }
- /**
- * The DOM Mapper will traverse an entire DOM Tree and will load the configuration from the
- * DOM elements and attributes.
- */
- class DOMMapper implements IMapper {
- /**
- * The mapping function that will convert HTML data to a viewer configuration object
- * @param baseElement the baseElement from which to start traversing
- * @returns a ViewerCOnfiguration object from the provided HTML Element
- */
- map(baseElement: HTMLElement): ViewerConfiguration {
- let htmlMapper = new HTMLMapper();
- let config = htmlMapper.map(baseElement);
- let traverseChildren = function (element: HTMLElement, partConfig) {
- let children = element.children;
- if (children.length) {
- for (let i = 0; i < children.length; ++i) {
- let item = <HTMLElement>children.item(i);
- // use the HTML Mapper to read configuration from a single element
- let configMapped = htmlMapper.map(item);
- let key = kebabToCamel(item.nodeName.toLowerCase());
- if (item.attributes.getNamedItem('array') && item.attributes.getNamedItem('array')!.nodeValue === 'true') {
- partConfig[key] = [];
- } else {
- if (element.attributes.getNamedItem('array') && element.attributes.getNamedItem('array')!.nodeValue === 'true') {
- partConfig.push(configMapped)
- } else if (partConfig[key]) {
- //exists already! probably an array
- element.setAttribute('array', 'true');
- let oldItem = partConfig[key];
- partConfig = [oldItem, configMapped]
- } else {
- partConfig[key] = configMapped;
- }
- }
- traverseChildren(item, partConfig[key] || configMapped);
- }
- }
- return partConfig;
- }
- traverseChildren(baseElement, config);
- return config;
- }
- }
- /**
- * The MapperManager manages the different implemented mappers.
- * It allows the user to register new mappers as well and use them to parse their own configuration data
- */
- export class MapperManager {
- private _mappers: { [key: string]: IMapper };
- /**
- * The default mapper is the JSON mapper.
- */
- public static DefaultMapper = 'json';
- constructor() {
- this._mappers = {
- "html": new HTMLMapper(),
- "json": new JSONMapper(),
- "dom": new DOMMapper()
- }
- }
- /**
- * Get a specific configuration mapper.
- *
- * @param type the name of the mapper to load
- */
- public getMapper(type: string) {
- if (!this._mappers[type]) {
- Tools.Error("No mapper defined for " + type);
- }
- return this._mappers[type] || this._mappers[MapperManager.DefaultMapper];
- }
- /**
- * Use this functio to register your own configuration mapper.
- * After a mapper is registered, it can be used to parse the specific type fo configuration to the standard ViewerConfiguration.
- * @param type the name of the mapper. This will be used to define the configuration type and/or to get the mapper
- * @param mapper The implemented mapper
- */
- public registerMapper(type: string, mapper: IMapper) {
- this._mappers[type] = mapper;
- }
- /**
- * Dispose the mapper manager and all of its mappers.
- */
- public dispose() {
- this._mappers = {};
- }
- }
- /**
- * mapperManager is a singleton of the type MapperManager.
- * The mapperManager can be disposed directly with calling mapperManager.dispose()
- * or indirectly with using BabylonViewer.disposeAll()
- */
- export let mapperManager = new MapperManager();
|