@extjs/sencha-cmd-linux-32
Version:
Productivity and performance optimization tool for building applications with Sencha Ext JS and Sencha Touch.
512 lines (442 loc) • 16.4 kB
JavaScript
"use strict";
var Fashion = require('./export/Base.js');
var TypeVisitor = require('./type/TypeVisitor.js');
var SelectorList = require('./type/selectors/SelectorList.js');
var MultiPartSelector = require('./type/selectors/MultiPartSelector.js');
var CompoundSelector = require('./type/selectors/CompoundSelector.js');
var SourceBuilder = require('./type/SourceBuilder.js');
function pushApply (array, items) {
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (!!item) {
array.push(item);
}
}
}
function joinArrays () {
var arrays = arguments,
out = [];
for (var i = 0; i < arrays.length; i++) {
var array = arrays[i];
if (Array.isArray(array)) {
pushApply(out, arrays[i]);
}
else if (!!array) {
out.push(array);
}
}
return out;
}
class ExtendProcessor extends TypeVisitor {
constructor(cfg) {
super(cfg);
}
mergeCompoundSelector(match, extendSelector, matchKeys, targetKeys) {
var origCompoundSelector = this.currCompoundSelector,
compoundSelector = origCompoundSelector,
multiPartSelector = this.currMultiPartSelector,
items = [],
newCompoundSelector, matchIndex;
for (var i = 0; i < compoundSelector.items.length; i++) {
var item = compoundSelector.items[i];
while (item && item.visitTarget) {
item = item.visitTarget;
}
if(item && item.$isFashionBaseSelectorList) {
compoundSelector = this.context.parseSelectors(SourceBuilder.toSource(compoundSelector));
multiPartSelector = null;
}
}
// first, remove the matched component,
for (var i = 0; i < compoundSelector.items.length; i++) {
var item = compoundSelector.items[i];
var hash = item.getHash();
if (targetKeys) {
if (!targetKeys.hasOwnProperty(hash)) {
items.push(item);
} else {
matchIndex = i;
items.push(null);
}
}
else {
if (hash != match.getHash()) {
items.push(item);
} else {
matchIndex = i;
items.push(null);
}
}
}
// then, if the extending selector is multi part,
// merge this with the last component of that selector,
if (extendSelector instanceof MultiPartSelector) {
var newSelector = extendSelector.clone(),
last = newSelector.last();
if (last instanceof CompoundSelector) {
last.setItems(joinArrays(items, last.items));
}
// we may have reprocessed the compound selector into being a multi part
// selector, due to expansion of a visitTarget override added by a parent
// selector reference (& selector operator)
else if (compoundSelector.$isFashionMultiPartSelector) {
last = new MultiPartSelector(joinArrays([last], items));
newSelector.items[newSelector.items.length - 1] = last;
}
else {
last = new CompoundSelector(joinArrays([last], items));
newSelector.items[newSelector.items.length - 1] = last;
}
newCompoundSelector = newSelector;
}
else if (extendSelector instanceof CompoundSelector) {
items.splice.apply(items, [matchIndex, 1].concat(extendSelector.items));
} else {
items[matchIndex] = extendSelector;
}
newCompoundSelector = newCompoundSelector || new CompoundSelector(items);
if (multiPartSelector) {
var newItems = [];
for (var i = 0; i < multiPartSelector.items.length; i++) {
var item = multiPartSelector.items[i];
if (item === origCompoundSelector) {
newItems.push(newCompoundSelector);
} else {
newItems.push(item);
}
}
this.newSelectors.push(new MultiPartSelector(newItems));
} else {
this.newSelectors.push(newCompoundSelector);
}
}
mergeMultiPartSelector(match, extendSelector) {
var multiPartSelector = this.currMultiPartSelector,
items = multiPartSelector.items,
len = items.length, i, item,
before, after;
for (i = 0; i < len; i++) {
item = items[i];
if (item.getHash() === match.getHash()) {
before = items.slice(0, i);
after = items.slice(i + 1);
// if we're trying to insert a new multi-part selector,
// we need to weave the prefix elements together
if (extendSelector instanceof MultiPartSelector) {
var mpExtendSelector = extendSelector,
extendItems = mpExtendSelector.items,
elen = extendItems.length,
first = extendItems.slice(0, elen - 1),
last = extendItems.slice(elen - 1);
// weave the two sets of items together
this.newSelectors.push(new MultiPartSelector(
joinArrays(before, first, last, after)
));
this.newSelectors.push(new MultiPartSelector(
joinArrays(first, before, last, after)
));
}
else {
this.newSelectors.push(new MultiPartSelector(
joinArrays(before, extendSelector, after)
));
}
}
}
}
checkSelectorPart(obj) {
if (obj.getHash() === this.currTargetHash) {
if (this.currCompoundSelector) {
for (var e = 0; e < this.extendSelectors.length; e++) {
var extendSelector = this.extendSelectors[e];
this.mergeCompoundSelector(obj, extendSelector);
}
}
else if (this.currMultiPartSelector) {
// need to weave together the current multi-part selector
// with the various extending selectors;
for (var e = 0; e < this.extendSelectors.length; e++) {
var extendSelector = this.extendSelectors[e];
this.mergeMultiPartSelector(obj, extendSelector);
}
}
else {
this.appendAllExtendSelectors();
}
}
}
appendAllExtendSelectors() {
this.newSelectors.push.apply(this.newSelectors, this.extendSelectors);
}
getCompoundSelectorMap(compoundSelector) {
var map = {},
item;
for (var i = 0; i < compoundSelector.items.length; i++) {
item = compoundSelector.items[i];
map[item.getHash()] = true;
}
return map;
}
//--------------------------------------------------
// visitor methods
literal(obj) {
this.checkSelectorPart(obj);
}
selector(obj) {
this.checkSelectorPart(obj);
}
compoundselector(obj) {
var resetCompoundSelector = this.currCompoundSelector;
this.currCompoundSelector = obj;
if (obj.getHash() === this.currTargetHash) {
this.appendAllExtendSelectors();
}
else if (this.currTarget instanceof CompoundSelector) {
// need to check for a subset match
var objMap = this.getCompoundSelectorMap(obj),
targetMap = this.getCompoundSelectorMap(this.currTarget),
objKeys = Object.keys(objMap),
targetKeys = Object.keys(targetMap),
subset = true,
targetKey;
for (var t = 0; t < targetKeys.length; t++) {
targetKey = targetKeys[t];
if (!objKeys.hasOwnProperty(targetKey)) {
subset = false;
break;
}
}
if (subset) {
for (var e = 0; e < this.extendSelectors.length; e++) {
var extendSelector = this.extendSelectors[e];
this.mergeCompoundSelector(obj, extendSelector, objKeys, targetKeys);
}
}
}
else {
obj.descend(this);
}
this.currCompoundSelector = resetCompoundSelector;
return false;
}
multipartselector(obj) {
var resetMultiPartSelector = this.currMultiPartSelector;
this.currMultiPartSelector = obj;
if (obj.getHash() === this.currTargetHash) {
this.appendAllExtendSelectors();
}
else {
obj.descend(this);
}
this.currMultiPartSelector = resetMultiPartSelector;
return false;
}
//--------------------------------------------------
extend(ruleset, targetSelector, extendSelectors) {
var i, j, newSelector, hash;
this.currTarget = targetSelector;
this.currTargetHash = this.currTarget.getHash();
this.newSelectors = [];
this.extendSelectors = extendSelectors;
if (ruleset.selectors) {
if (ruleset.selectors.flatten) {
ruleset.selectors.flatten();
}
this.visit(ruleset.selectors);
}
// now, add any newly created selectors to the ruleset
if (this.newSelectors.length) {
var selectors = ruleset.selectors,
map = {};
if (selectors instanceof SelectorList) {
selectors = selectors.items;
} else {
selectors = [selectors];
}
for (i = 0; i < selectors.length; i++) {
map[selectors[i].getHash()] = true;
}
for (i = 0; i < this.newSelectors.length; i++) {
newSelector = this.newSelectors[i];
hash = newSelector.getHash();
if (!map.hasOwnProperty(hash)) {
selectors.push(newSelector);
map[hash] = true;
}
}
for (i = 0; i < selectors.length; i++) {
for (j = 0; j < selectors.length; j++) {
if (i != j && selectors[i] && selectors[j]) {
var comp = this.compareSelectors(selectors[i], selectors[j]);
if (comp !== 0) {
if (comp > 1) {
selectors[i] = null;
} else {
selectors[j] = null;
}
}
}
}
}
var filteredSelectors = [];
for (var i = 0; i < selectors.length; i++) {
var selector = selectors[i];
if (!!selector) {
filteredSelectors.push(selector);
}
}
ruleset.selectors = new SelectorList(filteredSelectors);
}
for (var c = 0; c < ruleset.children.length; c++) {
this.extend(ruleset.children[c], targetSelector, extendSelectors);
}
}
/**
* returns:
* 1 == sel1 is subset of sel2
* -1 == sel2 is subset of sel1
* 0 == different
*/
compareSelectors(sel1, sel2) {
if (sel1 instanceof MultiPartSelector) {
if (!(sel2 instanceof MultiPartSelector)) {
sel2 = new MultiPartSelector([sel2]);
}
return this.isSuperSelector(sel1, sel2);
} else if (sel2 instanceof MultiPartSelector) {
sel1 = new MultiPartSelector([sel1]);
return this.isSuperSelector(sel1, sel2);
}
if (sel1 instanceof CompoundSelector) {
if (!(sel2 instanceof CompoundSelector)) {
sel2 = new CompoundSelector([sel2]);
}
return this.isSubset(sel1, sel2);
}
else if (sel2 instanceof CompoundSelector) {
sel1 = new CompoundSelector([sel1]);
return this.isSubset(sel1, sel2);
}
var h1 = sel1.getHash(),
h2 = sel2.getHash();
if (h1 == h2) {
return 1;
}
return 0;
}
/**
* returns:
* 1 == this isSuperSelector of other
* -1 == other isSuperSelector of this
* 0 == different
*/
isSuperSelector(sel1, sel2) {
var items = sel1.items,
sItems = sel2.items,
shortList = items,
longList = sItems,
res = 1,
tmpRes;
if (items.length > sItems.length) {
shortList = sItems;
longList = items;
res = -1;
}
for (var i = 0; i < shortList.length; i++) {
tmpRes = this.compareSelectors(shortList[i], longList[i]);
var tmpRes;
if (tmpRes === 0) {
return 0;
} else if (tmpRes !== res) {
return 0;
}
}
return res;
}
/**
* returns:
* 1 == this is subset of other
* -1 == other is subset of this
* 0 == different
*/
isSubset(sel1, sel2) {
var items = sel1.items,
sItems = sel2.items,
longItemMap = {},
shortList = items,
longList = sItems,
item,
res = 1;
if (items.length > sItems.length) {
shortList = sItems;
longList = items;
res = -1;
}
for (var i = 0; i < longList.length; i++) {
item = longList[i];
longItemMap[item.getHash()] = item;
}
for (var i = 0; i < shortList.length; i++) {
item = shortList[i];
if (!longItemMap[item.getHash()]) {
return 0;
}
}
return res;
}
extendRulesets(rulesets, extenders) {
var i, j, k, e,
iLen, jLen, kLen, eLen,
extender, extend, ruleset,
extendMap = {},
extenderArray = [],
keys, token, hash;
iLen = extenders.length;
kLen = rulesets.length;
for (i = 0; i < iLen; i++) {
extender = extenders[i];
jLen = extender.extend.length;
for (j = 0; j < jLen; j++) {
extend = extender.extend[j];
var extendSelectors = extender.selectors;
if (extendSelectors instanceof SelectorList) {
extendSelectors.flatten();
extendSelectors = extendSelectors.items;
} else {
if (extendSelectors.$isFashionMultiPartSelector || extendSelectors.$isFashionCompoundSelector) {
extendSelectors.flatten();
}
extendSelectors = [extendSelectors];
}
hash = extend.getHash();
token = extendMap[hash];
if (!token) {
token = {
selector: extend,
extenders: []
};
extendMap[hash] = token;
extenderArray.push(token);
}
token.extenders.push.apply(token.extenders, extendSelectors);
}
}
eLen = extenderArray.length;
for (k = 0; k < kLen; k++) {
ruleset = rulesets[k];
for (e = 0; e < eLen; e++) {
token = extenderArray[e];
this.extend(ruleset, token.selector, token.extenders);
}
}
}
}
Fashion.apply(ExtendProcessor.prototype, {
currTarget: null,
currTargetHash: null,
newSelectors: null,
extendSelectors: null,
currCompoundSelector: null,
currMultiPartSelector: null
});
module.exports = ExtendProcessor;