From 9cec4aa0124cd583a0fa569fc885e81200de8fbe Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Tue, 25 Jan 2022 15:32:00 +0100 Subject: [PATCH] Add matchedOnly option to CSS code generator. --- src/code_manager/model/CssGenerator.js | 74 ++++++++++++++++++++------ 1 file changed, 57 insertions(+), 17 deletions(-) diff --git a/src/code_manager/model/CssGenerator.js b/src/code_manager/model/CssGenerator.js index b801488e3..28b89e615 100644 --- a/src/code_manager/model/CssGenerator.js +++ b/src/code_manager/model/CssGenerator.js @@ -1,5 +1,6 @@ import Backbone from 'backbone'; import { bindAll, isUndefined, each } from 'underscore'; +import { hasWin } from 'utils/mixins'; const maxValue = Number.MAX_VALUE; @@ -54,16 +55,17 @@ export default Backbone.Model.extend({ this.model = model; const codeJson = []; let code = model ? this.buildFromModel(model, opts) : ''; - const clearStyles = - isUndefined(opts.clearStyles) && em - ? em.getConfig('clearStyles') - : opts.clearStyles; + const clearStyles = isUndefined(opts.clearStyles) && em ? em.getConfig('clearStyles') : opts.clearStyles; if (cssc) { - const rules = opts.rules || cssc.getAll(); + let rules = opts.rules || cssc.getAll(); const atRules = {}; const dump = []; + if (opts.matchedOnly && model && hasWin()) { + rules = this.matchedRules(model, rules); + } + rules.forEach(rule => { const atRule = rule.getAtRule(); @@ -130,11 +132,7 @@ export default Backbone.Model.extend({ // This will not render a rule if there is no its component rule.get('selectors').each(selector => { const name = selector.getFullName(); - if ( - this.compCls.indexOf(name) >= 0 || - this.ids.indexOf(name) >= 0 || - opts.keepUnusedStyles - ) { + if (this.compCls.indexOf(name) >= 0 || this.ids.indexOf(name) >= 0 || opts.keepUnusedStyles) { found = 1; } }); @@ -149,6 +147,39 @@ export default Backbone.Model.extend({ return result; }, + /** + * Get matched rules of a component + * @param {Component} component + * @param {Array} rules + * @returns {Array} + */ + matchedRules(component, rules) { + const el = component.getEl(); + let result = []; + + rules.forEach(rule => { + try { + if ( + rule + .selectorsToString() + .split(',') + .some(selector => el.matches(this.__cleanSelector(selector))) + ) { + result.push(rule); + } + } catch (err) {} + }); + + component.components().forEach(component => { + result = result.concat(this.matchedRules(component, rules)); + }); + + // Remove duplicates + result = result.filter((rule, i) => result.indexOf(rule) === i); + + return result; + }, + /** * Get the numeric length of the media query string * @param {String} mediaQuery Media query string @@ -170,9 +201,7 @@ export default Backbone.Model.extend({ const itemsArr = []; each(items, (value, key) => itemsArr.push({ key, value })); return itemsArr.sort((a, b) => { - const isMobFirst = [a.key, b.key].every( - mquery => mquery.indexOf('min-width') !== -1 - ); + const isMobFirst = [a.key, b.key].every(mquery => mquery.indexOf('min-width') !== -1); const left = isMobFirst ? a.key : b.key; const right = isMobFirst ? b.key : a.key; return this.getQueryLength(left) - this.getQueryLength(right); @@ -181,11 +210,22 @@ export default Backbone.Model.extend({ sortRules(a, b) { const getKey = rule => rule.get('mediaText'); - const isMobFirst = [getKey(a), getKey(b)].every( - q => q.indexOf('min-width') !== -1 - ); + const isMobFirst = [getKey(a), getKey(b)].every(q => q.indexOf('min-width') !== -1); const left = isMobFirst ? getKey(a) : getKey(b); const right = isMobFirst ? getKey(b) : getKey(a); return this.getQueryLength(left) - this.getQueryLength(right); - } + }, + + /** + * Return passed selector without states + * @param {String} selector + * @returns {String} + * @private + */ + __cleanSelector(selector) { + return selector + .split(' ') + .map(item => item.split(':')[0]) + .join(' '); + }, });