mappers.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import { Tools } from 'babylonjs';
  2. import { ViewerConfiguration } from './configuration';
  3. import { kebabToCamel } from '../helper';
  4. /**
  5. * This is the mapper's interface. Implement this function to create your own mapper and register it at the mapper manager
  6. */
  7. export interface IMapper {
  8. map(rawSource: any): ViewerConfiguration;
  9. }
  10. /**
  11. * This is a simple HTML mapper.
  12. * This mapper parses a single HTML element and returns the configuration from its attributes.
  13. * it parses numbers and boolean values to the corresponding variable types.
  14. * The following HTML element:
  15. * <div test="1" random-flag="true" a.string.object="test"> will result in the following configuration:
  16. *
  17. * {
  18. * test: 1, //a number!
  19. * randomFlag: boolean, //camelCase and boolean
  20. * a: {
  21. * string: {
  22. * object: "test" //dot-separated object levels
  23. * }
  24. * }
  25. * }
  26. */
  27. class HTMLMapper implements IMapper {
  28. /**
  29. * Map a specific element and get configuration from it
  30. * @param element the HTML element to analyze.
  31. */
  32. map(element: HTMLElement): ViewerConfiguration {
  33. let config = {};
  34. for (let attrIdx = 0; attrIdx < element.attributes.length; ++attrIdx) {
  35. let attr = element.attributes.item(attrIdx);
  36. // map "object.property" to the right configuration place.
  37. let split = attr.nodeName.split('.');
  38. split.reduce((currentConfig, key, idx) => {
  39. //convert html-style to json-style
  40. let camelKey = kebabToCamel(key);
  41. if (idx === split.length - 1) {
  42. let val: any = attr.nodeValue; // firefox warns nodeValue is deprecated, but I found no sign of it anywhere.
  43. if (val === "true") {
  44. val = true;
  45. } else if (val === "false") {
  46. val = false;
  47. } else {
  48. var isnum = /^\d+$/.test(val);
  49. if (isnum) {
  50. let number = parseFloat(val);
  51. if (!isNaN(number)) {
  52. val = number;
  53. }
  54. }
  55. }
  56. currentConfig[camelKey] = val;
  57. } else {
  58. currentConfig[camelKey] = currentConfig[camelKey] || {};
  59. }
  60. return currentConfig[camelKey];
  61. }, config);
  62. }
  63. return config;
  64. }
  65. }
  66. class JSONMapper implements IMapper {
  67. map(rawSource: any) {
  68. return JSON.parse(rawSource);
  69. }
  70. }
  71. // TODO - Dom configuration mapper.
  72. class DOMMapper implements IMapper {
  73. map(baseElement: HTMLElement): ViewerConfiguration {
  74. let htmlMapper = new HTMLMapper();
  75. let config = htmlMapper.map(baseElement);
  76. let traverseChildren = function (element: HTMLElement, partConfig) {
  77. let children = element.children;
  78. if (children.length) {
  79. for (let i = 0; i < children.length; ++i) {
  80. let item = <HTMLElement>children.item(i);
  81. let configMapped = htmlMapper.map(item);
  82. let key = kebabToCamel(item.nodeName.toLowerCase());
  83. if (item.attributes.getNamedItem('array') && item.attributes.getNamedItem('array').nodeValue === 'true') {
  84. partConfig[key] = [];
  85. } else {
  86. if (element.attributes.getNamedItem('array') && element.attributes.getNamedItem('array').nodeValue === 'true') {
  87. partConfig.push(configMapped)
  88. } else if (partConfig[key]) {
  89. //exists already! problem... probably an array
  90. element.setAttribute('array', 'true');
  91. let oldItem = partConfig[key];
  92. partConfig = [oldItem, configMapped]
  93. } else {
  94. partConfig[key] = configMapped;
  95. }
  96. }
  97. traverseChildren(item, partConfig[key] || configMapped);
  98. }
  99. }
  100. return partConfig;
  101. }
  102. traverseChildren(baseElement, config);
  103. return config;
  104. }
  105. }
  106. export class MapperManager {
  107. private _mappers: { [key: string]: IMapper };
  108. public static DefaultMapper = 'json';
  109. constructor() {
  110. this._mappers = {
  111. "html": new HTMLMapper(),
  112. "json": new JSONMapper(),
  113. "dom": new DOMMapper()
  114. }
  115. }
  116. public getMapper(type: string) {
  117. if (!this._mappers[type]) {
  118. Tools.Error("No mapper defined for " + type);
  119. }
  120. return this._mappers[type] || this._mappers[MapperManager.DefaultMapper];
  121. }
  122. public registerMapper(type: string, mapper: IMapper) {
  123. this._mappers[type] = mapper;
  124. }
  125. public dispose() {
  126. this._mappers = {};
  127. }
  128. }
  129. export let mapperManager = new MapperManager();