| 
									
										
										
										
											2016-06-23 09:47:54 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							| 
									
										
										
										
											2020-05-19 12:08:49 -07:00
										 |  |  |  * Copyright Google LLC All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2016-06-23 09:47:54 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-26 16:17:35 -07:00
										 |  |  | const SVG_PREFIX = ':svg:'; | 
					
						
							| 
									
										
										
										
											2016-09-01 17:32:47 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Element | Node interfaces
 | 
					
						
							|  |  |  | // see https://developer.mozilla.org/en-US/docs/Web/API/Element
 | 
					
						
							|  |  |  | // see https://developer.mozilla.org/en-US/docs/Web/API/Node
 | 
					
						
							|  |  |  | const ELEMENT_IF = '[Element]'; | 
					
						
							|  |  |  | // HTMLElement interface
 | 
					
						
							|  |  |  | // see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
 | 
					
						
							|  |  |  | const HTMLELEMENT_IF = '[HTMLElement]'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const HTMLELEMENT_TAGS = | 
					
						
							| 
									
										
										
										
											2016-09-01 19:37:09 -07:00
										 |  |  |     'abbr,address,article,aside,b,bdi,bdo,cite,code,dd,dfn,dt,em,figcaption,figure,footer,header,i,kbd,main,mark,nav,noscript,rb,rp,rt,rtc,ruby,s,samp,section,small,strong,sub,sup,u,var,wbr'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ALL_HTML_TAGS = | 
					
						
							|  |  |  |     // https://www.w3.org/TR/html5/index.html
 | 
					
						
							|  |  |  |     'a,abbr,address,area,article,aside,audio,b,base,bdi,bdo,blockquote,body,br,button,canvas,caption,cite,code,col,colgroup,data,datalist,dd,del,dfn,div,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,head,header,hr,html,i,iframe,img,input,ins,kbd,keygen,label,legend,li,link,main,map,mark,meta,meter,nav,noscript,object,ol,optgroup,option,output,p,param,pre,progress,q,rb,rp,rt,rtc,ruby,s,samp,script,section,select,small,source,span,strong,style,sub,sup,table,tbody,td,template,textarea,tfoot,th,thead,time,title,tr,track,u,ul,var,video,wbr,' + | 
					
						
							|  |  |  |     // https://html.spec.whatwg.org/
 | 
					
						
							|  |  |  |     'details,summary,menu,menuitem'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Elements missing from Chrome (HtmlUnknownElement), to be manually added
 | 
					
						
							|  |  |  | const MISSING_FROM_CHROME: {[el: string]: string[]} = { | 
					
						
							|  |  |  |   'data^[HTMLElement]': ['value'], | 
					
						
							| 
									
										
										
										
											2017-06-08 12:43:37 +03:00
										 |  |  |   'keygen^[HTMLElement]': ['!autofocus', 'challenge', '!disabled', 'form', 'keytype', 'name'], | 
					
						
							| 
									
										
										
										
											2016-09-01 19:37:09 -07:00
										 |  |  |   // TODO(vicb): Figure out why Chrome and WhatWG do not agree on the props
 | 
					
						
							|  |  |  |   // 'menu^[HTMLElement]': ['type', 'label'],
 | 
					
						
							|  |  |  |   'menuitem^[HTMLElement]': | 
					
						
							|  |  |  |       ['type', 'label', 'icon', '!disabled', '!checked', 'radiogroup', '!default'], | 
					
						
							|  |  |  |   'summary^[HTMLElement]': [], | 
					
						
							|  |  |  |   'time^[HTMLElement]': ['dateTime'], | 
					
						
							| 
									
										
										
										
											2017-07-06 12:11:34 -07:00
										 |  |  |   ':svg:cursor^:svg:': [], | 
					
						
							| 
									
										
										
										
											2016-09-01 19:37:09 -07:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2016-04-28 17:50:03 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-30 22:34:15 -07:00
										 |  |  | const _G: any = typeof window != 'undefined' && window || typeof global != 'undefined' && global || | 
					
						
							|  |  |  |     typeof self != 'undefined' && self; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  | const document: any = typeof _G['document'] == 'object' ? _G['document'] : null; | 
					
						
							| 
									
										
										
										
											2016-04-28 17:50:03 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:58 -07:00
										 |  |  | export function extractSchema(): Map<string, string[]>|null { | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  |   if (!document) return null; | 
					
						
							|  |  |  |   const SVGGraphicsElement = _G['SVGGraphicsElement']; | 
					
						
							|  |  |  |   if (!SVGGraphicsElement) return null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const element = document.createElement('video'); | 
					
						
							|  |  |  |   const descMap: Map<string, string[]> = new Map(); | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |   const visited: {[name: string]: boolean} = {}; | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // HTML top level
 | 
					
						
							| 
									
										
										
										
											2016-09-01 17:32:47 -07:00
										 |  |  |   extractProperties(Node, element, visited, descMap, ELEMENT_IF, ''); | 
					
						
							|  |  |  |   extractProperties(Element, element, visited, descMap, ELEMENT_IF, ''); | 
					
						
							|  |  |  |   extractProperties(HTMLElement, element, visited, descMap, HTMLELEMENT_IF, ELEMENT_IF); | 
					
						
							|  |  |  |   extractProperties(HTMLElement, element, visited, descMap, HTMLELEMENT_TAGS, HTMLELEMENT_IF); | 
					
						
							|  |  |  |   extractProperties(HTMLMediaElement, element, visited, descMap, 'media', HTMLELEMENT_IF); | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // SVG top level
 | 
					
						
							| 
									
										
										
										
											2017-07-06 12:11:34 -07:00
										 |  |  |   const svgAnimation = document.createElementNS('http://www.w3.org/2000/svg', 'set'); | 
					
						
							|  |  |  |   const svgPath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); | 
					
						
							|  |  |  |   const svgFeFuncA = document.createElementNS('http://www.w3.org/2000/svg', 'feFuncA'); | 
					
						
							|  |  |  |   const svgGradient = document.createElementNS('http://www.w3.org/2000/svg', 'linearGradient'); | 
					
						
							|  |  |  |   const svgText = document.createElementNS('http://www.w3.org/2000/svg', 'text'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const SVGAnimationElement = _G['SVGAnimationElement']; | 
					
						
							|  |  |  |   const SVGGeometryElement = _G['SVGGeometryElement']; | 
					
						
							|  |  |  |   const SVGComponentTransferFunctionElement = _G['SVGComponentTransferFunctionElement']; | 
					
						
							|  |  |  |   const SVGGradientElement = _G['SVGGradientElement']; | 
					
						
							|  |  |  |   const SVGTextContentElement = _G['SVGTextContentElement']; | 
					
						
							|  |  |  |   const SVGTextPositioningElement = _G['SVGTextPositioningElement']; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-01 17:32:47 -07:00
										 |  |  |   extractProperties(SVGElement, svgText, visited, descMap, SVG_PREFIX, HTMLELEMENT_IF); | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |   extractProperties( | 
					
						
							|  |  |  |       SVGGraphicsElement, svgText, visited, descMap, SVG_PREFIX + 'graphics', SVG_PREFIX); | 
					
						
							|  |  |  |   extractProperties( | 
					
						
							|  |  |  |       SVGAnimationElement, svgAnimation, visited, descMap, SVG_PREFIX + 'animation', SVG_PREFIX); | 
					
						
							|  |  |  |   extractProperties( | 
					
						
							|  |  |  |       SVGGeometryElement, svgPath, visited, descMap, SVG_PREFIX + 'geometry', SVG_PREFIX); | 
					
						
							|  |  |  |   extractProperties( | 
					
						
							|  |  |  |       SVGComponentTransferFunctionElement, svgFeFuncA, visited, descMap, | 
					
						
							|  |  |  |       SVG_PREFIX + 'componentTransferFunction', SVG_PREFIX); | 
					
						
							|  |  |  |   extractProperties( | 
					
						
							|  |  |  |       SVGGradientElement, svgGradient, visited, descMap, SVG_PREFIX + 'gradient', SVG_PREFIX); | 
					
						
							|  |  |  |   extractProperties( | 
					
						
							|  |  |  |       SVGTextContentElement, svgText, visited, descMap, SVG_PREFIX + 'textContent', | 
					
						
							|  |  |  |       SVG_PREFIX + 'graphics'); | 
					
						
							|  |  |  |   extractProperties( | 
					
						
							|  |  |  |       SVGTextPositioningElement, svgText, visited, descMap, SVG_PREFIX + 'textPositioning', | 
					
						
							|  |  |  |       SVG_PREFIX + 'textContent'); | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Get all element types
 | 
					
						
							|  |  |  |   const types = Object.getOwnPropertyNames(window).filter(k => /^(HTML|SVG).*?Element$/.test(k)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   types.sort(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 10:14:18 -07:00
										 |  |  |   types.forEach(type => { | 
					
						
							|  |  |  |     extractRecursiveProperties(visited, descMap, (window as any)[type]); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-06-02 10:27:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-01 19:37:09 -07:00
										 |  |  |   // Add elements missed by Chrome auto-detection
 | 
					
						
							|  |  |  |   Object.keys(MISSING_FROM_CHROME).forEach(elHierarchy => { | 
					
						
							|  |  |  |     descMap.set(elHierarchy, MISSING_FROM_CHROME[elHierarchy]); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   assertNoMissingTags(descMap); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 10:27:33 -07:00
										 |  |  |   return descMap; | 
					
						
							| 
									
										
										
										
											2016-04-28 17:50:03 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-01 19:37:09 -07:00
										 |  |  | function assertNoMissingTags(descMap: Map<string, string[]>): void { | 
					
						
							|  |  |  |   const extractedTags: string[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-03 16:58:27 -07:00
										 |  |  |   Array.from(descMap.keys()).forEach((key: string) => { | 
					
						
							|  |  |  |     extractedTags.push(...key.split('|')[0].split('^')[0].split(',')); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-09-01 19:37:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const missingTags = ALL_HTML_TAGS.split(',').filter(tag => extractedTags.indexOf(tag) == -1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (missingTags.length) { | 
					
						
							|  |  |  |     throw new Error(`DOM schema misses tags: ${missingTags.join(',')}`); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  | function extractRecursiveProperties( | 
					
						
							|  |  |  |     visited: {[name: string]: boolean}, descMap: Map<string, string[]>, type: Function): string { | 
					
						
							| 
									
										
										
										
											2020-04-08 10:14:18 -07:00
										 |  |  |   const name = extractName(type)!; | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (visited[name]) { | 
					
						
							|  |  |  |     return name; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let superName: string; | 
					
						
							|  |  |  |   switch (name) { | 
					
						
							| 
									
										
										
										
											2016-09-01 17:32:47 -07:00
										 |  |  |     case ELEMENT_IF: | 
					
						
							|  |  |  |       // ELEMENT_IF is the top most interface (Element | Node)
 | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  |       superName = ''; | 
					
						
							|  |  |  |       break; | 
					
						
							| 
									
										
										
										
											2016-09-01 17:32:47 -07:00
										 |  |  |     case HTMLELEMENT_IF: | 
					
						
							|  |  |  |       superName = ELEMENT_IF; | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       superName = | 
					
						
							|  |  |  |           extractRecursiveProperties(visited, descMap, type.prototype.__proto__.constructor); | 
					
						
							| 
									
										
										
										
											2016-04-28 17:50:03 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:58 -07:00
										 |  |  |   let instance: HTMLElement|null = null; | 
					
						
							| 
									
										
										
										
											2016-04-28 17:50:03 -07:00
										 |  |  |   name.split(',').forEach(tagName => { | 
					
						
							| 
									
										
										
										
											2016-09-01 17:32:47 -07:00
										 |  |  |     instance = type['name'].startsWith('SVG') ? | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  |         document.createElementNS('http://www.w3.org/2000/svg', tagName.replace(SVG_PREFIX, '')) : | 
					
						
							|  |  |  |         document.createElement(tagName); | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     let htmlType: Function; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (tagName) { | 
					
						
							|  |  |  |       case 'cite': | 
					
						
							| 
									
										
										
										
											2016-09-01 17:32:47 -07:00
										 |  |  |         // <cite> interface is `HTMLQuoteElement`
 | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  |         htmlType = HTMLElement; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         htmlType = type; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 17:50:03 -07:00
										 |  |  |     if (!(instance instanceof htmlType)) { | 
					
						
							|  |  |  |       throw new Error(`Tag <${tagName}> is not an instance of ${htmlType['name']}`); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 10:27:33 -07:00
										 |  |  |   extractProperties(type, instance, visited, descMap, name, superName); | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 17:50:03 -07:00
										 |  |  |   return name; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 16:38:52 -07:00
										 |  |  | function extractProperties( | 
					
						
							|  |  |  |     type: Function, instance: any, visited: {[name: string]: boolean}, | 
					
						
							|  |  |  |     descMap: Map<string, string[]>, name: string, superName: string) { | 
					
						
							| 
									
										
										
										
											2016-04-28 17:50:03 -07:00
										 |  |  |   if (!type) return; | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 17:50:03 -07:00
										 |  |  |   visited[name] = true; | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 10:27:33 -07:00
										 |  |  |   const fullName = name + (superName ? '^' + superName : ''); | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-08 10:14:18 -07:00
										 |  |  |   const props: string[] = descMap.has(fullName) ? descMap.get(fullName)! : []; | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const prototype = type.prototype; | 
					
						
							| 
									
										
										
										
											2016-11-12 14:08:58 +01:00
										 |  |  |   const keys = Object.getOwnPropertyNames(prototype); | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 17:50:03 -07:00
										 |  |  |   keys.sort(); | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  |   keys.forEach((name) => { | 
					
						
							|  |  |  |     if (name.startsWith('on')) { | 
					
						
							|  |  |  |       props.push('*' + name.substr(2)); | 
					
						
							| 
									
										
										
										
											2016-04-28 17:50:03 -07:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  |       const typeCh = _TYPE_MNEMONICS[typeof instance[name]]; | 
					
						
							|  |  |  |       const descriptor = Object.getOwnPropertyDescriptor(prototype, name); | 
					
						
							|  |  |  |       const isSetter = descriptor && descriptor.set; | 
					
						
							|  |  |  |       if (typeCh !== void 0 && !name.startsWith('webkit') && isSetter) { | 
					
						
							|  |  |  |         props.push(typeCh + name); | 
					
						
							| 
									
										
										
										
											2016-04-28 17:50:03 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-06-02 10:27:33 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // There is no point in using `Node.nodeValue`, filter it out
 | 
					
						
							|  |  |  |   descMap.set(fullName, type === Node ? props.filter(p => p != '%nodeValue') : props); | 
					
						
							| 
									
										
										
										
											2016-04-28 17:50:03 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:58 -07:00
										 |  |  | function extractName(type: Function): string|null { | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  |   let name = type['name']; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-06 14:02:25 -08:00
										 |  |  |   // The polyfill @webcomponents/custom-element/src/native-shim.js overrides the
 | 
					
						
							|  |  |  |   // window.HTMLElement and does not have the name property. Check if this is the
 | 
					
						
							|  |  |  |   // case and if so, set the name manually.
 | 
					
						
							|  |  |  |   if (name === '' && type === HTMLElement) { | 
					
						
							|  |  |  |     name = 'HTMLElement'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  |   switch (name) { | 
					
						
							|  |  |  |     // see https://www.w3.org/TR/html5/index.html
 | 
					
						
							|  |  |  |     // TODO(vicb): generate this map from all the element types
 | 
					
						
							|  |  |  |     case 'Element': | 
					
						
							| 
									
										
										
										
											2016-09-01 17:32:47 -07:00
										 |  |  |       return ELEMENT_IF; | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  |     case 'HTMLElement': | 
					
						
							| 
									
										
										
										
											2016-09-01 17:32:47 -07:00
										 |  |  |       return HTMLELEMENT_IF; | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  |     case 'HTMLImageElement': | 
					
						
							|  |  |  |       return 'img'; | 
					
						
							|  |  |  |     case 'HTMLAnchorElement': | 
					
						
							|  |  |  |       return 'a'; | 
					
						
							|  |  |  |     case 'HTMLDListElement': | 
					
						
							|  |  |  |       return 'dl'; | 
					
						
							|  |  |  |     case 'HTMLDirectoryElement': | 
					
						
							|  |  |  |       return 'dir'; | 
					
						
							|  |  |  |     case 'HTMLHeadingElement': | 
					
						
							|  |  |  |       return 'h1,h2,h3,h4,h5,h6'; | 
					
						
							|  |  |  |     case 'HTMLModElement': | 
					
						
							|  |  |  |       return 'ins,del'; | 
					
						
							|  |  |  |     case 'HTMLOListElement': | 
					
						
							|  |  |  |       return 'ol'; | 
					
						
							|  |  |  |     case 'HTMLParagraphElement': | 
					
						
							|  |  |  |       return 'p'; | 
					
						
							|  |  |  |     case 'HTMLQuoteElement': | 
					
						
							|  |  |  |       return 'q,blockquote,cite'; | 
					
						
							|  |  |  |     case 'HTMLTableCaptionElement': | 
					
						
							|  |  |  |       return 'caption'; | 
					
						
							|  |  |  |     case 'HTMLTableCellElement': | 
					
						
							|  |  |  |       return 'th,td'; | 
					
						
							|  |  |  |     case 'HTMLTableColElement': | 
					
						
							|  |  |  |       return 'col,colgroup'; | 
					
						
							|  |  |  |     case 'HTMLTableRowElement': | 
					
						
							|  |  |  |       return 'tr'; | 
					
						
							|  |  |  |     case 'HTMLTableSectionElement': | 
					
						
							|  |  |  |       return 'tfoot,thead,tbody'; | 
					
						
							|  |  |  |     case 'HTMLUListElement': | 
					
						
							|  |  |  |       return 'ul'; | 
					
						
							|  |  |  |     case 'SVGGraphicsElement': | 
					
						
							|  |  |  |       return SVG_PREFIX + 'graphics'; | 
					
						
							|  |  |  |     case 'SVGMPathElement': | 
					
						
							|  |  |  |       return SVG_PREFIX + 'mpath'; | 
					
						
							|  |  |  |     case 'SVGSVGElement': | 
					
						
							|  |  |  |       return SVG_PREFIX + 'svg'; | 
					
						
							|  |  |  |     case 'SVGTSpanElement': | 
					
						
							|  |  |  |       return SVG_PREFIX + 'tspan'; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       const isSVG = name.startsWith('SVG'); | 
					
						
							|  |  |  |       if (name.startsWith('HTML') || isSVG) { | 
					
						
							|  |  |  |         name = name.replace('HTML', '').replace('SVG', '').replace('Element', ''); | 
					
						
							|  |  |  |         if (isSVG && name.startsWith('FE')) { | 
					
						
							|  |  |  |           name = 'fe' + name.substring(2); | 
					
						
							|  |  |  |         } else if (name) { | 
					
						
							|  |  |  |           name = name.charAt(0).toLowerCase() + name.substring(1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return isSVG ? SVG_PREFIX + name : name.toLowerCase(); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-04-28 17:50:03 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return null; | 
					
						
							| 
									
										
										
										
											2016-04-28 17:50:03 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 10:52:40 -07:00
										 |  |  | const _TYPE_MNEMONICS: {[type: string]: string} = { | 
					
						
							|  |  |  |   'string': '', | 
					
						
							|  |  |  |   'number': '#', | 
					
						
							|  |  |  |   'boolean': '!', | 
					
						
							|  |  |  |   'object': '%', | 
					
						
							| 
									
										
										
										
											2017-06-08 12:43:37 +03:00
										 |  |  | }; |