parent
93deff6c33
commit
d309f7799c
|
@ -33,7 +33,8 @@ const OBJECT = 'object';
|
|||
* An `element` may inherit additional properties from `parentElement` If no `^parentElement` is
|
||||
* specified then `""` (blank) element is assumed.
|
||||
*
|
||||
* NOTE: The blank element inherits from root `[Element]` element, the super element of all elements.
|
||||
* NOTE: The blank element inherits from root `[Element]` element, the super element of all
|
||||
* elements.
|
||||
*
|
||||
* NOTE an element prefix such as `:svg:` has no special meaning to the schema.
|
||||
*
|
||||
|
@ -71,7 +72,9 @@ const OBJECT = 'object';
|
|||
//
|
||||
// =================================================================================================
|
||||
|
||||
const SCHEMA: string[] = ([
|
||||
const SCHEMA:
|
||||
string[] =
|
||||
[
|
||||
'[Element]|textContent,%classList,className,id,innerHTML,*beforecopy,*beforecut,*beforepaste,*copy,*cut,*paste,*search,*selectstart,*webkitfullscreenchange,*webkitfullscreenerror,*wheel,outerHTML,#scrollLeft,#scrollTop',
|
||||
'[HTMLElement]^[Element]|accessKey,contentEditable,dir,!draggable,!hidden,innerText,lang,*abort,*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',
|
||||
'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^[HTMLElement]|accessKey,contentEditable,dir,!draggable,!hidden,innerText,lang,*abort,*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',
|
||||
|
@ -218,14 +221,18 @@ const SCHEMA: string[] = ([
|
|||
':svg:title^:svg:|',
|
||||
':svg:use^:svg:graphics|',
|
||||
':svg:view^:svg:|#zoomAndPan',
|
||||
]);
|
||||
'data^[HTMLElement]|value',
|
||||
'menuitem^[HTMLElement]|type,label,icon,!disabled,!checked,radiogroup,!default',
|
||||
'summary^[HTMLElement]|',
|
||||
'time^[HTMLElement]|dateTime',
|
||||
];
|
||||
|
||||
const _ATTR_TO_PROP: {[name: string]: string} = {
|
||||
'class': 'className',
|
||||
'formaction': 'formAction',
|
||||
'innerHtml': 'innerHTML',
|
||||
'readonly': 'readOnly',
|
||||
'tabindex': 'tabIndex'
|
||||
'tabindex': 'tabIndex',
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
|
|
|
@ -31,6 +31,14 @@ export function main() {
|
|||
expect(registry.hasElement('abc', [])).toBeFalsy();
|
||||
});
|
||||
|
||||
// https://github.com/angular/angular/issues/11219
|
||||
it('should detect elements missing from chrome', () => {
|
||||
expect(registry.hasElement('data', [])).toBeTruthy();
|
||||
expect(registry.hasElement('menuitem', [])).toBeTruthy();
|
||||
expect(registry.hasElement('summary', [])).toBeTruthy();
|
||||
expect(registry.hasElement('time', [])).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should detect properties on regular elements', () => {
|
||||
expect(registry.hasProperty('div', 'id', [])).toBeTruthy();
|
||||
expect(registry.hasProperty('div', 'title', [])).toBeTruthy();
|
||||
|
@ -46,6 +54,16 @@ export function main() {
|
|||
expect(registry.hasProperty('div', 'unknown', [])).toBeFalsy();
|
||||
});
|
||||
|
||||
// https://github.com/angular/angular/issues/11219
|
||||
it('should detect properties on elements missing from Chrome', () => {
|
||||
expect(registry.hasProperty('data', 'value', [])).toBeTruthy();
|
||||
|
||||
expect(registry.hasProperty('menuitem', 'type', [])).toBeTruthy();
|
||||
expect(registry.hasProperty('menuitem', 'default', [])).toBeTruthy();
|
||||
|
||||
expect(registry.hasProperty('time', 'dateTime', [])).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should detect different kinds of types', () => {
|
||||
// inheritance: video => media => [HTMLElement] => [Element]
|
||||
expect(registry.hasProperty('video', 'className', [])).toBeTruthy(); // from [Element]
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {MapWrapper} from '../../src/facade/collection';
|
||||
|
||||
const SVG_PREFIX = ':svg:';
|
||||
|
||||
// Element | Node interfaces
|
||||
|
@ -19,6 +21,23 @@ const HTMLELEMENT_IF = '[HTMLElement]';
|
|||
const HTMLELEMENT_TAGS =
|
||||
'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'],
|
||||
// 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'],
|
||||
};
|
||||
|
||||
const _G: any = global;
|
||||
const document: any = typeof _G['document'] == 'object' ? _G['document'] : null;
|
||||
|
||||
|
@ -77,9 +96,29 @@ export function extractSchema(): Map<string, string[]> {
|
|||
|
||||
types.forEach(type => { extractRecursiveProperties(visited, descMap, (window as any)[type]); });
|
||||
|
||||
// Add elements missed by Chrome auto-detection
|
||||
Object.keys(MISSING_FROM_CHROME).forEach(elHierarchy => {
|
||||
descMap.set(elHierarchy, MISSING_FROM_CHROME[elHierarchy]);
|
||||
});
|
||||
|
||||
assertNoMissingTags(descMap);
|
||||
|
||||
return descMap;
|
||||
}
|
||||
|
||||
function assertNoMissingTags(descMap: Map<string, string[]>): void {
|
||||
const extractedTags: string[] = [];
|
||||
|
||||
MapWrapper.keys(descMap).forEach(
|
||||
(key: string) => { extractedTags.push(...key.split('|')[0].split('^')[0].split(',')); });
|
||||
|
||||
const missingTags = ALL_HTML_TAGS.split(',').filter(tag => extractedTags.indexOf(tag) == -1);
|
||||
|
||||
if (missingTags.length) {
|
||||
throw new Error(`DOM schema misses tags: ${missingTags.join(',')}`);
|
||||
}
|
||||
}
|
||||
|
||||
function extractRecursiveProperties(
|
||||
visited: {[name: string]: boolean}, descMap: Map<string, string[]>, type: Function): string {
|
||||
const name = extractName(type);
|
||||
|
|
Loading…
Reference in New Issue