Revert "refactor(upgrade): don’t rely on compiler internals"
This reverts commit 8e2c8b3e4d
.
This commit is contained in:
parent
cd981499f9
commit
322bf7a0d5
|
@ -0,0 +1,7 @@
|
||||||
|
The following code has been copied from the Angular compiler to be used in the upgrade library without
|
||||||
|
the need to import the entire compiler:
|
||||||
|
|
||||||
|
* `selector.ts`
|
||||||
|
* `ml_parser/html_tags.ts`
|
||||||
|
* `ml_parser/tags.ts`
|
||||||
|
* `createElementCssSelector.ts`
|
|
@ -0,0 +1,55 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {CssSelector} from './selector';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following items are copied from the Angular Compiler to be used here
|
||||||
|
* without the need to import the entire compiler into the build
|
||||||
|
*/
|
||||||
|
|
||||||
|
const CLASS_ATTR = 'class';
|
||||||
|
|
||||||
|
export function createElementCssSelector(
|
||||||
|
elementName: string, attributes: [string, string][]): CssSelector {
|
||||||
|
const cssSelector = new CssSelector();
|
||||||
|
const elNameNoNs = splitNsName(elementName)[1];
|
||||||
|
|
||||||
|
cssSelector.setElement(elNameNoNs);
|
||||||
|
|
||||||
|
for (let i = 0; i < attributes.length; i++) {
|
||||||
|
const attrName = attributes[i][0];
|
||||||
|
const attrNameNoNs = splitNsName(attrName)[1];
|
||||||
|
const attrValue = attributes[i][1];
|
||||||
|
|
||||||
|
cssSelector.addAttribute(attrNameNoNs, attrValue);
|
||||||
|
if (attrName.toLowerCase() == CLASS_ATTR) {
|
||||||
|
const classes = splitClasses(attrValue);
|
||||||
|
classes.forEach(className => cssSelector.addClassName(className));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cssSelector;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function splitNsName(elementName: string): [string, string] {
|
||||||
|
if (elementName[0] != ':') {
|
||||||
|
return [null, elementName];
|
||||||
|
}
|
||||||
|
|
||||||
|
const colonIndex = elementName.indexOf(':', 1);
|
||||||
|
|
||||||
|
if (colonIndex == -1) {
|
||||||
|
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function splitClasses(classAttrValue: string): string[] {
|
||||||
|
return classAttrValue.trim().split(/\s+/g);
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {TagContentType, TagDefinition} from './tags';
|
||||||
|
|
||||||
|
export class HtmlTagDefinition implements TagDefinition {
|
||||||
|
private closedByChildren: {[key: string]: boolean} = {};
|
||||||
|
|
||||||
|
closedByParent: boolean = false;
|
||||||
|
requiredParents: {[key: string]: boolean};
|
||||||
|
parentToAdd: string;
|
||||||
|
implicitNamespacePrefix: string;
|
||||||
|
contentType: TagContentType;
|
||||||
|
isVoid: boolean;
|
||||||
|
ignoreFirstLf: boolean;
|
||||||
|
canSelfClose: boolean = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
{closedByChildren, requiredParents, implicitNamespacePrefix,
|
||||||
|
contentType = TagContentType.PARSABLE_DATA, closedByParent = false, isVoid = false,
|
||||||
|
ignoreFirstLf = false}: {
|
||||||
|
closedByChildren?: string[],
|
||||||
|
closedByParent?: boolean,
|
||||||
|
requiredParents?: string[],
|
||||||
|
implicitNamespacePrefix?: string,
|
||||||
|
contentType?: TagContentType,
|
||||||
|
isVoid?: boolean,
|
||||||
|
ignoreFirstLf?: boolean
|
||||||
|
} = {}) {
|
||||||
|
if (closedByChildren && closedByChildren.length > 0) {
|
||||||
|
closedByChildren.forEach(tagName => this.closedByChildren[tagName] = true);
|
||||||
|
}
|
||||||
|
this.isVoid = isVoid;
|
||||||
|
this.closedByParent = closedByParent || isVoid;
|
||||||
|
if (requiredParents && requiredParents.length > 0) {
|
||||||
|
this.requiredParents = {};
|
||||||
|
// The first parent is the list is automatically when none of the listed parents are present
|
||||||
|
this.parentToAdd = requiredParents[0];
|
||||||
|
requiredParents.forEach(tagName => this.requiredParents[tagName] = true);
|
||||||
|
}
|
||||||
|
this.implicitNamespacePrefix = implicitNamespacePrefix;
|
||||||
|
this.contentType = contentType;
|
||||||
|
this.ignoreFirstLf = ignoreFirstLf;
|
||||||
|
}
|
||||||
|
|
||||||
|
requireExtraParent(currentParent: string): boolean {
|
||||||
|
if (!this.requiredParents) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentParent) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lcParent = currentParent.toLowerCase();
|
||||||
|
const isParentTemplate = lcParent === 'template' || currentParent === 'ng-template';
|
||||||
|
return !isParentTemplate && this.requiredParents[lcParent] != true;
|
||||||
|
}
|
||||||
|
|
||||||
|
isClosedByChild(name: string): boolean {
|
||||||
|
return this.isVoid || name.toLowerCase() in this.closedByChildren;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// see http://www.w3.org/TR/html51/syntax.html#optional-tags
|
||||||
|
// This implementation does not fully conform to the HTML5 spec.
|
||||||
|
const TAG_DEFINITIONS: {[key: string]: HtmlTagDefinition} = {
|
||||||
|
'base': new HtmlTagDefinition({isVoid: true}),
|
||||||
|
'meta': new HtmlTagDefinition({isVoid: true}),
|
||||||
|
'area': new HtmlTagDefinition({isVoid: true}),
|
||||||
|
'embed': new HtmlTagDefinition({isVoid: true}),
|
||||||
|
'link': new HtmlTagDefinition({isVoid: true}),
|
||||||
|
'img': new HtmlTagDefinition({isVoid: true}),
|
||||||
|
'input': new HtmlTagDefinition({isVoid: true}),
|
||||||
|
'param': new HtmlTagDefinition({isVoid: true}),
|
||||||
|
'hr': new HtmlTagDefinition({isVoid: true}),
|
||||||
|
'br': new HtmlTagDefinition({isVoid: true}),
|
||||||
|
'source': new HtmlTagDefinition({isVoid: true}),
|
||||||
|
'track': new HtmlTagDefinition({isVoid: true}),
|
||||||
|
'wbr': new HtmlTagDefinition({isVoid: true}),
|
||||||
|
'p': new HtmlTagDefinition({
|
||||||
|
closedByChildren: [
|
||||||
|
'address', 'article', 'aside', 'blockquote', 'div', 'dl', 'fieldset', 'footer', 'form',
|
||||||
|
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr',
|
||||||
|
'main', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'
|
||||||
|
],
|
||||||
|
closedByParent: true
|
||||||
|
}),
|
||||||
|
'thead': new HtmlTagDefinition({closedByChildren: ['tbody', 'tfoot']}),
|
||||||
|
'tbody': new HtmlTagDefinition({closedByChildren: ['tbody', 'tfoot'], closedByParent: true}),
|
||||||
|
'tfoot': new HtmlTagDefinition({closedByChildren: ['tbody'], closedByParent: true}),
|
||||||
|
'tr': new HtmlTagDefinition({
|
||||||
|
closedByChildren: ['tr'],
|
||||||
|
requiredParents: ['tbody', 'tfoot', 'thead'],
|
||||||
|
closedByParent: true
|
||||||
|
}),
|
||||||
|
'td': new HtmlTagDefinition({closedByChildren: ['td', 'th'], closedByParent: true}),
|
||||||
|
'th': new HtmlTagDefinition({closedByChildren: ['td', 'th'], closedByParent: true}),
|
||||||
|
'col': new HtmlTagDefinition({requiredParents: ['colgroup'], isVoid: true}),
|
||||||
|
'svg': new HtmlTagDefinition({implicitNamespacePrefix: 'svg'}),
|
||||||
|
'math': new HtmlTagDefinition({implicitNamespacePrefix: 'math'}),
|
||||||
|
'li': new HtmlTagDefinition({closedByChildren: ['li'], closedByParent: true}),
|
||||||
|
'dt': new HtmlTagDefinition({closedByChildren: ['dt', 'dd']}),
|
||||||
|
'dd': new HtmlTagDefinition({closedByChildren: ['dt', 'dd'], closedByParent: true}),
|
||||||
|
'rb': new HtmlTagDefinition({closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true}),
|
||||||
|
'rt': new HtmlTagDefinition({closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true}),
|
||||||
|
'rtc': new HtmlTagDefinition({closedByChildren: ['rb', 'rtc', 'rp'], closedByParent: true}),
|
||||||
|
'rp': new HtmlTagDefinition({closedByChildren: ['rb', 'rt', 'rtc', 'rp'], closedByParent: true}),
|
||||||
|
'optgroup': new HtmlTagDefinition({closedByChildren: ['optgroup'], closedByParent: true}),
|
||||||
|
'option': new HtmlTagDefinition({closedByChildren: ['option', 'optgroup'], closedByParent: true}),
|
||||||
|
'pre': new HtmlTagDefinition({ignoreFirstLf: true}),
|
||||||
|
'listing': new HtmlTagDefinition({ignoreFirstLf: true}),
|
||||||
|
'style': new HtmlTagDefinition({contentType: TagContentType.RAW_TEXT}),
|
||||||
|
'script': new HtmlTagDefinition({contentType: TagContentType.RAW_TEXT}),
|
||||||
|
'title': new HtmlTagDefinition({contentType: TagContentType.ESCAPABLE_RAW_TEXT}),
|
||||||
|
'textarea':
|
||||||
|
new HtmlTagDefinition({contentType: TagContentType.ESCAPABLE_RAW_TEXT, ignoreFirstLf: true}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const _DEFAULT_TAG_DEFINITION = new HtmlTagDefinition();
|
||||||
|
|
||||||
|
export function getHtmlTagDefinition(tagName: string): HtmlTagDefinition {
|
||||||
|
return TAG_DEFINITIONS[tagName.toLowerCase()] || _DEFAULT_TAG_DEFINITION;
|
||||||
|
}
|
|
@ -0,0 +1,310 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
export enum TagContentType {
|
||||||
|
RAW_TEXT,
|
||||||
|
ESCAPABLE_RAW_TEXT,
|
||||||
|
PARSABLE_DATA
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(vicb): read-only when TS supports it
|
||||||
|
export interface TagDefinition {
|
||||||
|
closedByParent: boolean;
|
||||||
|
requiredParents: {[key: string]: boolean};
|
||||||
|
parentToAdd: string;
|
||||||
|
implicitNamespacePrefix: string;
|
||||||
|
contentType: TagContentType;
|
||||||
|
isVoid: boolean;
|
||||||
|
ignoreFirstLf: boolean;
|
||||||
|
canSelfClose: boolean;
|
||||||
|
|
||||||
|
requireExtraParent(currentParent: string): boolean;
|
||||||
|
|
||||||
|
isClosedByChild(name: string): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function splitNsName(elementName: string): [string, string] {
|
||||||
|
if (elementName[0] != ':') {
|
||||||
|
return [null, elementName];
|
||||||
|
}
|
||||||
|
|
||||||
|
const colonIndex = elementName.indexOf(':', 1);
|
||||||
|
|
||||||
|
if (colonIndex == -1) {
|
||||||
|
throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNsPrefix(fullName: string): string {
|
||||||
|
return fullName === null ? null : splitNsName(fullName)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mergeNsAndName(prefix: string, localName: string): string {
|
||||||
|
return prefix ? `:${prefix}:${localName}` : localName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// see http://www.w3.org/TR/html51/syntax.html#named-character-references
|
||||||
|
// see https://html.spec.whatwg.org/multipage/entities.json
|
||||||
|
// This list is not exhaustive to keep the compiler footprint low.
|
||||||
|
// The `{` / `ƫ` syntax should be used when the named character reference does not exist.
|
||||||
|
export const NAMED_ENTITIES: {[k: string]: string} = {
|
||||||
|
'Aacute': '\u00C1',
|
||||||
|
'aacute': '\u00E1',
|
||||||
|
'Acirc': '\u00C2',
|
||||||
|
'acirc': '\u00E2',
|
||||||
|
'acute': '\u00B4',
|
||||||
|
'AElig': '\u00C6',
|
||||||
|
'aelig': '\u00E6',
|
||||||
|
'Agrave': '\u00C0',
|
||||||
|
'agrave': '\u00E0',
|
||||||
|
'alefsym': '\u2135',
|
||||||
|
'Alpha': '\u0391',
|
||||||
|
'alpha': '\u03B1',
|
||||||
|
'amp': '&',
|
||||||
|
'and': '\u2227',
|
||||||
|
'ang': '\u2220',
|
||||||
|
'apos': '\u0027',
|
||||||
|
'Aring': '\u00C5',
|
||||||
|
'aring': '\u00E5',
|
||||||
|
'asymp': '\u2248',
|
||||||
|
'Atilde': '\u00C3',
|
||||||
|
'atilde': '\u00E3',
|
||||||
|
'Auml': '\u00C4',
|
||||||
|
'auml': '\u00E4',
|
||||||
|
'bdquo': '\u201E',
|
||||||
|
'Beta': '\u0392',
|
||||||
|
'beta': '\u03B2',
|
||||||
|
'brvbar': '\u00A6',
|
||||||
|
'bull': '\u2022',
|
||||||
|
'cap': '\u2229',
|
||||||
|
'Ccedil': '\u00C7',
|
||||||
|
'ccedil': '\u00E7',
|
||||||
|
'cedil': '\u00B8',
|
||||||
|
'cent': '\u00A2',
|
||||||
|
'Chi': '\u03A7',
|
||||||
|
'chi': '\u03C7',
|
||||||
|
'circ': '\u02C6',
|
||||||
|
'clubs': '\u2663',
|
||||||
|
'cong': '\u2245',
|
||||||
|
'copy': '\u00A9',
|
||||||
|
'crarr': '\u21B5',
|
||||||
|
'cup': '\u222A',
|
||||||
|
'curren': '\u00A4',
|
||||||
|
'dagger': '\u2020',
|
||||||
|
'Dagger': '\u2021',
|
||||||
|
'darr': '\u2193',
|
||||||
|
'dArr': '\u21D3',
|
||||||
|
'deg': '\u00B0',
|
||||||
|
'Delta': '\u0394',
|
||||||
|
'delta': '\u03B4',
|
||||||
|
'diams': '\u2666',
|
||||||
|
'divide': '\u00F7',
|
||||||
|
'Eacute': '\u00C9',
|
||||||
|
'eacute': '\u00E9',
|
||||||
|
'Ecirc': '\u00CA',
|
||||||
|
'ecirc': '\u00EA',
|
||||||
|
'Egrave': '\u00C8',
|
||||||
|
'egrave': '\u00E8',
|
||||||
|
'empty': '\u2205',
|
||||||
|
'emsp': '\u2003',
|
||||||
|
'ensp': '\u2002',
|
||||||
|
'Epsilon': '\u0395',
|
||||||
|
'epsilon': '\u03B5',
|
||||||
|
'equiv': '\u2261',
|
||||||
|
'Eta': '\u0397',
|
||||||
|
'eta': '\u03B7',
|
||||||
|
'ETH': '\u00D0',
|
||||||
|
'eth': '\u00F0',
|
||||||
|
'Euml': '\u00CB',
|
||||||
|
'euml': '\u00EB',
|
||||||
|
'euro': '\u20AC',
|
||||||
|
'exist': '\u2203',
|
||||||
|
'fnof': '\u0192',
|
||||||
|
'forall': '\u2200',
|
||||||
|
'frac12': '\u00BD',
|
||||||
|
'frac14': '\u00BC',
|
||||||
|
'frac34': '\u00BE',
|
||||||
|
'frasl': '\u2044',
|
||||||
|
'Gamma': '\u0393',
|
||||||
|
'gamma': '\u03B3',
|
||||||
|
'ge': '\u2265',
|
||||||
|
'gt': '>',
|
||||||
|
'harr': '\u2194',
|
||||||
|
'hArr': '\u21D4',
|
||||||
|
'hearts': '\u2665',
|
||||||
|
'hellip': '\u2026',
|
||||||
|
'Iacute': '\u00CD',
|
||||||
|
'iacute': '\u00ED',
|
||||||
|
'Icirc': '\u00CE',
|
||||||
|
'icirc': '\u00EE',
|
||||||
|
'iexcl': '\u00A1',
|
||||||
|
'Igrave': '\u00CC',
|
||||||
|
'igrave': '\u00EC',
|
||||||
|
'image': '\u2111',
|
||||||
|
'infin': '\u221E',
|
||||||
|
'int': '\u222B',
|
||||||
|
'Iota': '\u0399',
|
||||||
|
'iota': '\u03B9',
|
||||||
|
'iquest': '\u00BF',
|
||||||
|
'isin': '\u2208',
|
||||||
|
'Iuml': '\u00CF',
|
||||||
|
'iuml': '\u00EF',
|
||||||
|
'Kappa': '\u039A',
|
||||||
|
'kappa': '\u03BA',
|
||||||
|
'Lambda': '\u039B',
|
||||||
|
'lambda': '\u03BB',
|
||||||
|
'lang': '\u27E8',
|
||||||
|
'laquo': '\u00AB',
|
||||||
|
'larr': '\u2190',
|
||||||
|
'lArr': '\u21D0',
|
||||||
|
'lceil': '\u2308',
|
||||||
|
'ldquo': '\u201C',
|
||||||
|
'le': '\u2264',
|
||||||
|
'lfloor': '\u230A',
|
||||||
|
'lowast': '\u2217',
|
||||||
|
'loz': '\u25CA',
|
||||||
|
'lrm': '\u200E',
|
||||||
|
'lsaquo': '\u2039',
|
||||||
|
'lsquo': '\u2018',
|
||||||
|
'lt': '<',
|
||||||
|
'macr': '\u00AF',
|
||||||
|
'mdash': '\u2014',
|
||||||
|
'micro': '\u00B5',
|
||||||
|
'middot': '\u00B7',
|
||||||
|
'minus': '\u2212',
|
||||||
|
'Mu': '\u039C',
|
||||||
|
'mu': '\u03BC',
|
||||||
|
'nabla': '\u2207',
|
||||||
|
'nbsp': '\u00A0',
|
||||||
|
'ndash': '\u2013',
|
||||||
|
'ne': '\u2260',
|
||||||
|
'ni': '\u220B',
|
||||||
|
'not': '\u00AC',
|
||||||
|
'notin': '\u2209',
|
||||||
|
'nsub': '\u2284',
|
||||||
|
'Ntilde': '\u00D1',
|
||||||
|
'ntilde': '\u00F1',
|
||||||
|
'Nu': '\u039D',
|
||||||
|
'nu': '\u03BD',
|
||||||
|
'Oacute': '\u00D3',
|
||||||
|
'oacute': '\u00F3',
|
||||||
|
'Ocirc': '\u00D4',
|
||||||
|
'ocirc': '\u00F4',
|
||||||
|
'OElig': '\u0152',
|
||||||
|
'oelig': '\u0153',
|
||||||
|
'Ograve': '\u00D2',
|
||||||
|
'ograve': '\u00F2',
|
||||||
|
'oline': '\u203E',
|
||||||
|
'Omega': '\u03A9',
|
||||||
|
'omega': '\u03C9',
|
||||||
|
'Omicron': '\u039F',
|
||||||
|
'omicron': '\u03BF',
|
||||||
|
'oplus': '\u2295',
|
||||||
|
'or': '\u2228',
|
||||||
|
'ordf': '\u00AA',
|
||||||
|
'ordm': '\u00BA',
|
||||||
|
'Oslash': '\u00D8',
|
||||||
|
'oslash': '\u00F8',
|
||||||
|
'Otilde': '\u00D5',
|
||||||
|
'otilde': '\u00F5',
|
||||||
|
'otimes': '\u2297',
|
||||||
|
'Ouml': '\u00D6',
|
||||||
|
'ouml': '\u00F6',
|
||||||
|
'para': '\u00B6',
|
||||||
|
'permil': '\u2030',
|
||||||
|
'perp': '\u22A5',
|
||||||
|
'Phi': '\u03A6',
|
||||||
|
'phi': '\u03C6',
|
||||||
|
'Pi': '\u03A0',
|
||||||
|
'pi': '\u03C0',
|
||||||
|
'piv': '\u03D6',
|
||||||
|
'plusmn': '\u00B1',
|
||||||
|
'pound': '\u00A3',
|
||||||
|
'prime': '\u2032',
|
||||||
|
'Prime': '\u2033',
|
||||||
|
'prod': '\u220F',
|
||||||
|
'prop': '\u221D',
|
||||||
|
'Psi': '\u03A8',
|
||||||
|
'psi': '\u03C8',
|
||||||
|
'quot': '\u0022',
|
||||||
|
'radic': '\u221A',
|
||||||
|
'rang': '\u27E9',
|
||||||
|
'raquo': '\u00BB',
|
||||||
|
'rarr': '\u2192',
|
||||||
|
'rArr': '\u21D2',
|
||||||
|
'rceil': '\u2309',
|
||||||
|
'rdquo': '\u201D',
|
||||||
|
'real': '\u211C',
|
||||||
|
'reg': '\u00AE',
|
||||||
|
'rfloor': '\u230B',
|
||||||
|
'Rho': '\u03A1',
|
||||||
|
'rho': '\u03C1',
|
||||||
|
'rlm': '\u200F',
|
||||||
|
'rsaquo': '\u203A',
|
||||||
|
'rsquo': '\u2019',
|
||||||
|
'sbquo': '\u201A',
|
||||||
|
'Scaron': '\u0160',
|
||||||
|
'scaron': '\u0161',
|
||||||
|
'sdot': '\u22C5',
|
||||||
|
'sect': '\u00A7',
|
||||||
|
'shy': '\u00AD',
|
||||||
|
'Sigma': '\u03A3',
|
||||||
|
'sigma': '\u03C3',
|
||||||
|
'sigmaf': '\u03C2',
|
||||||
|
'sim': '\u223C',
|
||||||
|
'spades': '\u2660',
|
||||||
|
'sub': '\u2282',
|
||||||
|
'sube': '\u2286',
|
||||||
|
'sum': '\u2211',
|
||||||
|
'sup': '\u2283',
|
||||||
|
'sup1': '\u00B9',
|
||||||
|
'sup2': '\u00B2',
|
||||||
|
'sup3': '\u00B3',
|
||||||
|
'supe': '\u2287',
|
||||||
|
'szlig': '\u00DF',
|
||||||
|
'Tau': '\u03A4',
|
||||||
|
'tau': '\u03C4',
|
||||||
|
'there4': '\u2234',
|
||||||
|
'Theta': '\u0398',
|
||||||
|
'theta': '\u03B8',
|
||||||
|
'thetasym': '\u03D1',
|
||||||
|
'thinsp': '\u2009',
|
||||||
|
'THORN': '\u00DE',
|
||||||
|
'thorn': '\u00FE',
|
||||||
|
'tilde': '\u02DC',
|
||||||
|
'times': '\u00D7',
|
||||||
|
'trade': '\u2122',
|
||||||
|
'Uacute': '\u00DA',
|
||||||
|
'uacute': '\u00FA',
|
||||||
|
'uarr': '\u2191',
|
||||||
|
'uArr': '\u21D1',
|
||||||
|
'Ucirc': '\u00DB',
|
||||||
|
'ucirc': '\u00FB',
|
||||||
|
'Ugrave': '\u00D9',
|
||||||
|
'ugrave': '\u00F9',
|
||||||
|
'uml': '\u00A8',
|
||||||
|
'upsih': '\u03D2',
|
||||||
|
'Upsilon': '\u03A5',
|
||||||
|
'upsilon': '\u03C5',
|
||||||
|
'Uuml': '\u00DC',
|
||||||
|
'uuml': '\u00FC',
|
||||||
|
'weierp': '\u2118',
|
||||||
|
'Xi': '\u039E',
|
||||||
|
'xi': '\u03BE',
|
||||||
|
'Yacute': '\u00DD',
|
||||||
|
'yacute': '\u00FD',
|
||||||
|
'yen': '\u00A5',
|
||||||
|
'yuml': '\u00FF',
|
||||||
|
'Yuml': '\u0178',
|
||||||
|
'Zeta': '\u0396',
|
||||||
|
'zeta': '\u03B6',
|
||||||
|
'zwj': '\u200D',
|
||||||
|
'zwnj': '\u200C',
|
||||||
|
};
|
|
@ -0,0 +1,368 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {getHtmlTagDefinition} from './ml_parser/html_tags';
|
||||||
|
|
||||||
|
const _SELECTOR_REGEXP = new RegExp(
|
||||||
|
'(\\:not\\()|' + //":not("
|
||||||
|
'([-\\w]+)|' + // "tag"
|
||||||
|
'(?:\\.([-\\w]+))|' + // ".class"
|
||||||
|
// "-" should appear first in the regexp below as FF31 parses "[.-\w]" as a range
|
||||||
|
'(?:\\[([-.\\w*]+)(?:=([^\\]]*))?\\])|' + // "[name]", "[name=value]"
|
||||||
|
'(\\))|' + // ")"
|
||||||
|
'(\\s*,\\s*)', // ","
|
||||||
|
'g');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A css selector contains an element name,
|
||||||
|
* css classes and attribute/value pairs with the purpose
|
||||||
|
* of selecting subsets out of them.
|
||||||
|
*/
|
||||||
|
export class CssSelector {
|
||||||
|
element: string = null;
|
||||||
|
classNames: string[] = [];
|
||||||
|
attrs: string[] = [];
|
||||||
|
notSelectors: CssSelector[] = [];
|
||||||
|
|
||||||
|
static parse(selector: string): CssSelector[] {
|
||||||
|
const results: CssSelector[] = [];
|
||||||
|
const _addResult = (res: CssSelector[], cssSel: CssSelector) => {
|
||||||
|
if (cssSel.notSelectors.length > 0 && !cssSel.element && cssSel.classNames.length == 0 &&
|
||||||
|
cssSel.attrs.length == 0) {
|
||||||
|
cssSel.element = '*';
|
||||||
|
}
|
||||||
|
res.push(cssSel);
|
||||||
|
};
|
||||||
|
let cssSelector = new CssSelector();
|
||||||
|
let match: string[];
|
||||||
|
let current = cssSelector;
|
||||||
|
let inNot = false;
|
||||||
|
_SELECTOR_REGEXP.lastIndex = 0;
|
||||||
|
while (match = _SELECTOR_REGEXP.exec(selector)) {
|
||||||
|
if (match[1]) {
|
||||||
|
if (inNot) {
|
||||||
|
throw new Error('Nesting :not is not allowed in a selector');
|
||||||
|
}
|
||||||
|
inNot = true;
|
||||||
|
current = new CssSelector();
|
||||||
|
cssSelector.notSelectors.push(current);
|
||||||
|
}
|
||||||
|
if (match[2]) {
|
||||||
|
current.setElement(match[2]);
|
||||||
|
}
|
||||||
|
if (match[3]) {
|
||||||
|
current.addClassName(match[3]);
|
||||||
|
}
|
||||||
|
if (match[4]) {
|
||||||
|
current.addAttribute(match[4], match[5]);
|
||||||
|
}
|
||||||
|
if (match[6]) {
|
||||||
|
inNot = false;
|
||||||
|
current = cssSelector;
|
||||||
|
}
|
||||||
|
if (match[7]) {
|
||||||
|
if (inNot) {
|
||||||
|
throw new Error('Multiple selectors in :not are not supported');
|
||||||
|
}
|
||||||
|
_addResult(results, cssSelector);
|
||||||
|
cssSelector = current = new CssSelector();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_addResult(results, cssSelector);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
isElementSelector(): boolean {
|
||||||
|
return this.hasElementSelector() && this.classNames.length == 0 && this.attrs.length == 0 &&
|
||||||
|
this.notSelectors.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasElementSelector(): boolean { return !!this.element; }
|
||||||
|
|
||||||
|
setElement(element: string = null) { this.element = element; }
|
||||||
|
|
||||||
|
/** Gets a template string for an element that matches the selector. */
|
||||||
|
getMatchingElementTemplate(): string {
|
||||||
|
const tagName = this.element || 'div';
|
||||||
|
const classAttr = this.classNames.length > 0 ? ` class="${this.classNames.join(' ')}"` : '';
|
||||||
|
|
||||||
|
let attrs = '';
|
||||||
|
for (let i = 0; i < this.attrs.length; i += 2) {
|
||||||
|
const attrName = this.attrs[i];
|
||||||
|
const attrValue = this.attrs[i + 1] !== '' ? `="${this.attrs[i + 1]}"` : '';
|
||||||
|
attrs += ` ${attrName}${attrValue}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getHtmlTagDefinition(tagName).isVoid ? `<${tagName}${classAttr}${attrs}/>` :
|
||||||
|
`<${tagName}${classAttr}${attrs}></${tagName}>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
addAttribute(name: string, value: string = '') {
|
||||||
|
this.attrs.push(name, value && value.toLowerCase() || '');
|
||||||
|
}
|
||||||
|
|
||||||
|
addClassName(name: string) { this.classNames.push(name.toLowerCase()); }
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
let res: string = this.element || '';
|
||||||
|
if (this.classNames) {
|
||||||
|
this.classNames.forEach(klass => res += `.${klass}`);
|
||||||
|
}
|
||||||
|
if (this.attrs) {
|
||||||
|
for (let i = 0; i < this.attrs.length; i += 2) {
|
||||||
|
const name = this.attrs[i];
|
||||||
|
const value = this.attrs[i + 1];
|
||||||
|
res += `[${name}${value ? '=' + value : ''}]`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.notSelectors.forEach(notSelector => res += `:not(${notSelector})`);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a list of CssSelectors and allows to calculate which ones
|
||||||
|
* are contained in a given CssSelector.
|
||||||
|
*/
|
||||||
|
export class SelectorMatcher {
|
||||||
|
static createNotMatcher(notSelectors: CssSelector[]): SelectorMatcher {
|
||||||
|
const notMatcher = new SelectorMatcher();
|
||||||
|
notMatcher.addSelectables(notSelectors, null);
|
||||||
|
return notMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _elementMap = new Map<string, SelectorContext[]>();
|
||||||
|
private _elementPartialMap = new Map<string, SelectorMatcher>();
|
||||||
|
private _classMap = new Map<string, SelectorContext[]>();
|
||||||
|
private _classPartialMap = new Map<string, SelectorMatcher>();
|
||||||
|
private _attrValueMap = new Map<string, Map<string, SelectorContext[]>>();
|
||||||
|
private _attrValuePartialMap = new Map<string, Map<string, SelectorMatcher>>();
|
||||||
|
private _listContexts: SelectorListContext[] = [];
|
||||||
|
|
||||||
|
addSelectables(cssSelectors: CssSelector[], callbackCtxt?: any) {
|
||||||
|
let listContext: SelectorListContext = null;
|
||||||
|
if (cssSelectors.length > 1) {
|
||||||
|
listContext = new SelectorListContext(cssSelectors);
|
||||||
|
this._listContexts.push(listContext);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < cssSelectors.length; i++) {
|
||||||
|
this._addSelectable(cssSelectors[i], callbackCtxt, listContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an object that can be found later on by calling `match`.
|
||||||
|
* @param cssSelector A css selector
|
||||||
|
* @param callbackCtxt An opaque object that will be given to the callback of the `match` function
|
||||||
|
*/
|
||||||
|
private _addSelectable(
|
||||||
|
cssSelector: CssSelector, callbackCtxt: any, listContext: SelectorListContext) {
|
||||||
|
let matcher: SelectorMatcher = this;
|
||||||
|
const element = cssSelector.element;
|
||||||
|
const classNames = cssSelector.classNames;
|
||||||
|
const attrs = cssSelector.attrs;
|
||||||
|
const selectable = new SelectorContext(cssSelector, callbackCtxt, listContext);
|
||||||
|
|
||||||
|
if (element) {
|
||||||
|
const isTerminal = attrs.length === 0 && classNames.length === 0;
|
||||||
|
if (isTerminal) {
|
||||||
|
this._addTerminal(matcher._elementMap, element, selectable);
|
||||||
|
} else {
|
||||||
|
matcher = this._addPartial(matcher._elementPartialMap, element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (classNames) {
|
||||||
|
for (let i = 0; i < classNames.length; i++) {
|
||||||
|
const isTerminal = attrs.length === 0 && i === classNames.length - 1;
|
||||||
|
const className = classNames[i];
|
||||||
|
if (isTerminal) {
|
||||||
|
this._addTerminal(matcher._classMap, className, selectable);
|
||||||
|
} else {
|
||||||
|
matcher = this._addPartial(matcher._classPartialMap, className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrs) {
|
||||||
|
for (let i = 0; i < attrs.length; i += 2) {
|
||||||
|
const isTerminal = i === attrs.length - 2;
|
||||||
|
const name = attrs[i];
|
||||||
|
const value = attrs[i + 1];
|
||||||
|
if (isTerminal) {
|
||||||
|
const terminalMap = matcher._attrValueMap;
|
||||||
|
let terminalValuesMap = terminalMap.get(name);
|
||||||
|
if (!terminalValuesMap) {
|
||||||
|
terminalValuesMap = new Map<string, SelectorContext[]>();
|
||||||
|
terminalMap.set(name, terminalValuesMap);
|
||||||
|
}
|
||||||
|
this._addTerminal(terminalValuesMap, value, selectable);
|
||||||
|
} else {
|
||||||
|
const partialMap = matcher._attrValuePartialMap;
|
||||||
|
let partialValuesMap = partialMap.get(name);
|
||||||
|
if (!partialValuesMap) {
|
||||||
|
partialValuesMap = new Map<string, SelectorMatcher>();
|
||||||
|
partialMap.set(name, partialValuesMap);
|
||||||
|
}
|
||||||
|
matcher = this._addPartial(partialValuesMap, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _addTerminal(
|
||||||
|
map: Map<string, SelectorContext[]>, name: string, selectable: SelectorContext) {
|
||||||
|
let terminalList = map.get(name);
|
||||||
|
if (!terminalList) {
|
||||||
|
terminalList = [];
|
||||||
|
map.set(name, terminalList);
|
||||||
|
}
|
||||||
|
terminalList.push(selectable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _addPartial(map: Map<string, SelectorMatcher>, name: string): SelectorMatcher {
|
||||||
|
let matcher = map.get(name);
|
||||||
|
if (!matcher) {
|
||||||
|
matcher = new SelectorMatcher();
|
||||||
|
map.set(name, matcher);
|
||||||
|
}
|
||||||
|
return matcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the objects that have been added via `addSelectable`
|
||||||
|
* whose css selector is contained in the given css selector.
|
||||||
|
* @param cssSelector A css selector
|
||||||
|
* @param matchedCallback This callback will be called with the object handed into `addSelectable`
|
||||||
|
* @return boolean true if a match was found
|
||||||
|
*/
|
||||||
|
match(cssSelector: CssSelector, matchedCallback: (c: CssSelector, a: any) => void): boolean {
|
||||||
|
let result = false;
|
||||||
|
const element = cssSelector.element;
|
||||||
|
const classNames = cssSelector.classNames;
|
||||||
|
const attrs = cssSelector.attrs;
|
||||||
|
|
||||||
|
for (let i = 0; i < this._listContexts.length; i++) {
|
||||||
|
this._listContexts[i].alreadyMatched = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = this._matchTerminal(this._elementMap, element, cssSelector, matchedCallback) || result;
|
||||||
|
result = this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) ||
|
||||||
|
result;
|
||||||
|
|
||||||
|
if (classNames) {
|
||||||
|
for (let i = 0; i < classNames.length; i++) {
|
||||||
|
const className = classNames[i];
|
||||||
|
result =
|
||||||
|
this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result;
|
||||||
|
result =
|
||||||
|
this._matchPartial(this._classPartialMap, className, cssSelector, matchedCallback) ||
|
||||||
|
result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrs) {
|
||||||
|
for (let i = 0; i < attrs.length; i += 2) {
|
||||||
|
const name = attrs[i];
|
||||||
|
const value = attrs[i + 1];
|
||||||
|
|
||||||
|
const terminalValuesMap = this._attrValueMap.get(name);
|
||||||
|
if (value) {
|
||||||
|
result =
|
||||||
|
this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result;
|
||||||
|
}
|
||||||
|
result =
|
||||||
|
this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result;
|
||||||
|
|
||||||
|
const partialValuesMap = this._attrValuePartialMap.get(name);
|
||||||
|
if (value) {
|
||||||
|
result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result;
|
||||||
|
}
|
||||||
|
result =
|
||||||
|
this._matchPartial(partialValuesMap, value, cssSelector, matchedCallback) || result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
_matchTerminal(
|
||||||
|
map: Map<string, SelectorContext[]>, name: string, cssSelector: CssSelector,
|
||||||
|
matchedCallback: (c: CssSelector, a: any) => void): boolean {
|
||||||
|
if (!map || typeof name !== 'string') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let selectables: SelectorContext[] = map.get(name) || [];
|
||||||
|
const starSelectables: SelectorContext[] = map.get('*');
|
||||||
|
if (starSelectables) {
|
||||||
|
selectables = selectables.concat(starSelectables);
|
||||||
|
}
|
||||||
|
if (selectables.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let selectable: SelectorContext;
|
||||||
|
let result = false;
|
||||||
|
for (let i = 0; i < selectables.length; i++) {
|
||||||
|
selectable = selectables[i];
|
||||||
|
result = selectable.finalize(cssSelector, matchedCallback) || result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
_matchPartial(
|
||||||
|
map: Map<string, SelectorMatcher>, name: string, cssSelector: CssSelector,
|
||||||
|
matchedCallback: (c: CssSelector, a: any) => void): boolean {
|
||||||
|
if (!map || typeof name !== 'string') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nestedSelector = map.get(name);
|
||||||
|
if (!nestedSelector) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// TODO(perf): get rid of recursion and measure again
|
||||||
|
// TODO(perf): don't pass the whole selector into the recursion,
|
||||||
|
// but only the not processed parts
|
||||||
|
return nestedSelector.match(cssSelector, matchedCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class SelectorListContext {
|
||||||
|
alreadyMatched: boolean = false;
|
||||||
|
|
||||||
|
constructor(public selectors: CssSelector[]) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store context to pass back selector and context when a selector is matched
|
||||||
|
export class SelectorContext {
|
||||||
|
notSelectors: CssSelector[];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public selector: CssSelector, public cbContext: any,
|
||||||
|
public listContext: SelectorListContext) {
|
||||||
|
this.notSelectors = selector.notSelectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
finalize(cssSelector: CssSelector, callback: (c: CssSelector, a: any) => void): boolean {
|
||||||
|
let result = true;
|
||||||
|
if (this.notSelectors.length > 0 && (!this.listContext || !this.listContext.alreadyMatched)) {
|
||||||
|
const notMatcher = SelectorMatcher.createNotMatcher(this.notSelectors);
|
||||||
|
result = !notMatcher.match(cssSelector, null);
|
||||||
|
}
|
||||||
|
if (result && callback && (!this.listContext || !this.listContext.alreadyMatched)) {
|
||||||
|
if (this.listContext) {
|
||||||
|
this.listContext.alreadyMatched = true;
|
||||||
|
}
|
||||||
|
callback(this.selector, this.cbContext);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,8 @@
|
||||||
import {ChangeDetectorRef, ComponentFactory, ComponentRef, EventEmitter, Injector, OnChanges, ReflectiveInjector, SimpleChange, SimpleChanges, Type} from '@angular/core';
|
import {ChangeDetectorRef, ComponentFactory, ComponentRef, EventEmitter, Injector, OnChanges, ReflectiveInjector, SimpleChange, SimpleChanges, Type} from '@angular/core';
|
||||||
|
|
||||||
import * as angular from './angular1';
|
import * as angular from './angular1';
|
||||||
|
import {createElementCssSelector} from './compiler_helpers/createElementCssSelector';
|
||||||
|
import {CssSelector, SelectorMatcher} from './compiler_helpers/selector';
|
||||||
import {ComponentInfo, PropertyBinding} from './component_info';
|
import {ComponentInfo, PropertyBinding} from './component_info';
|
||||||
import {$SCOPE} from './constants';
|
import {$SCOPE} from './constants';
|
||||||
import {NgContentSelectorHelper} from './ng_content_selector_helper';
|
import {NgContentSelectorHelper} from './ng_content_selector_helper';
|
||||||
|
@ -199,52 +201,38 @@ export class DowngradeComponentAdapter {
|
||||||
*/
|
*/
|
||||||
private _groupNodesBySelector(ngContentSelectors: string[], nodes: Node[]): Node[][] {
|
private _groupNodesBySelector(ngContentSelectors: string[], nodes: Node[]): Node[][] {
|
||||||
const projectableNodes: Node[][] = [];
|
const projectableNodes: Node[][] = [];
|
||||||
|
let matcher = new SelectorMatcher();
|
||||||
let wildcardNgContentIndex: number;
|
let wildcardNgContentIndex: number;
|
||||||
|
|
||||||
for (let i = 0, ii = ngContentSelectors.length; i < ii; ++i) {
|
for (let i = 0, ii = ngContentSelectors.length; i < ii; ++i) {
|
||||||
projectableNodes[i] = [];
|
projectableNodes[i] = [];
|
||||||
|
|
||||||
|
const selector = ngContentSelectors[i];
|
||||||
|
if (selector === '*') {
|
||||||
|
wildcardNgContentIndex = i;
|
||||||
|
} else {
|
||||||
|
matcher.addSelectables(CssSelector.parse(selector), i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let j = 0, jj = nodes.length; j < jj; ++j) {
|
for (let j = 0, jj = nodes.length; j < jj; ++j) {
|
||||||
|
const ngContentIndices: number[] = [];
|
||||||
const node = nodes[j];
|
const node = nodes[j];
|
||||||
const ngContentIndex = findMatchingNgContentIndex(node, ngContentSelectors);
|
const selector =
|
||||||
if (ngContentIndex != null) {
|
createElementCssSelector(node.nodeName.toLowerCase(), getAttributesAsArray(node));
|
||||||
projectableNodes[ngContentIndex].push(node);
|
|
||||||
|
matcher.match(selector, (_, index) => ngContentIndices.push(index));
|
||||||
|
ngContentIndices.sort();
|
||||||
|
|
||||||
|
if (wildcardNgContentIndex !== undefined) {
|
||||||
|
ngContentIndices.push(wildcardNgContentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ngContentIndices.length) {
|
||||||
|
projectableNodes[ngContentIndices[0]].push(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return projectableNodes;
|
return projectableNodes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _matches: (this: any, selector: string) => boolean;
|
|
||||||
|
|
||||||
function matchesSelector(el: any, selector: string): boolean {
|
|
||||||
if (!_matches) {
|
|
||||||
const elProto = <any>Element.prototype;
|
|
||||||
_matches = elProto.matchesSelector || elProto.mozMatchesSelector || elProto.msMatchesSelector ||
|
|
||||||
elProto.oMatchesSelector || elProto.webkitMatchesSelector;
|
|
||||||
}
|
|
||||||
return _matches.call(el, selector);
|
|
||||||
}
|
|
||||||
|
|
||||||
function findMatchingNgContentIndex(element: any, ngContentSelectors: string[]): number {
|
|
||||||
const ngContentIndices: number[] = [];
|
|
||||||
let wildcardNgContentIndex: number;
|
|
||||||
for (let i = 0; i < ngContentSelectors.length; i++) {
|
|
||||||
const selector = ngContentSelectors[i];
|
|
||||||
if (selector === '*') {
|
|
||||||
wildcardNgContentIndex = i;
|
|
||||||
} else {
|
|
||||||
if (matchesSelector(element, selector)) {
|
|
||||||
ngContentIndices.push(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ngContentIndices.sort();
|
|
||||||
|
|
||||||
if (wildcardNgContentIndex !== undefined) {
|
|
||||||
ngContentIndices.push(wildcardNgContentIndex);
|
|
||||||
}
|
|
||||||
return ngContentIndices.length ? ngContentIndices[0] : null;
|
|
||||||
}
|
|
Loading…
Reference in New Issue