1 | (function (tree) { |
---|
2 | |
---|
3 | tree.mixin = {}; |
---|
4 | tree.mixin.Call = function (elements, args, index) { |
---|
5 | this.selector = new(tree.Selector)(elements); |
---|
6 | this.arguments = args; |
---|
7 | this.index = index; |
---|
8 | }; |
---|
9 | tree.mixin.Call.prototype = { |
---|
10 | eval: function (env) { |
---|
11 | var mixins, args, rules = [], match = false; |
---|
12 | |
---|
13 | for (var i = 0; i < env.frames.length; i++) { |
---|
14 | if ((mixins = env.frames[i].find(this.selector)).length > 0) { |
---|
15 | args = this.arguments && this.arguments.map(function (a) { return a.eval(env) }); |
---|
16 | for (var m = 0; m < mixins.length; m++) { |
---|
17 | if (mixins[m].match(args, env)) { |
---|
18 | try { |
---|
19 | Array.prototype.push.apply( |
---|
20 | rules, mixins[m].eval(env, this.arguments).rules); |
---|
21 | match = true; |
---|
22 | } catch (e) { |
---|
23 | throw { message: e.message, index: e.index, stack: e.stack, call: this.index }; |
---|
24 | } |
---|
25 | } |
---|
26 | } |
---|
27 | if (match) { |
---|
28 | return rules; |
---|
29 | } else { |
---|
30 | throw { message: 'No matching definition was found for `' + |
---|
31 | this.selector.toCSS().trim() + '(' + |
---|
32 | this.arguments.map(function (a) { |
---|
33 | return a.toCSS(); |
---|
34 | }).join(', ') + ")`", |
---|
35 | index: this.index }; |
---|
36 | } |
---|
37 | } |
---|
38 | } |
---|
39 | throw { message: this.selector.toCSS().trim() + " is undefined", |
---|
40 | index: this.index }; |
---|
41 | } |
---|
42 | }; |
---|
43 | |
---|
44 | tree.mixin.Definition = function (name, params, rules) { |
---|
45 | this.name = name; |
---|
46 | this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])]; |
---|
47 | this.params = params; |
---|
48 | this.arity = params.length; |
---|
49 | this.rules = rules; |
---|
50 | this._lookups = {}; |
---|
51 | this.required = params.reduce(function (count, p) { |
---|
52 | if (!p.name || (p.name && !p.value)) { return count + 1 } |
---|
53 | else { return count } |
---|
54 | }, 0); |
---|
55 | this.parent = tree.Ruleset.prototype; |
---|
56 | this.frames = []; |
---|
57 | }; |
---|
58 | tree.mixin.Definition.prototype = { |
---|
59 | toCSS: function () { return "" }, |
---|
60 | variable: function (name) { return this.parent.variable.call(this, name) }, |
---|
61 | variables: function () { return this.parent.variables.call(this) }, |
---|
62 | find: function () { return this.parent.find.apply(this, arguments) }, |
---|
63 | rulesets: function () { return this.parent.rulesets.apply(this) }, |
---|
64 | |
---|
65 | eval: function (env, args) { |
---|
66 | var frame = new(tree.Ruleset)(null, []), context, _arguments = []; |
---|
67 | |
---|
68 | for (var i = 0, val; i < this.params.length; i++) { |
---|
69 | if (this.params[i].name) { |
---|
70 | if (val = (args && args[i]) || this.params[i].value) { |
---|
71 | frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env))); |
---|
72 | } else { |
---|
73 | throw { message: "wrong number of arguments for " + this.name + |
---|
74 | ' (' + args.length + ' for ' + this.arity + ')' }; |
---|
75 | } |
---|
76 | } |
---|
77 | } |
---|
78 | for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) { |
---|
79 | _arguments.push(args[i] || this.params[i].value); |
---|
80 | } |
---|
81 | frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env))); |
---|
82 | |
---|
83 | return new(tree.Ruleset)(null, this.rules.slice(0)).eval({ |
---|
84 | frames: [this, frame].concat(this.frames, env.frames) |
---|
85 | }); |
---|
86 | }, |
---|
87 | match: function (args, env) { |
---|
88 | var argsLength = (args && args.length) || 0, len; |
---|
89 | |
---|
90 | if (argsLength < this.required) { return false } |
---|
91 | if ((this.required > 0) && (argsLength > this.params.length)) { return false } |
---|
92 | |
---|
93 | len = Math.min(argsLength, this.arity); |
---|
94 | |
---|
95 | for (var i = 0; i < len; i++) { |
---|
96 | if (!this.params[i].name) { |
---|
97 | if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) { |
---|
98 | return false; |
---|
99 | } |
---|
100 | } |
---|
101 | } |
---|
102 | return true; |
---|
103 | } |
---|
104 | }; |
---|
105 | |
---|
106 | })(require('less/tree')); |
---|