/Tour of Heroes/node_modules/@angular/compiler/src/selector.js
JavaScript | 339 lines | 303 code | 0 blank | 36 comment | 77 complexity | 0c800c81e2cdc3b229b559a896396190 MD5 | raw file
- /**
- * @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';
- var _SELECTOR_REGEXP = new RegExp('(\\:not\\()|' +
- '([-\\w]+)|' +
- '(?:\\.([-\\w]+))|' +
- '(?:\\[([-\\w*]+)(?:=([^\\]]*))?\\])|' +
- '(\\))|' +
- '(\\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 var CssSelector = (function () {
- function CssSelector() {
- this.element = null;
- this.classNames = [];
- this.attrs = [];
- this.notSelectors = [];
- }
- CssSelector.parse = function (selector) {
- var results = [];
- var _addResult = function (res, cssSel) {
- if (cssSel.notSelectors.length > 0 && !cssSel.element && cssSel.classNames.length == 0 &&
- cssSel.attrs.length == 0) {
- cssSel.element = '*';
- }
- res.push(cssSel);
- };
- var cssSelector = new CssSelector();
- var match;
- var current = cssSelector;
- var 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;
- };
- CssSelector.prototype.isElementSelector = function () {
- return this.hasElementSelector() && this.classNames.length == 0 && this.attrs.length == 0 &&
- this.notSelectors.length === 0;
- };
- CssSelector.prototype.hasElementSelector = function () { return !!this.element; };
- CssSelector.prototype.setElement = function (element) {
- if (element === void 0) { element = null; }
- this.element = element;
- };
- /** Gets a template string for an element that matches the selector. */
- CssSelector.prototype.getMatchingElementTemplate = function () {
- var tagName = this.element || 'div';
- var classAttr = this.classNames.length > 0 ? " class=\"" + this.classNames.join(' ') + "\"" : '';
- var attrs = '';
- for (var i = 0; i < this.attrs.length; i += 2) {
- var attrName = this.attrs[i];
- var attrValue = this.attrs[i + 1] !== '' ? "=\"" + this.attrs[i + 1] + "\"" : '';
- attrs += " " + attrName + attrValue;
- }
- return getHtmlTagDefinition(tagName).isVoid ? "<" + tagName + classAttr + attrs + "/>" :
- "<" + tagName + classAttr + attrs + "></" + tagName + ">";
- };
- CssSelector.prototype.addAttribute = function (name, value) {
- if (value === void 0) { value = ''; }
- this.attrs.push(name, value && value.toLowerCase() || '');
- };
- CssSelector.prototype.addClassName = function (name) { this.classNames.push(name.toLowerCase()); };
- CssSelector.prototype.toString = function () {
- var res = this.element || '';
- if (this.classNames) {
- this.classNames.forEach(function (klass) { return res += "." + klass; });
- }
- if (this.attrs) {
- for (var i = 0; i < this.attrs.length; i += 2) {
- var name_1 = this.attrs[i];
- var value = this.attrs[i + 1];
- res += "[" + name_1 + (value ? '=' + value : '') + "]";
- }
- }
- this.notSelectors.forEach(function (notSelector) { return res += ":not(" + notSelector + ")"; });
- return res;
- };
- return CssSelector;
- }());
- /**
- * Reads a list of CssSelectors and allows to calculate which ones
- * are contained in a given CssSelector.
- */
- export var SelectorMatcher = (function () {
- function SelectorMatcher() {
- this._elementMap = {};
- this._elementPartialMap = {};
- this._classMap = {};
- this._classPartialMap = {};
- this._attrValueMap = {};
- this._attrValuePartialMap = {};
- this._listContexts = [];
- }
- SelectorMatcher.createNotMatcher = function (notSelectors) {
- var notMatcher = new SelectorMatcher();
- notMatcher.addSelectables(notSelectors, null);
- return notMatcher;
- };
- SelectorMatcher.prototype.addSelectables = function (cssSelectors, callbackCtxt) {
- var listContext = null;
- if (cssSelectors.length > 1) {
- listContext = new SelectorListContext(cssSelectors);
- this._listContexts.push(listContext);
- }
- for (var 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
- */
- SelectorMatcher.prototype._addSelectable = function (cssSelector, callbackCtxt, listContext) {
- var matcher = this;
- var element = cssSelector.element;
- var classNames = cssSelector.classNames;
- var attrs = cssSelector.attrs;
- var selectable = new SelectorContext(cssSelector, callbackCtxt, listContext);
- if (element) {
- var 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 (var i = 0; i < classNames.length; i++) {
- var isTerminal = attrs.length === 0 && i === classNames.length - 1;
- var className = classNames[i];
- if (isTerminal) {
- this._addTerminal(matcher._classMap, className, selectable);
- }
- else {
- matcher = this._addPartial(matcher._classPartialMap, className);
- }
- }
- }
- if (attrs) {
- for (var i = 0; i < attrs.length; i += 2) {
- var isTerminal = i === attrs.length - 2;
- var name_2 = attrs[i];
- var value = attrs[i + 1];
- if (isTerminal) {
- var terminalMap = matcher._attrValueMap;
- var terminalValuesMap = terminalMap[name_2];
- if (!terminalValuesMap) {
- terminalValuesMap = {};
- terminalMap[name_2] = terminalValuesMap;
- }
- this._addTerminal(terminalValuesMap, value, selectable);
- }
- else {
- var partialMap = matcher._attrValuePartialMap;
- var partialValuesMap = partialMap[name_2];
- if (!partialValuesMap) {
- partialValuesMap = {};
- partialMap[name_2] = partialValuesMap;
- }
- matcher = this._addPartial(partialValuesMap, value);
- }
- }
- }
- };
- SelectorMatcher.prototype._addTerminal = function (map, name, selectable) {
- var terminalList = map[name];
- if (!terminalList) {
- terminalList = [];
- map[name] = terminalList;
- }
- terminalList.push(selectable);
- };
- SelectorMatcher.prototype._addPartial = function (map, name) {
- var matcher = map[name];
- if (!matcher) {
- matcher = new SelectorMatcher();
- map[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
- */
- SelectorMatcher.prototype.match = function (cssSelector, matchedCallback) {
- var result = false;
- var element = cssSelector.element;
- var classNames = cssSelector.classNames;
- var attrs = cssSelector.attrs;
- for (var 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 (var i = 0; i < classNames.length; i++) {
- var className = classNames[i];
- result =
- this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result;
- result =
- this._matchPartial(this._classPartialMap, className, cssSelector, matchedCallback) ||
- result;
- }
- }
- if (attrs) {
- for (var i = 0; i < attrs.length; i += 2) {
- var name_3 = attrs[i];
- var value = attrs[i + 1];
- var terminalValuesMap = this._attrValueMap[name_3];
- if (value) {
- result =
- this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result;
- }
- result =
- this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result;
- var partialValuesMap = this._attrValuePartialMap[name_3];
- if (value) {
- result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result;
- }
- result =
- this._matchPartial(partialValuesMap, value, cssSelector, matchedCallback) || result;
- }
- }
- return result;
- };
- /** @internal */
- SelectorMatcher.prototype._matchTerminal = function (map, name, cssSelector, matchedCallback) {
- if (!map || typeof name !== 'string') {
- return false;
- }
- var selectables = map[name];
- var starSelectables = map['*'];
- if (starSelectables) {
- selectables = selectables.concat(starSelectables);
- }
- if (!selectables) {
- return false;
- }
- var selectable;
- var result = false;
- for (var i = 0; i < selectables.length; i++) {
- selectable = selectables[i];
- result = selectable.finalize(cssSelector, matchedCallback) || result;
- }
- return result;
- };
- /** @internal */
- SelectorMatcher.prototype._matchPartial = function (map, name, cssSelector, matchedCallback) {
- if (!map || typeof name !== 'string') {
- return false;
- }
- var nestedSelector = map[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);
- };
- return SelectorMatcher;
- }());
- export var SelectorListContext = (function () {
- function SelectorListContext(selectors) {
- this.selectors = selectors;
- this.alreadyMatched = false;
- }
- return SelectorListContext;
- }());
- // Store context to pass back selector and context when a selector is matched
- export var SelectorContext = (function () {
- function SelectorContext(selector, cbContext, listContext) {
- this.selector = selector;
- this.cbContext = cbContext;
- this.listContext = listContext;
- this.notSelectors = selector.notSelectors;
- }
- SelectorContext.prototype.finalize = function (cssSelector, callback) {
- var result = true;
- if (this.notSelectors.length > 0 && (!this.listContext || !this.listContext.alreadyMatched)) {
- var 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;
- };
- return SelectorContext;
- }());
- //# sourceMappingURL=selector.js.map