You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
214 lines
4.4 KiB
214 lines
4.4 KiB
|
|
/*! |
|
* Stylus - Unit |
|
* Copyright (c) Automattic <developer.wordpress.com> |
|
* MIT Licensed |
|
*/ |
|
|
|
/** |
|
* Module dependencies. |
|
*/ |
|
|
|
var Node = require('./node') |
|
, nodes = require('./'); |
|
|
|
/** |
|
* Unit conversion table. |
|
*/ |
|
|
|
var FACTOR_TABLE = { |
|
'mm': {val: 1, label: 'mm'}, |
|
'cm': {val: 10, label: 'mm'}, |
|
'in': {val: 25.4, label: 'mm'}, |
|
'pt': {val: 25.4/72, label: 'mm'}, |
|
'ms': {val: 1, label: 'ms'}, |
|
's': {val: 1000, label: 'ms'}, |
|
'Hz': {val: 1, label: 'Hz'}, |
|
'kHz': {val: 1000, label: 'Hz'} |
|
}; |
|
|
|
/** |
|
* Initialize a new `Unit` with the given `val` and unit `type` |
|
* such as "px", "pt", "in", etc. |
|
* |
|
* @param {String} val |
|
* @param {String} type |
|
* @api public |
|
*/ |
|
|
|
var Unit = module.exports = function Unit(val, type){ |
|
Node.call(this); |
|
this.val = val; |
|
this.type = type; |
|
}; |
|
|
|
/** |
|
* Inherit from `Node.prototype`. |
|
*/ |
|
|
|
Unit.prototype.__proto__ = Node.prototype; |
|
|
|
/** |
|
* Return Boolean based on the unit value. |
|
* |
|
* @return {Boolean} |
|
* @api public |
|
*/ |
|
|
|
Unit.prototype.toBoolean = function(){ |
|
return nodes.Boolean(this.type |
|
? true |
|
: this.val); |
|
}; |
|
|
|
/** |
|
* Return unit string. |
|
* |
|
* @return {String} |
|
* @api public |
|
*/ |
|
|
|
Unit.prototype.toString = function(){ |
|
return this.val + (this.type || ''); |
|
}; |
|
|
|
/** |
|
* Return a clone of this node. |
|
* |
|
* @return {Node} |
|
* @api public |
|
*/ |
|
|
|
Unit.prototype.clone = function(){ |
|
var clone = new Unit(this.val, this.type); |
|
clone.lineno = this.lineno; |
|
clone.column = this.column; |
|
clone.filename = this.filename; |
|
return clone; |
|
}; |
|
|
|
/** |
|
* Return a JSON representation of this node. |
|
* |
|
* @return {Object} |
|
* @api public |
|
*/ |
|
|
|
Unit.prototype.toJSON = function(){ |
|
return { |
|
__type: 'Unit', |
|
val: this.val, |
|
type: this.type, |
|
lineno: this.lineno, |
|
column: this.column, |
|
filename: this.filename |
|
}; |
|
}; |
|
|
|
/** |
|
* Operate on `right` with the given `op`. |
|
* |
|
* @param {String} op |
|
* @param {Node} right |
|
* @return {Node} |
|
* @api public |
|
*/ |
|
|
|
Unit.prototype.operate = function(op, right){ |
|
var type = this.type || right.first.type; |
|
|
|
// swap color |
|
if ('rgba' == right.nodeName || 'hsla' == right.nodeName) { |
|
return right.operate(op, this); |
|
} |
|
|
|
// operate |
|
if (this.shouldCoerce(op)) { |
|
right = right.first; |
|
// percentages |
|
if ('%' != this.type && ('-' == op || '+' == op) && '%' == right.type) { |
|
right = new Unit(this.val * (right.val / 100), '%'); |
|
} else { |
|
right = this.coerce(right); |
|
} |
|
|
|
switch (op) { |
|
case '-': |
|
return new Unit(this.val - right.val, type); |
|
case '+': |
|
// keyframes interpolation |
|
type = type || (right.type == '%' && right.type); |
|
return new Unit(this.val + right.val, type); |
|
case '/': |
|
return new Unit(this.val / right.val, type); |
|
case '*': |
|
return new Unit(this.val * right.val, type); |
|
case '%': |
|
return new Unit(this.val % right.val, type); |
|
case '**': |
|
return new Unit(Math.pow(this.val, right.val), type); |
|
case '..': |
|
case '...': |
|
var start = this.val |
|
, end = right.val |
|
, expr = new nodes.Expression |
|
, inclusive = '..' == op; |
|
if (start < end) { |
|
do { |
|
expr.push(new nodes.Unit(start)); |
|
} while (inclusive ? ++start <= end : ++start < end); |
|
} else { |
|
do { |
|
expr.push(new nodes.Unit(start)); |
|
} while (inclusive ? --start >= end : --start > end); |
|
} |
|
return expr; |
|
} |
|
} |
|
|
|
return Node.prototype.operate.call(this, op, right); |
|
}; |
|
|
|
/** |
|
* Coerce `other` unit to the same type as `this` unit. |
|
* |
|
* Supports: |
|
* |
|
* mm -> cm | in |
|
* cm -> mm | in |
|
* in -> mm | cm |
|
* |
|
* ms -> s |
|
* s -> ms |
|
* |
|
* Hz -> kHz |
|
* kHz -> Hz |
|
* |
|
* @param {Unit} other |
|
* @return {Unit} |
|
* @api public |
|
*/ |
|
|
|
Unit.prototype.coerce = function(other){ |
|
if ('unit' == other.nodeName) { |
|
var a = this |
|
, b = other |
|
, factorA = FACTOR_TABLE[a.type] |
|
, factorB = FACTOR_TABLE[b.type]; |
|
|
|
if (factorA && factorB && (factorA.label == factorB.label)) { |
|
var bVal = b.val * (factorB.val / factorA.val); |
|
return new nodes.Unit(bVal, a.type); |
|
} else { |
|
return new nodes.Unit(b.val, a.type); |
|
} |
|
} else if ('string' == other.nodeName) { |
|
// keyframes interpolation |
|
if ('%' == other.val) return new nodes.Unit(0, '%'); |
|
var val = parseFloat(other.val); |
|
if (isNaN(val)) Node.prototype.coerce.call(this, other); |
|
return new nodes.Unit(val); |
|
} else { |
|
return Node.prototype.coerce.call(this, other); |
|
} |
|
};
|
|
|