@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
JavaScript
"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;