diff --git a/lib/less/tree/mixin.js b/lib/less/tree/mixin.js index 94f48efa..078f30e7 100644 --- a/lib/less/tree/mixin.js +++ b/lib/less/tree/mixin.js @@ -19,16 +19,45 @@ tree.mixin.Call.prototype = { } }, eval: function (env) { - var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound, rule, - candidates = [], candidate, conditionResult = [], defaultFunc = tree.defaultFunc, - defaultResult, defNone = 0, defTrue = 1, defFalse = 2, count, originalRuleset; + var mixins, mixin, mixinPath, args, rules = [], match = false, i, m, f, isRecursive, isOneFound, rule, + candidates = [], candidate, conditionResult = [], defaultFunc = tree.defaultFunc, + defaultResult, defFalseEitherCase=-1, defNone = 0, defTrue = 1, defFalse = 2, count, originalRuleset, noArgumentsFilter; + + function calcDefGroup(mixin, mixinPath) { + var p, namespace; + + for (f = 0; f < 2; f++) { + conditionResult[f] = true; + defaultFunc.value(f); + for(p = 0; p < mixinPath.length && conditionResult[f]; p++) { + namespace = mixinPath[p]; + if (namespace.matchCondition) { + conditionResult[f] = conditionResult[f] && namespace.matchCondition(null, env); + } + } + if (mixin.matchCondition) { + conditionResult[f] = conditionResult[f] && mixin.matchCondition(args, env); + } + } + if (conditionResult[0] || conditionResult[1]) { + if (conditionResult[0] != conditionResult[1]) { + return conditionResult[1] ? + defTrue : defFalse; + } + + return defNone; + } + return defFalseEitherCase; + } args = this.arguments && this.arguments.map(function (a) { return { name: a.name, value: a.value.eval(env) }; }); + noArgumentsFilter = function(rule) {return rule.matchArgs(null, env);}; + for (i = 0; i < env.frames.length; i++) { - if ((mixins = env.frames[i].find(this.selector)).length > 0) { + if ((mixins = env.frames[i].find(this.selector, null, noArgumentsFilter)).length > 0) { isOneFound = true; // To make `default()` function independent of definition order we have two "subpasses" here. @@ -37,7 +66,8 @@ tree.mixin.Call.prototype = { // we make a final decision. for (m = 0; m < mixins.length; m++) { - mixin = mixins[m]; + mixin = mixins[m].rule; + mixinPath = mixins[m].path; isRecursive = false; for(f = 0; f < env.frames.length; f++) { if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) { @@ -48,28 +78,14 @@ tree.mixin.Call.prototype = { if (isRecursive) { continue; } - - if (mixin.matchArgs(args, env)) { - candidate = {mixin: mixin, group: defNone}; - - if (mixin.matchCondition) { - for (f = 0; f < 2; f++) { - defaultFunc.value(f); - conditionResult[f] = mixin.matchCondition(args, env); - } - if (conditionResult[0] || conditionResult[1]) { - if (conditionResult[0] != conditionResult[1]) { - candidate.group = conditionResult[1] ? - defTrue : defFalse; - } - candidates.push(candidate); - } + if (mixin.matchArgs(args, env)) { + candidate = {mixin: mixin, group: calcDefGroup(mixin, mixinPath)}; + + if (candidate.group!==defFalseEitherCase) { + candidates.push(candidate); } - else { - candidates.push(candidate); - } - + match = true; } } @@ -133,6 +149,7 @@ tree.mixin.Call.prototype = { message: this.selector.toCSS().trim() + " is undefined", index: this.index, filename: this.currentFileInfo.filename }; } + }, format: function (args) { return this.selector.toCSS().trim() + '(' + diff --git a/lib/less/tree/ruleset.js b/lib/less/tree/ruleset.js index 17c0ad1a..f5cdf1f5 100644 --- a/lib/less/tree/ruleset.js +++ b/lib/less/tree/ruleset.js @@ -238,9 +238,9 @@ tree.Ruleset.prototype = { var rules = this.rules; if (rules) { rules.unshift(rule); } else { this.rules = [ rule ]; } }, - find: function (selector, self) { + find: function (selector, self, filter) { self = self || this; - var rules = [], match, + var rules = [], match, foundMixins, key = selector.toCSS(); if (key in this._lookups) { return this._lookups[key]; } @@ -251,10 +251,15 @@ tree.Ruleset.prototype = { match = selector.match(rule.selectors[j]); if (match) { if (selector.elements.length > match) { - Array.prototype.push.apply(rules, rule.find( - new(tree.Selector)(selector.elements.slice(match)), self)); + if (!filter || filter(rule)) { + foundMixins = rule.find(new(tree.Selector)(selector.elements.slice(match)), self, filter); + for (var i = 0; i < foundMixins.length; ++i) { + foundMixins[i].path.push(rule); + } + Array.prototype.push.apply(rules, foundMixins); + } } else { - rules.push(rule); + rules.push({ rule: rule, path: []}); } break; } diff --git a/test/css/mixins-guards.css b/test/css/mixins-guards.css index 59b6f932..b918cda6 100644 --- a/test/css/mixins-guards.css +++ b/test/css/mixins-guards.css @@ -91,3 +91,11 @@ .mixin-generated-class { a: 1; } +#guarded-caller { + guarded: namespace; + silent: namespace; + guarded: with default; +} +#guarded-deeper { + should: match 1; +} diff --git a/test/less/mixins-guards.less b/test/less/mixins-guards.less index 5aec2e51..33a35830 100644 --- a/test/less/mixins-guards.less +++ b/test/less/mixins-guards.less @@ -171,3 +171,58 @@ } #ns > .mixin-for-root-usage(1); + +@namespaceGuard: 1; +#guarded when (@namespaceGuard>0) { + #deeper { + .mixin() { + guarded: namespace; + } + } +} +#guarded() when (@namespaceGuard>0) { + #deeper { + .mixin() { + silent: namespace; + } + } +} +#guarded(@variable) when (@namespaceGuard>0) { + #deeper { + .mixin() { + should: not match because namespace argument; + } + } +} +#guarded(@variable: default) when (@namespaceGuard>0) { + #deeper { + .mixin() { + guarded: with default; + } + } +} +#guarded when (@namespaceGuard<0) { + #deeper { + .mixin() { + should: not match because namespace guard; + } + } +} +#guarded-caller { + #guarded > #deeper > .mixin(); +} +#top { + #deeper when (@namespaceGuard<0) { + .mixin(@a) { + should: not match because namespace guard; + } + } + #deeper() when (@namespaceGuard>0) { + .mixin(@a) { + should: match @a; + } + } +} +#guarded-deeper { + #top > #deeper > .mixin(1); +} \ No newline at end of file