UNPKG

@extjs/sencha-cmd-linux-32

Version:

Productivity and performance optimization tool for building applications with Sencha Ext JS and Sencha Touch.

284 lines (239 loc) 8.75 kB
"use strict"; var Fashion = require('./export/Base.js'); var TypeVisitor = require('./type/TypeVisitor.js'); var Declaration = require('./type/Declaration.js'); var Ruleset = require('./type/Ruleset.js'); var SelectorList = require('./type/selectors/SelectorList.js'); var MultiPartSelector = require('./type/selectors/MultiPartSelector.js'); var Types = require('./type/Types.js'), Literal = Types.Literal; class CssPostprocessor extends TypeVisitor { constructor(cfg) { super(cfg); } selector(obj) { if (obj.selectorType === 'parent') { if (this.currentParentSelector) { obj.visitTarget = this.currentParentSelector; this.parentUsed = true; } else if (this.strictParentRef) { Fashion.raise("Base-level rules cannot contain the parent-selector-referencing character '&'."); } } } literal(obj) { if (obj.value === '&') { if (this.currentParentSelector) { obj.visitTarget = this.currentParentSelector; } else if (this.strictParentRef) { Fashion.raise("Base-level rules cannot contain the parent-selector-referencing character '&'."); } } } getSelectorArray(selectors, applyInterpolations) { if (selectors instanceof SelectorList) { if (applyInterpolations) { selectors.applyInterpolations(); } selectors = selectors.items; } else { var str = selectors.toString(); if (str.indexOf(',') > -1 && applyInterpolations) { return this.getSelectorArray(this.context.parseSelectors(str)); } selectors = [selectors]; } return selectors; } combineSelectors(parent, child) { var parentSelectors = this.getSelectorArray(parent.selectors), childSelectors = this.getSelectorArray(child.selectors), expandedSelectors = [], plen = parentSelectors.length, clen = childSelectors.length, p, c, parentSelector, childSelector; for (p = 0; p < plen; p++) { parentSelector = parentSelectors[p]; this.currentParentSelector = parentSelector; for (c = 0; c < clen; c++) { childSelector = childSelectors[c].clone(); this.parentUsed = false; this.visit(childSelector); if (!this.parentUsed) { childSelector = new MultiPartSelector([parentSelector, childSelector]); } expandedSelectors.push(childSelector); } } this.currentParentSelector = null; if (expandedSelectors.length == 1) { expandedSelectors = expandedSelectors[0] } else { expandedSelectors = new SelectorList(expandedSelectors); } child.selectors = expandedSelectors; } combineMediaSelectors(parent, child) { var expanded = [], selectors = this.getSelectorArray(parent.selectors), items = this.getSelectorArray(child.selectors), parentSelector, nestedSelector; for (var s = 0; s < selectors.length; s++) { parentSelector = selectors[s]; for (var n = 0; n < items.length; n++) { nestedSelector = items[n]; if (n === 0) { // remove the @media portion nestedSelector.items = nestedSelector.items.slice(1); } this.currentParentSelector = parentSelector; this.parentUsed = false; this.visit(nestedSelector); this.parentUsed = false; var newSelector = new MultiPartSelector([ parentSelector, new Literal('and'), nestedSelector ]); newSelector.skipParentPrepend = child.isAtRoot(); expanded.push(newSelector); } } if (expanded.length === 1) { expanded = expanded[0]; } else { expanded = new SelectorList(expanded); } child.selectors = expanded; } declaration(obj) { var declWas = this.currDeclaration; this.currDeclaration = obj; obj.descend(this); this.currDeclaration = declWas; } ruleset(obj) { var prevMedia = this.prevMedia, prevAtRoot = this.prevAtRoot, prevAtRule = this.prevAtRule, prevPlain = this.prevPlain, atRoot = false, declaration = this.currDeclaration, parent, ns, d, decl, idx; if (obj.isNamespaced) { // first, process any nested namespaced rulesets this.visit(obj.declarations); if (declaration) { ns = declaration.property; parent = declaration.ruleset; idx = parent.getDeclarationIndex(declaration); if (idx === -1) { idx = parent.declarations.length; } for (d = 0; d < obj.declarations.length; d++) { decl = obj.declarations[d]; parent.addDeclaration(new Declaration({ property: ns + '-' + decl.property, value: decl.value, docs: decl.docs, sourceInfo: decl.sourceInfo, important: decl.important }), d + idx); } // prevent this obj from generating css output obj.visitTarget = null; // if this is the immediate child of the declaration // then skip that as well during css gen if (obj.parentNode === declaration) { parent.removeDeclaration(declaration); } } return false; } obj.selectors = this.getSelectorArray(obj.selectors, true); if (obj.selectors.length === 1) { obj.selectors = obj.selectors[0]; } else { obj.selectors = new SelectorList(obj.selectors); } if (obj.isAtRule()) { this.prevAtRule = obj; if (prevPlain && obj.declarations.length) { var newRuleset = new Ruleset({ parent: obj, declarations: obj.declarations, selectors: prevPlain.selectors, isMediaRoot: true }); newRuleset.declarations.forEach((d) => d.ruleset = newRuleset); obj.declarations = []; obj.children.unshift(newRuleset); } if (!prevAtRule) { atRoot = true; } } if (obj.isMedia()) { if (prevMedia) { this.combineMediaSelectors(prevMedia, obj); } this.prevMedia = obj; atRoot = true; } else if (obj.isAtRoot()) { atRoot = true; } else if (!obj.isAtRule()) { if (prevPlain && !obj.isMediaRoot) { this.combineSelectors(prevPlain, obj); } this.prevPlain = obj; if (!prevAtRule) { atRoot = true; } } if (atRoot) { if (obj.parent) { obj.parent.removeChildRuleset(obj); } // we may want to exlude the ruleset from printing if (obj.isAtRule() || obj.declarations.length || obj.isAtDirective) { this.rootCss.push(obj); } } obj.descend(this); this.prevMedia = prevMedia; this.prevAtRoot = prevAtRoot; this.prevPlain = prevPlain; this.prevAtRule = prevAtRule; return false; } visitItem(obj) { var currParent = this.currParent; obj.parentNode = currParent; this.currParent = obj; super.visitItem(obj); this.currParent = currParent; } process(obj) { this.rootCss = []; this.visit(obj); return this.rootCss; } } Fashion.apply(CssPostprocessor.prototype, { currentParentSelector: null, parentUsed: null, rootCss: null, context: null, prevMedia: null, prevAtRule: null, prevAtRoot: null, prevPlain: null, currDeclaration: null, currParent: null, strictParentRef: false }); module.exports = CssPostprocessor;