1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | var Node = require('./node')
|
13 | , nodes = require('./');
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 | var FACTOR_TABLE = {
|
20 | 'mm': {val: 1, label: 'mm'},
|
21 | 'cm': {val: 10, label: 'mm'},
|
22 | 'in': {val: 25.4, label: 'mm'},
|
23 | 'pt': {val: 25.4/72, label: 'mm'},
|
24 | 'ms': {val: 1, label: 'ms'},
|
25 | 's': {val: 1000, label: 'ms'},
|
26 | 'Hz': {val: 1, label: 'Hz'},
|
27 | 'kHz': {val: 1000, label: 'Hz'}
|
28 | };
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 | var Unit = module.exports = function Unit(val, type){
|
40 | Node.call(this);
|
41 | this.val = val;
|
42 | this.type = type;
|
43 | };
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 | Unit.prototype.__proto__ = Node.prototype;
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 | Unit.prototype.toBoolean = function(){
|
59 | return nodes.Boolean(this.type
|
60 | ? true
|
61 | : this.val);
|
62 | };
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 | Unit.prototype.toString = function(){
|
72 | return this.val + (this.type || '');
|
73 | };
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 | Unit.prototype.clone = function(){
|
83 | var clone = new Unit(this.val, this.type);
|
84 | clone.lineno = this.lineno;
|
85 | clone.column = this.column;
|
86 | clone.filename = this.filename;
|
87 | return clone;
|
88 | };
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | Unit.prototype.toJSON = function(){
|
98 | return {
|
99 | __type: 'Unit',
|
100 | val: this.val,
|
101 | type: this.type,
|
102 | lineno: this.lineno,
|
103 | column: this.column,
|
104 | filename: this.filename
|
105 | };
|
106 | };
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 | Unit.prototype.operate = function(op, right){
|
118 | var type = this.type || right.first.type;
|
119 |
|
120 |
|
121 | if ('rgba' == right.nodeName || 'hsla' == right.nodeName) {
|
122 | return right.operate(op, this);
|
123 | }
|
124 |
|
125 |
|
126 | if (this.shouldCoerce(op)) {
|
127 | right = right.first;
|
128 |
|
129 | if ('%' != this.type && ('-' == op || '+' == op) && '%' == right.type) {
|
130 | right = new Unit(this.val * (right.val / 100), '%');
|
131 | } else {
|
132 | right = this.coerce(right);
|
133 | }
|
134 |
|
135 | switch (op) {
|
136 | case '-':
|
137 | return new Unit(this.val - right.val, type);
|
138 | case '+':
|
139 |
|
140 | type = type || (right.type == '%' && right.type);
|
141 | return new Unit(this.val + right.val, type);
|
142 | case '/':
|
143 | return new Unit(this.val / right.val, type);
|
144 | case '*':
|
145 | return new Unit(this.val * right.val, type);
|
146 | case '%':
|
147 | return new Unit(this.val % right.val, type);
|
148 | case '**':
|
149 | return new Unit(Math.pow(this.val, right.val), type);
|
150 | case '..':
|
151 | case '...':
|
152 | var start = this.val
|
153 | , end = right.val
|
154 | , expr = new nodes.Expression
|
155 | , inclusive = '..' == op;
|
156 | if (start < end) {
|
157 | do {
|
158 | expr.push(new nodes.Unit(start));
|
159 | } while (inclusive ? ++start <= end : ++start < end);
|
160 | } else {
|
161 | do {
|
162 | expr.push(new nodes.Unit(start));
|
163 | } while (inclusive ? --start >= end : --start > end);
|
164 | }
|
165 | return expr;
|
166 | }
|
167 | }
|
168 |
|
169 | return Node.prototype.operate.call(this, op, right);
|
170 | };
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 | Unit.prototype.coerce = function(other){
|
193 | if ('unit' == other.nodeName) {
|
194 | var a = this
|
195 | , b = other
|
196 | , factorA = FACTOR_TABLE[a.type]
|
197 | , factorB = FACTOR_TABLE[b.type];
|
198 |
|
199 | if (factorA && factorB && (factorA.label == factorB.label)) {
|
200 | var bVal = b.val * (factorB.val / factorA.val);
|
201 | return new nodes.Unit(bVal, a.type);
|
202 | } else {
|
203 | return new nodes.Unit(b.val, a.type);
|
204 | }
|
205 | } else if ('string' == other.nodeName) {
|
206 |
|
207 | if ('%' == other.val) return new nodes.Unit(0, '%');
|
208 | var val = parseFloat(other.val);
|
209 | if (isNaN(val)) Node.prototype.coerce.call(this, other);
|
210 | return new nodes.Unit(val);
|
211 | } else {
|
212 | return Node.prototype.coerce.call(this, other);
|
213 | }
|
214 | };
|