11import { Injectable } from 'angular2/src/core/di' ;
2- import { isPresent , isBlank , CONST_EXPR } from 'angular2/src/facade/lang' ;
2+ import { isPresent , CONST_EXPR } from 'angular2/src/facade/lang' ;
33import { StringMapWrapper } from 'angular2/src/facade/collection' ;
4- import { DOM } from 'angular2/src/platform/dom/dom_adapter' ;
5- import { splitNsName } from 'angular2/src/compiler/html_tags' ;
6-
74import { ElementSchemaRegistry } from './element_schema_registry' ;
85
9- const NAMESPACE_URIS =
10- CONST_EXPR ( { 'xlink' : 'http://www.w3.org/1999/xlink' , 'svg' : 'http://www.w3.org/2000/svg' } ) ;
6+ const EVENT = 'event' ;
7+ const BOOLEAN = 'boolean' ;
8+ const NUMBER = 'number' ;
9+ const STRING = 'string' ;
10+ const OBJECT = 'object' ;
11+
12+ /**
13+ * This array represents the DOM schema. It encodes inheritance, properties, and events.
14+ *
15+ * ## Overview
16+ *
17+ * Each line represents one kind of element. The `element_inheritance` and properties are joined
18+ * using `element_inheritance|preperties` syntax.
19+ *
20+ * ## Element Inheritance
21+ *
22+ * The `element_inheritance` can be further subdivided as `element1,element2,...^parentElement`.
23+ * Here the individual elements are separated by `,` (commas). Every element in the list
24+ * has identical properties.
25+ *
26+ * An `element` may inherit additional properties from `parentElement` If no `^parentElement` is
27+ * specified then `""` (blank) element is assumed.
28+ *
29+ * NOTE: The blank element inherits from root `*` element, the super element of all elements.
30+ *
31+ * NOTE an element prefix such as `@svg:` has no special meaning to the schema.
32+ *
33+ * ## Properties
34+ *
35+ * Each element has a set of properties separated by `,` (commas). Each property can be prefixed
36+ * by a special character designating its type:
37+ *
38+ * - (no prefix): property is a string.
39+ * - `*`: property represents an event.
40+ * - `!`: property is a boolean.
41+ * - `#`: property is a number.
42+ * - `%`: property is an object.
43+ *
44+ * ## Query
45+ *
46+ * The class creates an internal squas representaino which allows to easily answer the query of
47+ * if a given property exist on a given element.
48+ *
49+ * NOTE: We don't yet support querying for types or events.
50+ * NOTE: This schema is auto extracted from `schema_extractor.ts` located in the test folder.
51+ */
52+ const SCHEMA : string [ ] =
53+ CONST_EXPR ( [
54+ '*|%classList,className,id,innerHTML,*beforecopy,*beforecut,*beforepaste,*copy,*cut,*paste,*search,*selectstart,*webkitfullscreenchange,*webkitfullscreenerror,*wheel,outerHTML,#scrollLeft,#scrollTop' ,
55+ '^*|accessKey,contentEditable,dir,!draggable,!hidden,innerText,lang,*abort,*autocomplete,*autocompleteerror,*beforecopy,*beforecut,*beforepaste,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*copy,*cuechange,*cut,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*message,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*mozfullscreenchange,*mozfullscreenerror,*mozpointerlockchange,*mozpointerlockerror,*paste,*pause,*play,*playing,*progress,*ratechange,*reset,*resize,*scroll,*search,*seeked,*seeking,*select,*selectstart,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,*webglcontextcreationerror,*webglcontextlost,*webglcontextrestored,*webkitfullscreenchange,*webkitfullscreenerror,*wheel,outerText,!spellcheck,%style,#tabIndex,title,!translate' ,
56+ 'media|!autoplay,!controls,%crossOrigin,#currentTime,!defaultMuted,#defaultPlaybackRate,!disableRemotePlayback,!loop,!muted,*encrypted,#playbackRate,preload,src,#volume' ,
57+ '@svg:^*|*abort,*autocomplete,*autocompleteerror,*blur,*cancel,*canplay,*canplaythrough,*change,*click,*close,*contextmenu,*cuechange,*dblclick,*drag,*dragend,*dragenter,*dragleave,*dragover,*dragstart,*drop,*durationchange,*emptied,*ended,*error,*focus,*input,*invalid,*keydown,*keypress,*keyup,*load,*loadeddata,*loadedmetadata,*loadstart,*mousedown,*mouseenter,*mouseleave,*mousemove,*mouseout,*mouseover,*mouseup,*mousewheel,*pause,*play,*playing,*progress,*ratechange,*reset,*resize,*scroll,*seeked,*seeking,*select,*show,*stalled,*submit,*suspend,*timeupdate,*toggle,*volumechange,*waiting,%style,#tabIndex' ,
58+ '@svg:graphics^@svg:|' ,
59+ '@svg:animation^@svg:|*begin,*end,*repeat' ,
60+ '@svg:geometry^@svg:|' ,
61+ '@svg:componentTransferFunction^@svg:|' ,
62+ '@svg:gradient^@svg:|' ,
63+ '@svg:textContent^@svg:graphics|' ,
64+ '@svg:textPositioning^@svg:textContent|' ,
65+ 'a|charset,coords,download,hash,host,hostname,href,hreflang,name,password,pathname,ping,port,protocol,rel,rev,search,shape,target,text,type,username' ,
66+ 'area|alt,coords,hash,host,hostname,href,!noHref,password,pathname,ping,port,protocol,search,shape,target,username' ,
67+ 'audio^media|' ,
68+ 'br|clear' ,
69+ 'base|href,target' ,
70+ 'body|aLink,background,bgColor,link,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,text,vLink' ,
71+ 'button|!autofocus,!disabled,formAction,formEnctype,formMethod,!formNoValidate,formTarget,name,type,value' ,
72+ 'canvas|#height,#width' ,
73+ 'content|select' ,
74+ 'dl|!compact' ,
75+ 'datalist|' ,
76+ 'details|!open' ,
77+ 'dialog|!open,returnValue' ,
78+ 'dir|!compact' ,
79+ 'div|align' ,
80+ 'embed|align,height,name,src,type,width' ,
81+ 'fieldset|!disabled,name' ,
82+ 'font|color,face,size' ,
83+ 'form|acceptCharset,action,autocomplete,encoding,enctype,method,name,!noValidate,target' ,
84+ 'frame|frameBorder,longDesc,marginHeight,marginWidth,name,!noResize,scrolling,src' ,
85+ 'frameset|cols,*beforeunload,*blur,*error,*focus,*hashchange,*languagechange,*load,*message,*offline,*online,*pagehide,*pageshow,*popstate,*rejectionhandled,*resize,*scroll,*storage,*unhandledrejection,*unload,rows' ,
86+ 'hr|align,color,!noShade,size,width' ,
87+ 'head|' ,
88+ 'h1,h2,h3,h4,h5,h6|align' ,
89+ 'html|version' ,
90+ 'iframe|align,!allowFullscreen,frameBorder,height,longDesc,marginHeight,marginWidth,name,%sandbox,scrolling,src,srcdoc,width' ,
91+ 'img|align,alt,border,%crossOrigin,#height,#hspace,!isMap,longDesc,lowsrc,name,sizes,src,srcset,useMap,#vspace,#width' ,
92+ 'input|accept,align,alt,autocapitalize,autocomplete,!autofocus,!checked,!defaultChecked,defaultValue,dirName,!disabled,%files,formAction,formEnctype,formMethod,!formNoValidate,formTarget,#height,!incremental,!indeterminate,max,#maxLength,min,#minLength,!multiple,name,pattern,placeholder,!readOnly,!required,selectionDirection,#selectionEnd,#selectionStart,#size,src,step,type,useMap,value,%valueAsDate,#valueAsNumber,#width' ,
93+ 'keygen|!autofocus,challenge,!disabled,keytype,name' ,
94+ 'li|type,#value' ,
95+ 'label|htmlFor' ,
96+ 'legend|align' ,
97+ 'link|as,charset,%crossOrigin,!disabled,href,hreflang,integrity,media,rel,%relList,rev,%sizes,target,type' ,
98+ 'map|name' ,
99+ 'marquee|behavior,bgColor,direction,height,#hspace,#loop,#scrollAmount,#scrollDelay,!trueSpeed,#vspace,width' ,
100+ 'menu|!compact' ,
101+ 'meta|content,httpEquiv,name,scheme' ,
102+ 'meter|#high,#low,#max,#min,#optimum,#value' ,
103+ 'ins,del|cite,dateTime' ,
104+ 'ol|!compact,!reversed,#start,type' ,
105+ 'object|align,archive,border,code,codeBase,codeType,data,!declare,height,#hspace,name,standby,type,useMap,#vspace,width' ,
106+ 'optgroup|!disabled,label' ,
107+ 'option|!defaultSelected,!disabled,label,!selected,text,value' ,
108+ 'output|defaultValue,%htmlFor,name,value' ,
109+ 'p|align' ,
110+ 'param|name,type,value,valueType' ,
111+ 'picture|' ,
112+ 'pre|#width' ,
113+ 'progress|#max,#value' ,
114+ 'q,blockquote,cite|' ,
115+ 'script|!async,charset,%crossOrigin,!defer,event,htmlFor,integrity,src,text,type' ,
116+ 'select|!autofocus,!disabled,#length,!multiple,name,!required,#selectedIndex,#size,value' ,
117+ 'shadow|' ,
118+ 'source|media,sizes,src,srcset,type' ,
119+ 'span|' ,
120+ 'style|!disabled,media,type' ,
121+ 'caption|align' ,
122+ 'th,td|abbr,align,axis,bgColor,ch,chOff,#colSpan,headers,height,!noWrap,#rowSpan,scope,vAlign,width' ,
123+ 'col,colgroup|align,ch,chOff,#span,vAlign,width' ,
124+ 'table|align,bgColor,border,%caption,cellPadding,cellSpacing,frame,rules,summary,%tFoot,%tHead,width' ,
125+ 'tr|align,bgColor,ch,chOff,vAlign' ,
126+ 'tfoot,thead,tbody|align,ch,chOff,vAlign' ,
127+ 'template|' ,
128+ 'textarea|autocapitalize,!autofocus,#cols,defaultValue,dirName,!disabled,#maxLength,#minLength,name,placeholder,!readOnly,!required,#rows,selectionDirection,#selectionEnd,#selectionStart,value,wrap' ,
129+ 'title|text' ,
130+ 'track|!default,kind,label,src,srclang' ,
131+ 'ul|!compact,type' ,
132+ 'unknown|' ,
133+ 'video^media|#height,poster,#width' ,
134+ '@svg:a^@svg:graphics|' ,
135+ '@svg:animate^@svg:animation|' ,
136+ '@svg:animateMotion^@svg:animation|' ,
137+ '@svg:animateTransform^@svg:animation|' ,
138+ '@svg:circle^@svg:geometry|' ,
139+ '@svg:clipPath^@svg:graphics|' ,
140+ '@svg:cursor^@svg:|' ,
141+ '@svg:defs^@svg:graphics|' ,
142+ '@svg:desc^@svg:|' ,
143+ '@svg:discard^@svg:|' ,
144+ '@svg:ellipse^@svg:geometry|' ,
145+ '@svg:feBlend^@svg:|' ,
146+ '@svg:feColorMatrix^@svg:|' ,
147+ '@svg:feComponentTransfer^@svg:|' ,
148+ '@svg:feComposite^@svg:|' ,
149+ '@svg:feConvolveMatrix^@svg:|' ,
150+ '@svg:feDiffuseLighting^@svg:|' ,
151+ '@svg:feDisplacementMap^@svg:|' ,
152+ '@svg:feDistantLight^@svg:|' ,
153+ '@svg:feDropShadow^@svg:|' ,
154+ '@svg:feFlood^@svg:|' ,
155+ '@svg:feFuncA^@svg:componentTransferFunction|' ,
156+ '@svg:feFuncB^@svg:componentTransferFunction|' ,
157+ '@svg:feFuncG^@svg:componentTransferFunction|' ,
158+ '@svg:feFuncR^@svg:componentTransferFunction|' ,
159+ '@svg:feGaussianBlur^@svg:|' ,
160+ '@svg:feImage^@svg:|' ,
161+ '@svg:feMerge^@svg:|' ,
162+ '@svg:feMergeNode^@svg:|' ,
163+ '@svg:feMorphology^@svg:|' ,
164+ '@svg:feOffset^@svg:|' ,
165+ '@svg:fePointLight^@svg:|' ,
166+ '@svg:feSpecularLighting^@svg:|' ,
167+ '@svg:feSpotLight^@svg:|' ,
168+ '@svg:feTile^@svg:|' ,
169+ '@svg:feTurbulence^@svg:|' ,
170+ '@svg:filter^@svg:|' ,
171+ '@svg:foreignObject^@svg:graphics|' ,
172+ '@svg:g^@svg:graphics|' ,
173+ '@svg:image^@svg:graphics|' ,
174+ '@svg:line^@svg:geometry|' ,
175+ '@svg:linearGradient^@svg:gradient|' ,
176+ '@svg:mpath^@svg:|' ,
177+ '@svg:marker^@svg:|' ,
178+ '@svg:mask^@svg:|' ,
179+ '@svg:metadata^@svg:|' ,
180+ '@svg:path^@svg:geometry|' ,
181+ '@svg:pattern^@svg:|' ,
182+ '@svg:polygon^@svg:geometry|' ,
183+ '@svg:polyline^@svg:geometry|' ,
184+ '@svg:radialGradient^@svg:gradient|' ,
185+ '@svg:rect^@svg:geometry|' ,
186+ '@svg:svg^@svg:graphics|#currentScale,#zoomAndPan' ,
187+ '@svg:script^@svg:|type' ,
188+ '@svg:set^@svg:animation|' ,
189+ '@svg:stop^@svg:|' ,
190+ '@svg:style^@svg:|!disabled,media,title,type' ,
191+ '@svg:switch^@svg:graphics|' ,
192+ '@svg:symbol^@svg:|' ,
193+ '@svg:tspan^@svg:textPositioning|' ,
194+ '@svg:text^@svg:textPositioning|' ,
195+ '@svg:textPath^@svg:textContent|' ,
196+ '@svg:title^@svg:|' ,
197+ '@svg:use^@svg:graphics|' ,
198+ '@svg:view^@svg:|#zoomAndPan'
199+ ] ) ;
200+
201+ var attrToPropMap : { [ name : string ] : string } = < any > {
202+ 'class' : 'className' ,
203+ 'innerHtml' : 'innerHTML' ,
204+ 'readonly' : 'readOnly' ,
205+ 'tabindex' : 'tabIndex'
206+ } ;
207+
11208
12209@Injectable ( )
13- export class DomElementSchemaRegistry extends ElementSchemaRegistry {
14- private _protoElements = new Map < string , Element > ( ) ;
15-
16- private _getProtoElement ( tagName : string ) : Element {
17- var element = this . _protoElements . get ( tagName ) ;
18- if ( isBlank ( element ) ) {
19- var nsAndName = splitNsName ( tagName ) ;
20- element = isPresent ( nsAndName [ 0 ] ) ?
21- DOM . createElementNS ( NAMESPACE_URIS [ nsAndName [ 0 ] ] , nsAndName [ 1 ] ) :
22- DOM . createElement ( nsAndName [ 1 ] ) ;
23- this . _protoElements . set ( tagName , element ) ;
24- }
25- return element ;
210+ export class DomElementSchemaRegistry implements ElementSchemaRegistry {
211+ schema = < { [ element : string ] : { [ property : string ] : string } } > { } ;
212+
213+ constructor ( ) {
214+ SCHEMA . forEach ( encodedType => {
215+ var parts = encodedType . split ( '|' ) ;
216+ var properties = parts [ 1 ] . split ( ',' ) ;
217+ var typeParts = ( parts [ 0 ] + '^' ) . split ( '^' ) ;
218+ var typeName = typeParts [ 0 ] ;
219+ var type = < { [ property : string ] : string } > { } ;
220+ typeName . split ( ',' ) . forEach ( tag => this . schema [ tag ] = type ) ;
221+ var superType = this . schema [ typeParts [ 1 ] ] ;
222+ if ( isPresent ( superType ) ) {
223+ StringMapWrapper . forEach ( superType , ( v , k ) => type [ k ] = v ) ;
224+ }
225+ properties . forEach ( ( property : string ) => {
226+ if ( property == '' ) {
227+ } else if ( property . startsWith ( '*' ) ) {
228+ // We don't yet support events.
229+ // type[property.substring(1)] = EVENT;
230+ } else if ( property . startsWith ( '!' ) ) {
231+ type [ property . substring ( 1 ) ] = BOOLEAN ;
232+ } else if ( property . startsWith ( '#' ) ) {
233+ type [ property . substring ( 1 ) ] = NUMBER ;
234+ } else if ( property . startsWith ( '%' ) ) {
235+ type [ property . substring ( 1 ) ] = OBJECT ;
236+ } else {
237+ type [ property ] = STRING ;
238+ }
239+ } ) ;
240+ } ) ;
26241 }
27242
28243 hasProperty ( tagName : string , propName : string ) : boolean {
@@ -31,13 +246,16 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry {
31246 // once it is instantiated
32247 return true ;
33248 } else {
34- var elm = this . _getProtoElement ( tagName ) ;
35- return DOM . hasProperty ( elm , propName ) ;
249+ var elementProperties = this . schema [ tagName . toLowerCase ( ) ] ;
250+ if ( ! isPresent ( elementProperties ) ) {
251+ elementProperties = this . schema [ 'unknown' ] ;
252+ }
253+ return isPresent ( elementProperties [ propName ] ) ;
36254 }
37255 }
38256
39257 getMappedPropName ( propName : string ) : string {
40- var mappedPropName = StringMapWrapper . get ( DOM . attrToPropMap , propName ) ;
258+ var mappedPropName = StringMapWrapper . get ( attrToPropMap , propName ) ;
41259 return isPresent ( mappedPropName ) ? mappedPropName : propName ;
42260 }
43261}
0 commit comments