UNPKG

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