* functions.js: (minor) reworking to clean-up initialization of "externally" defined functions (math, blending, default).

* `default` function "front-end" reworked for a bit higher-level control from its "back-end" code (e.g. tree.mixin.eval).
This commit is contained in:
seven-phases-max
2013-12-22 18:25:39 +04:00
parent c18c9de242
commit bdfff94920
2 changed files with 71 additions and 39 deletions

View File

@@ -232,12 +232,6 @@ tree.functions = {
str = str.replace(/%%/g, '%');
return new(tree.Quoted)('"' + str + '"', str);
},
default: function () {
if (this.default.enabled) {
return this.default.value
? tree.True : tree.False;
}
},
unit: function (val, unit) {
if(!(val instanceof tree.Dimension)) {
throw { type: "Argument", message: "the first argument to unit must be a number" + (val instanceof tree.Operation ? ". Have you forgotten parenthesis?" : "") };
@@ -249,7 +243,7 @@ tree.functions = {
},
round: function (n, f) {
var fraction = typeof(f) === "undefined" ? 0 : f.value;
return this._math(function(num) { return num.toFixed(fraction); }, null, n);
return _math(function(num) { return num.toFixed(fraction); }, null, n);
},
pi: function () {
return new(tree.Dimension)(Math.PI);
@@ -267,15 +261,6 @@ tree.functions = {
return new(tree.Dimension)(Math.pow(x.value, y.value), x.unit);
},
_math: function (fn, unit, n) {
if (n instanceof tree.Dimension) {
return new(tree.Dimension)(fn(parseFloat(n.value)), unit == null ? n.unit : unit);
} else if (typeof(n) === 'number') {
return fn(n);
} else {
throw { type: "Argument", message: "argument must be a number" };
}
},
_minmax: function (isMin, args) {
args = Array.prototype.slice.call(args);
switch(args.length) {
@@ -565,22 +550,36 @@ tree._mime = {
}
};
var mathFunctions = [{name:"ceil"}, {name:"floor"}, {name: "sqrt"}, {name:"abs"},
{name:"tan", unit: ""}, {name:"sin", unit: ""}, {name:"cos", unit: ""},
{name:"atan", unit: "rad"}, {name:"asin", unit: "rad"}, {name:"acos", unit: "rad"}],
createMathFunction = function(name, unit) {
return function(n) {
if (unit != null) {
n = n.unify();
}
return this._math(Math[name], unit, n);
};
};
// Math
for(var i = 0; i < mathFunctions.length; i++) {
tree.functions[mathFunctions[i].name] = createMathFunction(mathFunctions[i].name, mathFunctions[i].unit);
var mathFunctions = {
// name, unit
ceil: null,
floor: null,
sqrt: null,
abs: null,
tan: "",
sin: "",
cos: "",
atan: "rad",
asin: "rad",
acos: "rad"
};
function _math(fn, unit, n) {
if (!(n instanceof tree.Dimension)) {
throw { type: "Argument", message: "argument must be a number" };
}
if (unit == null) {
unit = n.unit;
} else {
n = n.unify();
}
return new(tree.Dimension)(fn(parseFloat(n.value)), unit);
}
// ~ End of Math
// Color Blending
// ref: http://www.w3.org/TR/compositing-1
@@ -645,14 +644,48 @@ var colorBlendMode = {
}
};
function colorBlendInit() {
for (var f in colorBlendMode) {
tree.functions[f] = colorBlend.bind(null, colorBlendMode[f]);
}
} colorBlendInit();
// ~ End of Color Blending
tree.defaultFunc = {
eval: function () {
var v = this.value_, e = this.error_;
if (e) {
throw e;
}
if (v != null) {
return v ? tree.True : tree.False;
}
},
value: function (v) {
this.value_ = v;
},
error: function (e) {
this.error_ = e;
},
reset: function () {
this.value_ = this.error_ = null;
}
};
function initFunctions() {
var f, tf = tree.functions;
// math
for (f in mathFunctions) {
tf[f] = _math.bind(null, Math[f], mathFunctions[f]);
}
// color blending
for (f in colorBlendMode) {
tf[f] = colorBlend.bind(null, colorBlendMode[f]);
}
// default
f = tree.defaultFunc;
tf.default = f.eval.bind(f);
} initFunctions();
function hsla(color) {
return tree.functions.hsla(color.h, color.s, color.l, color.a);
}

View File

@@ -20,7 +20,7 @@ tree.mixin.Call.prototype = {
},
eval: function (env) {
var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound, rule;
var candidates = [], candidate, conditionResult = [], defaultFunc = tree.functions.default, defaultUsed = false;
var candidates = [], candidate, conditionResult = [], defaultFunc = tree.defaultFunc, defaultUsed = false;
args = this.arguments && this.arguments.map(function (a) {
return { name: a.name, value: a.value.eval(env) };
@@ -29,7 +29,6 @@ tree.mixin.Call.prototype = {
for (i = 0; i < env.frames.length; i++) {
if ((mixins = env.frames[i].find(this.selector)).length > 0) {
isOneFound = true;
defaultFunc.enabled = true;
// To make `default()` function independent of definition order we have two "subpasses" here.
// At first we evaluate each guard *twice* (with `default() == true` and `default() == false`),
@@ -54,7 +53,7 @@ tree.mixin.Call.prototype = {
if (mixin.matchCondition) {
for (f = 0; f < 2; f++) {
defaultFunc.value = f;
defaultFunc.value(f);
conditionResult[f] = mixin.matchCondition(args, env);
}
if (conditionResult[0] || conditionResult[1]) {
@@ -86,7 +85,7 @@ tree.mixin.Call.prototype = {
}
}
defaultFunc.enabled = false;
defaultFunc.reset();
for (m in candidates) {
candidate = candidates[m];