UNPKG

4.53 kBJavaScriptView Raw
1
2/*!
3 * Stylus - Unit
4 * Copyright (c) Automattic <developer.wordpress.com>
5 * MIT Licensed
6 */
7
8/**
9 * Module dependencies.
10 */
11
12var Node = require('./node')
13 , nodes = require('./');
14
15/**
16 * Unit conversion table.
17 */
18
19var 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 * Initialize a new `Unit` with the given `val` and unit `type`
32 * such as "px", "pt", "in", etc.
33 *
34 * @param {String} val
35 * @param {String} type
36 * @api public
37 */
38
39var Unit = module.exports = function Unit(val, type){
40 Node.call(this);
41 this.val = val;
42 this.type = type;
43};
44
45/**
46 * Inherit from `Node.prototype`.
47 */
48
49Unit.prototype.__proto__ = Node.prototype;
50
51/**
52 * Return Boolean based on the unit value.
53 *
54 * @return {Boolean}
55 * @api public
56 */
57
58Unit.prototype.toBoolean = function(){
59 return nodes.Boolean(this.type
60 ? true
61 : this.val);
62};
63
64/**
65 * Return unit string.
66 *
67 * @return {String}
68 * @api public
69 */
70
71Unit.prototype.toString = function(){
72 return this.val + (this.type || '');
73};
74
75/**
76 * Return a clone of this node.
77 *
78 * @return {Node}
79 * @api public
80 */
81
82Unit.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 * Return a JSON representation of this node.
92 *
93 * @return {Object}
94 * @api public
95 */
96
97Unit.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 * Operate on `right` with the given `op`.
110 *
111 * @param {String} op
112 * @param {Node} right
113 * @return {Node}
114 * @api public
115 */
116
117Unit.prototype.operate = function(op, right){
118 var type = this.type || right.first.type;
119
120 // swap color
121 if ('rgba' == right.nodeName || 'hsla' == right.nodeName) {
122 return right.operate(op, this);
123 }
124
125 // operate
126 if (this.shouldCoerce(op)) {
127 right = right.first;
128 // percentages
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 // keyframes interpolation
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 * Coerce `other` unit to the same type as `this` unit.
174 *
175 * Supports:
176 *
177 * mm -> cm | in
178 * cm -> mm | in
179 * in -> mm | cm
180 *
181 * ms -> s
182 * s -> ms
183 *
184 * Hz -> kHz
185 * kHz -> Hz
186 *
187 * @param {Unit} other
188 * @return {Unit}
189 * @api public
190 */
191
192Unit.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 // keyframes interpolation
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};