diff --git a/lib/less/functions/color-blending.js b/lib/less/functions/color-blending.js index c24b549a..ed2fa071 100644 --- a/lib/less/functions/color-blending.js +++ b/lib/less/functions/color-blending.js @@ -1,74 +1,74 @@ -module.exports = function(functions, tree) { +var Color = require("../tree/color.js"), + functionRegistry = require("./function-registry.js"); - // Color Blending - // ref: http://www.w3.org/TR/compositing-1 +// Color Blending +// ref: http://www.w3.org/TR/compositing-1 - function colorBlend(mode, color1, color2) { - var ab = color1.alpha, cb, // backdrop - as = color2.alpha, cs, // source - ar, cr, r = []; // result +function colorBlend(mode, color1, color2) { + var ab = color1.alpha, cb, // backdrop + as = color2.alpha, cs, // source + ar, cr, r = []; // result - ar = as + ab * (1 - as); - for (var i = 0; i < 3; i++) { - cb = color1.rgb[i] / 255; - cs = color2.rgb[i] / 255; - cr = mode(cb, cs); - if (ar) { - cr = (as * cs + ab * (cb - - as * (cb + cs - cr))) / ar; - } - r[i] = cr * 255; + ar = as + ab * (1 - as); + for (var i = 0; i < 3; i++) { + cb = color1.rgb[i] / 255; + cs = color2.rgb[i] / 255; + cr = mode(cb, cs); + if (ar) { + cr = (as * cs + ab * (cb - + as * (cb + cs - cr))) / ar; } - - return new(tree.Color)(r, ar); + r[i] = cr * 255; } - var colorBlendModeFunctions = { - multiply: function(cb, cs) { - return cb * cs; - }, - screen: function(cb, cs) { - return cb + cs - cb * cs; - }, - overlay: function(cb, cs) { - cb *= 2; - return (cb <= 1) - ? colorBlendModeFunctions.multiply(cb, cs) - : colorBlendModeFunctions.screen(cb - 1, cs); - }, - softlight: function(cb, cs) { - var d = 1, e = cb; - if (cs > 0.5) { - e = 1; - d = (cb > 0.25) ? Math.sqrt(cb) - : ((16 * cb - 12) * cb + 4) * cb; - } - return cb - (1 - 2 * cs) * e * (d - cb); - }, - hardlight: function(cb, cs) { - return colorBlendModeFunctions.overlay(cs, cb); - }, - difference: function(cb, cs) { - return Math.abs(cb - cs); - }, - exclusion: function(cb, cs) { - return cb + cs - 2 * cb * cs; - }, + return new(Color)(r, ar); +} - // non-w3c functions: - average: function(cb, cs) { - return (cb + cs) / 2; - }, - negation: function(cb, cs) { - return 1 - Math.abs(cb + cs - 1); +var colorBlendModeFunctions = { + multiply: function(cb, cs) { + return cb * cs; + }, + screen: function(cb, cs) { + return cb + cs - cb * cs; + }, + overlay: function(cb, cs) { + cb *= 2; + return (cb <= 1) + ? colorBlendModeFunctions.multiply(cb, cs) + : colorBlendModeFunctions.screen(cb - 1, cs); + }, + softlight: function(cb, cs) { + var d = 1, e = cb; + if (cs > 0.5) { + e = 1; + d = (cb > 0.25) ? Math.sqrt(cb) + : ((16 * cb - 12) * cb + 4) * cb; } - }; + return cb - (1 - 2 * cs) * e * (d - cb); + }, + hardlight: function(cb, cs) { + return colorBlendModeFunctions.overlay(cs, cb); + }, + difference: function(cb, cs) { + return Math.abs(cb - cs); + }, + exclusion: function(cb, cs) { + return cb + cs - 2 * cb * cs; + }, - for (var f in colorBlendModeFunctions) { - if (colorBlendModeFunctions.hasOwnProperty(f)) { - colorBlend[f] = colorBlend.bind(null, colorBlendModeFunctions[f]); - } + // non-w3c functions: + average: function(cb, cs) { + return (cb + cs) / 2; + }, + negation: function(cb, cs) { + return 1 - Math.abs(cb + cs - 1); } - - functions.functionRegistry.addMultiple(colorBlend); }; + +for (var f in colorBlendModeFunctions) { + if (colorBlendModeFunctions.hasOwnProperty(f)) { + colorBlend[f] = colorBlend.bind(null, colorBlendModeFunctions[f]); + } +} + +functionRegistry.addMultiple(colorBlend); diff --git a/lib/less/functions/color.js b/lib/less/functions/color.js index 1b493bce..c08aee8c 100644 --- a/lib/less/functions/color.js +++ b/lib/less/functions/color.js @@ -1,272 +1,277 @@ -module.exports = function(functions, tree) { - function clamp(val) { - return Math.min(1, Math.max(0, val)); +var Dimension = require("../tree/dimension.js"), + Color = require("../tree/color.js"), + Quoted = require("../tree/quoted.js"), + Anonymous = require("../tree/anonymous.js"), + functionRegistry = require("./function-registry.js"), + colorFunctions; + +function clamp(val) { + return Math.min(1, Math.max(0, val)); +} +function hsla(color) { + return colorFunctions.hsla(color.h, color.s, color.l, color.a); +} +function number(n) { + if (n instanceof Dimension) { + return parseFloat(n.unit.is('%') ? n.value / 100 : n.value); + } else if (typeof(n) === 'number') { + return n; + } else { + throw { + error: "RuntimeError", + message: "color functions take numbers as parameters" + }; } - function hsla(color) { - return colorFunctions.hsla(color.h, color.s, color.l, color.a); +} +function scaled(n, size) { + if (n instanceof Dimension && n.unit.is('%')) { + return parseFloat(n.value * size / 100); + } else { + return number(n); } - function number(n) { - if (n instanceof tree.Dimension) { - return parseFloat(n.unit.is('%') ? n.value / 100 : n.value); - } else if (typeof(n) === 'number') { - return n; +} +colorFunctions = { + rgb: function (r, g, b) { + return colorFunctions.rgba(r, g, b, 1.0); + }, + rgba: function (r, g, b, a) { + var rgb = [r, g, b].map(function (c) { return scaled(c, 255); }); + a = number(a); + return new(Color)(rgb, a); + }, + hsl: function (h, s, l) { + return colorFunctions.hsla(h, s, l, 1.0); + }, + hsla: function (h, s, l, a) { + function hue(h) { + h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); + if (h * 6 < 1) { return m1 + (m2 - m1) * h * 6; } + else if (h * 2 < 1) { return m2; } + else if (h * 3 < 2) { return m1 + (m2 - m1) * (2/3 - h) * 6; } + else { return m1; } + } + + h = (number(h) % 360) / 360; + s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a)); + + var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; + var m1 = l * 2 - m2; + + return colorFunctions.rgba(hue(h + 1/3) * 255, + hue(h) * 255, + hue(h - 1/3) * 255, + a); + }, + + hsv: function(h, s, v) { + return colorFunctions.hsva(h, s, v, 1.0); + }, + + hsva: function(h, s, v, a) { + h = ((number(h) % 360) / 360) * 360; + s = number(s); v = number(v); a = number(a); + + var i, f; + i = Math.floor((h / 60) % 6); + f = (h / 60) - i; + + var vs = [v, + v * (1 - s), + v * (1 - f * s), + v * (1 - (1 - f) * s)]; + var perm = [[0, 3, 1], + [2, 0, 1], + [1, 0, 3], + [1, 2, 0], + [3, 1, 0], + [0, 1, 2]]; + + return colorFunctions.rgba(vs[perm[i][0]] * 255, + vs[perm[i][1]] * 255, + vs[perm[i][2]] * 255, + a); + }, + + hue: function (color) { + return new(Dimension)(color.toHSL().h); + }, + saturation: function (color) { + return new(Dimension)(color.toHSL().s * 100, '%'); + }, + lightness: function (color) { + return new(Dimension)(color.toHSL().l * 100, '%'); + }, + hsvhue: function(color) { + return new(Dimension)(color.toHSV().h); + }, + hsvsaturation: function (color) { + return new(Dimension)(color.toHSV().s * 100, '%'); + }, + hsvvalue: function (color) { + return new(Dimension)(color.toHSV().v * 100, '%'); + }, + red: function (color) { + return new(Dimension)(color.rgb[0]); + }, + green: function (color) { + return new(Dimension)(color.rgb[1]); + }, + blue: function (color) { + return new(Dimension)(color.rgb[2]); + }, + alpha: function (color) { + return new(Dimension)(color.toHSL().a); + }, + luma: function (color) { + return new(Dimension)(color.luma() * color.alpha * 100, '%'); + }, + luminance: function (color) { + var luminance = + (0.2126 * color.rgb[0] / 255) + + (0.7152 * color.rgb[1] / 255) + + (0.0722 * color.rgb[2] / 255); + + return new(Dimension)(luminance * color.alpha * 100, '%'); + }, + saturate: function (color, amount) { + // filter: saturate(3.2); + // should be kept as is, so check for color + if (!color.rgb) { + return null; + } + var hsl = color.toHSL(); + + hsl.s += amount.value / 100; + hsl.s = clamp(hsl.s); + return hsla(hsl); + }, + desaturate: function (color, amount) { + var hsl = color.toHSL(); + + hsl.s -= amount.value / 100; + hsl.s = clamp(hsl.s); + return hsla(hsl); + }, + lighten: function (color, amount) { + var hsl = color.toHSL(); + + hsl.l += amount.value / 100; + hsl.l = clamp(hsl.l); + return hsla(hsl); + }, + darken: function (color, amount) { + var hsl = color.toHSL(); + + hsl.l -= amount.value / 100; + hsl.l = clamp(hsl.l); + return hsla(hsl); + }, + fadein: function (color, amount) { + var hsl = color.toHSL(); + + hsl.a += amount.value / 100; + hsl.a = clamp(hsl.a); + return hsla(hsl); + }, + fadeout: function (color, amount) { + var hsl = color.toHSL(); + + hsl.a -= amount.value / 100; + hsl.a = clamp(hsl.a); + return hsla(hsl); + }, + fade: function (color, amount) { + var hsl = color.toHSL(); + + hsl.a = amount.value / 100; + hsl.a = clamp(hsl.a); + return hsla(hsl); + }, + spin: function (color, amount) { + var hsl = color.toHSL(); + var hue = (hsl.h + amount.value) % 360; + + hsl.h = hue < 0 ? 360 + hue : hue; + + return hsla(hsl); + }, + // + // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein + // http://sass-lang.com + // + mix: function (color1, color2, weight) { + if (!weight) { + weight = new(Dimension)(50); + } + var p = weight.value / 100.0; + var w = p * 2 - 1; + var a = color1.toHSL().a - color2.toHSL().a; + + var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; + var w2 = 1 - w1; + + var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, + color1.rgb[1] * w1 + color2.rgb[1] * w2, + color1.rgb[2] * w1 + color2.rgb[2] * w2]; + + var alpha = color1.alpha * p + color2.alpha * (1 - p); + + return new(Color)(rgb, alpha); + }, + greyscale: function (color) { + return colorFunctions.desaturate(color, new(Dimension)(100)); + }, + contrast: function (color, dark, light, threshold) { + // filter: contrast(3.2); + // should be kept as is, so check for color + if (!color.rgb) { + return null; + } + if (typeof light === 'undefined') { + light = colorFunctions.rgba(255, 255, 255, 1.0); + } + if (typeof dark === 'undefined') { + dark = colorFunctions.rgba(0, 0, 0, 1.0); + } + //Figure out which is actually light and dark! + if (dark.luma() > light.luma()) { + var t = light; + light = dark; + dark = t; + } + if (typeof threshold === 'undefined') { + threshold = 0.43; } else { - throw { - error: "RuntimeError", - message: "color functions take numbers as parameters" - }; + threshold = number(threshold); } - } - function scaled(n, size) { - if (n instanceof tree.Dimension && n.unit.is('%')) { - return parseFloat(n.value * size / 100); + if (color.luma() < threshold) { + return light; } else { - return number(n); + return dark; } + }, + argb: function (color) { + return new(Anonymous)(color.toARGB()); + }, + color: function(c) { + if ((c instanceof Quoted) && + (/^#([a-f0-9]{6}|[a-f0-9]{3})$/i.test(c.value))) { + return new(Color)(c.value.slice(1)); + } + if ((c instanceof Color) || (c = Color.fromKeyword(c.value))) { + c.keyword = undefined; + return c; + } + throw { + type: "Argument", + message: "argument must be a color keyword or 3/6 digit hex e.g. #FFF" + }; + }, + tint: function(color, amount) { + return colorFunctions.mix(colorFunctions.rgb(255,255,255), color, amount); + }, + shade: function(color, amount) { + return colorFunctions.mix(colorFunctions.rgb(0, 0, 0), color, amount); } - var colorFunctions = { - rgb: function (r, g, b) { - return colorFunctions.rgba(r, g, b, 1.0); - }, - rgba: function (r, g, b, a) { - var rgb = [r, g, b].map(function (c) { return scaled(c, 255); }); - a = number(a); - return new(tree.Color)(rgb, a); - }, - hsl: function (h, s, l) { - return colorFunctions.hsla(h, s, l, 1.0); - }, - hsla: function (h, s, l, a) { - function hue(h) { - h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h); - if (h * 6 < 1) { return m1 + (m2 - m1) * h * 6; } - else if (h * 2 < 1) { return m2; } - else if (h * 3 < 2) { return m1 + (m2 - m1) * (2/3 - h) * 6; } - else { return m1; } - } - - h = (number(h) % 360) / 360; - s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a)); - - var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; - var m1 = l * 2 - m2; - - return colorFunctions.rgba(hue(h + 1/3) * 255, - hue(h) * 255, - hue(h - 1/3) * 255, - a); - }, - - hsv: function(h, s, v) { - return colorFunctions.hsva(h, s, v, 1.0); - }, - - hsva: function(h, s, v, a) { - h = ((number(h) % 360) / 360) * 360; - s = number(s); v = number(v); a = number(a); - - var i, f; - i = Math.floor((h / 60) % 6); - f = (h / 60) - i; - - var vs = [v, - v * (1 - s), - v * (1 - f * s), - v * (1 - (1 - f) * s)]; - var perm = [[0, 3, 1], - [2, 0, 1], - [1, 0, 3], - [1, 2, 0], - [3, 1, 0], - [0, 1, 2]]; - - return colorFunctions.rgba(vs[perm[i][0]] * 255, - vs[perm[i][1]] * 255, - vs[perm[i][2]] * 255, - a); - }, - - hue: function (color) { - return new(tree.Dimension)(color.toHSL().h); - }, - saturation: function (color) { - return new(tree.Dimension)(color.toHSL().s * 100, '%'); - }, - lightness: function (color) { - return new(tree.Dimension)(color.toHSL().l * 100, '%'); - }, - hsvhue: function(color) { - return new(tree.Dimension)(color.toHSV().h); - }, - hsvsaturation: function (color) { - return new(tree.Dimension)(color.toHSV().s * 100, '%'); - }, - hsvvalue: function (color) { - return new(tree.Dimension)(color.toHSV().v * 100, '%'); - }, - red: function (color) { - return new(tree.Dimension)(color.rgb[0]); - }, - green: function (color) { - return new(tree.Dimension)(color.rgb[1]); - }, - blue: function (color) { - return new(tree.Dimension)(color.rgb[2]); - }, - alpha: function (color) { - return new(tree.Dimension)(color.toHSL().a); - }, - luma: function (color) { - return new(tree.Dimension)(color.luma() * color.alpha * 100, '%'); - }, - luminance: function (color) { - var luminance = - (0.2126 * color.rgb[0] / 255) - + (0.7152 * color.rgb[1] / 255) - + (0.0722 * color.rgb[2] / 255); - - return new(tree.Dimension)(luminance * color.alpha * 100, '%'); - }, - saturate: function (color, amount) { - // filter: saturate(3.2); - // should be kept as is, so check for color - if (!color.rgb) { - return null; - } - var hsl = color.toHSL(); - - hsl.s += amount.value / 100; - hsl.s = clamp(hsl.s); - return hsla(hsl); - }, - desaturate: function (color, amount) { - var hsl = color.toHSL(); - - hsl.s -= amount.value / 100; - hsl.s = clamp(hsl.s); - return hsla(hsl); - }, - lighten: function (color, amount) { - var hsl = color.toHSL(); - - hsl.l += amount.value / 100; - hsl.l = clamp(hsl.l); - return hsla(hsl); - }, - darken: function (color, amount) { - var hsl = color.toHSL(); - - hsl.l -= amount.value / 100; - hsl.l = clamp(hsl.l); - return hsla(hsl); - }, - fadein: function (color, amount) { - var hsl = color.toHSL(); - - hsl.a += amount.value / 100; - hsl.a = clamp(hsl.a); - return hsla(hsl); - }, - fadeout: function (color, amount) { - var hsl = color.toHSL(); - - hsl.a -= amount.value / 100; - hsl.a = clamp(hsl.a); - return hsla(hsl); - }, - fade: function (color, amount) { - var hsl = color.toHSL(); - - hsl.a = amount.value / 100; - hsl.a = clamp(hsl.a); - return hsla(hsl); - }, - spin: function (color, amount) { - var hsl = color.toHSL(); - var hue = (hsl.h + amount.value) % 360; - - hsl.h = hue < 0 ? 360 + hue : hue; - - return hsla(hsl); - }, - // - // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein - // http://sass-lang.com - // - mix: function (color1, color2, weight) { - if (!weight) { - weight = new(tree.Dimension)(50); - } - var p = weight.value / 100.0; - var w = p * 2 - 1; - var a = color1.toHSL().a - color2.toHSL().a; - - var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; - var w2 = 1 - w1; - - var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2, - color1.rgb[1] * w1 + color2.rgb[1] * w2, - color1.rgb[2] * w1 + color2.rgb[2] * w2]; - - var alpha = color1.alpha * p + color2.alpha * (1 - p); - - return new(tree.Color)(rgb, alpha); - }, - greyscale: function (color) { - return colorFunctions.desaturate(color, new(tree.Dimension)(100)); - }, - contrast: function (color, dark, light, threshold) { - // filter: contrast(3.2); - // should be kept as is, so check for color - if (!color.rgb) { - return null; - } - if (typeof light === 'undefined') { - light = colorFunctions.rgba(255, 255, 255, 1.0); - } - if (typeof dark === 'undefined') { - dark = colorFunctions.rgba(0, 0, 0, 1.0); - } - //Figure out which is actually light and dark! - if (dark.luma() > light.luma()) { - var t = light; - light = dark; - dark = t; - } - if (typeof threshold === 'undefined') { - threshold = 0.43; - } else { - threshold = number(threshold); - } - if (color.luma() < threshold) { - return light; - } else { - return dark; - } - }, - argb: function (color) { - return new(tree.Anonymous)(color.toARGB()); - }, - color: function(c) { - if ((c instanceof tree.Quoted) && - (/^#([a-f0-9]{6}|[a-f0-9]{3})$/i.test(c.value))) { - return new(tree.Color)(c.value.slice(1)); - } - if ((c instanceof tree.Color) || (c = tree.Color.fromKeyword(c.value))) { - c.keyword = undefined; - return c; - } - throw { - type: "Argument", - message: "argument must be a color keyword or 3/6 digit hex e.g. #FFF" - }; - }, - tint: function(color, amount) { - return colorFunctions.mix(colorFunctions.rgb(255,255,255), color, amount); - }, - shade: function(color, amount) { - return colorFunctions.mix(colorFunctions.rgb(0, 0, 0), color, amount); - } - }; - functions.functionRegistry.addMultiple(colorFunctions); }; +functionRegistry.addMultiple(colorFunctions); diff --git a/lib/less/functions/data-uri.js b/lib/less/functions/data-uri.js index c60be3aa..47e1273e 100644 --- a/lib/less/functions/data-uri.js +++ b/lib/less/functions/data-uri.js @@ -1,8 +1,12 @@ -module.exports = function(functions, tree, less) { - functions.functionRegistry.add("data-uri", function(mimetypeNode, filePathNode) { +module.exports = function(less) { + var Anonymous = require("../tree/anonymous.js"), + URL = require("../tree/url.js"), + functionRegistry = require("./function-registry.js"); + + functionRegistry.add("data-uri", function(mimetypeNode, filePathNode) { if (!less.environment.supportsDataURI(this.env)) { - return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); + return new URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); } var mimetype = mimetypeNode.value; @@ -56,7 +60,7 @@ module.exports = function(functions, tree, less) { console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB); } - return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); + return new URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env); } } @@ -64,6 +68,6 @@ module.exports = function(functions, tree, less) { : encodeURIComponent(buf); var uri = "\"data:" + mimetype + ',' + buf + fragment + "\""; - return new(tree.URL)(new(tree.Anonymous)(uri)); + return new(URL)(new(Anonymous)(uri)); }); }; diff --git a/lib/less/functions/default.js b/lib/less/functions/default.js index ee256c71..8b97e7aa 100644 --- a/lib/less/functions/default.js +++ b/lib/less/functions/default.js @@ -1,4 +1,5 @@ -var Keyword = require("../tree/keyword.js"); +var Keyword = require("../tree/keyword.js"), + functionRegistry = require("./function-registry.js"); var defaultFunc = { eval: function () { @@ -20,4 +21,7 @@ var defaultFunc = { this.value_ = this.error_ = null; } }; + +functionRegistry.add("default", defaultFunc.eval.bind(defaultFunc)); + module.exports = defaultFunc; diff --git a/lib/less/functions/function-caller.js b/lib/less/functions/function-caller.js index da86d513..753c1480 100644 --- a/lib/less/functions/function-caller.js +++ b/lib/less/functions/function-caller.js @@ -1,7 +1,8 @@ -module.exports = function(functions) { +var functionRegistry = require("./function-registry.js"); + var functionCaller = function(name, env, currentFileInfo) { this.name = name.toLowerCase(); - this.function = functions.functionRegistry.get(this.name); + this.function = functionRegistry.get(this.name); this.env = env; this.currentFileInfo = currentFileInfo; }; @@ -11,5 +12,5 @@ functionCaller.prototype.isValid = function() { functionCaller.prototype.call = function(args) { return this.function.apply(this, args); }; -return functionCaller; -}; + +module.exports = functionCaller; diff --git a/lib/less/functions/index.js b/lib/less/functions/index.js index 4600500a..261b4bc5 100644 --- a/lib/less/functions/index.js +++ b/lib/less/functions/index.js @@ -1,22 +1,19 @@ -module.exports = function(less, tree) { - var functions = {}; - functions.functionRegistry = require("./function-registry.js"); - functions.functionCaller = require("./function-caller.js")(functions); +module.exports = function(less) { + var functions = { + functionRegistry: require("./function-registry.js"), + functionCaller: require("./function-caller.js") + }; //register functions - require("./color.js")(functions, tree); - require("./color-blending.js")(functions, tree); - require("./data-uri.js")(functions, tree, less); - - var defaultFunc = require("./default.js"); - functions.functionRegistry.add("default", defaultFunc.eval.bind(defaultFunc)); - tree.defaultFunc = defaultFunc; - - require("./math.js")(functions, tree); - require("./number.js")(functions, tree); - require("./string.js")(functions, tree); - require("./svg.js")(functions, tree, less); - require("./types.js")(functions, tree); + require("./default.js"); + require("./color.js"); + require("./color-blending.js"); + require("./data-uri.js")(less); + require("./math.js"); + require("./number.js"); + require("./string.js"); + require("./svg.js")(less); + require("./types.js"); return functions; }; diff --git a/lib/less/functions/math.js b/lib/less/functions/math.js index 4e56d8d2..94742737 100644 --- a/lib/less/functions/math.js +++ b/lib/less/functions/math.js @@ -1,42 +1,41 @@ -module.exports = function(functions, tree) { - - 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); - } - - for (var f in mathFunctions) { - if (mathFunctions.hasOwnProperty(f)) { - mathFunctions[f] = _math.bind(null, Math[f], mathFunctions[f]); - } - } - - mathFunctions.round = function (n, f) { - var fraction = typeof(f) === "undefined" ? 0 : f.value; - return _math(function(num) { return num.toFixed(fraction); }, null, n); - }; - - functions.functionRegistry.addMultiple(mathFunctions); +var Dimension = require("../tree/dimension.js"), + functionRegistry = require("./function-registry.js"); +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 Dimension)) { + throw { type: "Argument", message: "argument must be a number" }; + } + if (unit == null) { + unit = n.unit; + } else { + n = n.unify(); + } + return new(Dimension)(fn(parseFloat(n.value)), unit); +} + +for (var f in mathFunctions) { + if (mathFunctions.hasOwnProperty(f)) { + mathFunctions[f] = _math.bind(null, Math[f], mathFunctions[f]); + } +} + +mathFunctions.round = function (n, f) { + var fraction = typeof(f) === "undefined" ? 0 : f.value; + return _math(function(num) { return num.toFixed(fraction); }, null, n); +}; + +functionRegistry.addMultiple(mathFunctions); diff --git a/lib/less/functions/number.js b/lib/less/functions/number.js index dc6fdfd5..0eb84c9c 100644 --- a/lib/less/functions/number.js +++ b/lib/less/functions/number.js @@ -1,74 +1,76 @@ -module.exports = function(functions, tree) { - var minMax = function (isMin, args) { - args = Array.prototype.slice.call(args); - switch(args.length) { - case 0: throw { type: "Argument", message: "one or more arguments required" }; - } - var i, j, current, currentUnified, referenceUnified, unit, unitStatic, unitClone, - order = [], // elems only contains original argument values. - values = {}; // key is the unit.toString() for unified tree.Dimension values, - // value is the index into the order array. - for (i = 0; i < args.length; i++) { - current = args[i]; - if (!(current instanceof tree.Dimension)) { - if(Array.isArray(args[i].value)) { - Array.prototype.push.apply(args, Array.prototype.slice.call(args[i].value)); - } - continue; - } - currentUnified = current.unit.toString() === "" && unitClone !== undefined ? new(tree.Dimension)(current.value, unitClone).unify() : current.unify(); - unit = currentUnified.unit.toString() === "" && unitStatic !== undefined ? unitStatic : currentUnified.unit.toString(); - unitStatic = unit !== "" && unitStatic === undefined || unit !== "" && order[0].unify().unit.toString() === "" ? unit : unitStatic; - unitClone = unit !== "" && unitClone === undefined ? current.unit.toString() : unitClone; - j = values[""] !== undefined && unit !== "" && unit === unitStatic ? values[""] : values[unit]; - if (j === undefined) { - if(unitStatic !== undefined && unit !== unitStatic) { - throw{ type: "Argument", message: "incompatible types" }; - } - values[unit] = order.length; - order.push(current); - continue; - } - referenceUnified = order[j].unit.toString() === "" && unitClone !== undefined ? new(tree.Dimension)(order[j].value, unitClone).unify() : order[j].unify(); - if ( isMin && currentUnified.value < referenceUnified.value || - !isMin && currentUnified.value > referenceUnified.value) { - order[j] = current; - } - } - if (order.length == 1) { - return order[0]; - } - args = order.map(function (a) { return a.toCSS(this.env); }).join(this.env.compress ? "," : ", "); - return new(tree.Anonymous)((isMin ? "min" : "max") + "(" + args + ")"); - }; - functions.functionRegistry.addMultiple({ - min: function () { - return minMax(true, arguments); - }, - max: function () { - return minMax(false, arguments); - }, - convert: function (val, unit) { - return val.convertTo(unit.value); - }, - pi: function () { - return new(tree.Dimension)(Math.PI); - }, - mod: function(a, b) { - return new(tree.Dimension)(a.value % b.value, a.unit); - }, - pow: function(x, y) { - if (typeof x === "number" && typeof y === "number") { - x = new(tree.Dimension)(x); - y = new(tree.Dimension)(y); - } else if (!(x instanceof tree.Dimension) || !(y instanceof tree.Dimension)) { - throw { type: "Argument", message: "arguments must be numbers" }; - } +var Dimension = require("../tree/dimension.js"), + Anonymous = require("../tree/anonymous.js"), + functionRegistry = require("./function-registry.js"); - return new(tree.Dimension)(Math.pow(x.value, y.value), x.unit); - }, - percentage: function (n) { - return new(tree.Dimension)(n.value * 100, '%'); +var minMax = function (isMin, args) { + args = Array.prototype.slice.call(args); + switch(args.length) { + case 0: throw { type: "Argument", message: "one or more arguments required" }; + } + var i, j, current, currentUnified, referenceUnified, unit, unitStatic, unitClone, + order = [], // elems only contains original argument values. + values = {}; // key is the unit.toString() for unified Dimension values, + // value is the index into the order array. + for (i = 0; i < args.length; i++) { + current = args[i]; + if (!(current instanceof Dimension)) { + if(Array.isArray(args[i].value)) { + Array.prototype.push.apply(args, Array.prototype.slice.call(args[i].value)); + } + continue; } - }); + currentUnified = current.unit.toString() === "" && unitClone !== undefined ? new(Dimension)(current.value, unitClone).unify() : current.unify(); + unit = currentUnified.unit.toString() === "" && unitStatic !== undefined ? unitStatic : currentUnified.unit.toString(); + unitStatic = unit !== "" && unitStatic === undefined || unit !== "" && order[0].unify().unit.toString() === "" ? unit : unitStatic; + unitClone = unit !== "" && unitClone === undefined ? current.unit.toString() : unitClone; + j = values[""] !== undefined && unit !== "" && unit === unitStatic ? values[""] : values[unit]; + if (j === undefined) { + if(unitStatic !== undefined && unit !== unitStatic) { + throw{ type: "Argument", message: "incompatible types" }; + } + values[unit] = order.length; + order.push(current); + continue; + } + referenceUnified = order[j].unit.toString() === "" && unitClone !== undefined ? new(Dimension)(order[j].value, unitClone).unify() : order[j].unify(); + if ( isMin && currentUnified.value < referenceUnified.value || + !isMin && currentUnified.value > referenceUnified.value) { + order[j] = current; + } + } + if (order.length == 1) { + return order[0]; + } + args = order.map(function (a) { return a.toCSS(this.env); }).join(this.env.compress ? "," : ", "); + return new(Anonymous)((isMin ? "min" : "max") + "(" + args + ")"); }; +functionRegistry.addMultiple({ + min: function () { + return minMax(true, arguments); + }, + max: function () { + return minMax(false, arguments); + }, + convert: function (val, unit) { + return val.convertTo(unit.value); + }, + pi: function () { + return new(Dimension)(Math.PI); + }, + mod: function(a, b) { + return new(Dimension)(a.value % b.value, a.unit); + }, + pow: function(x, y) { + if (typeof x === "number" && typeof y === "number") { + x = new(Dimension)(x); + y = new(Dimension)(y); + } else if (!(x instanceof Dimension) || !(y instanceof Dimension)) { + throw { type: "Argument", message: "arguments must be numbers" }; + } + + return new(Dimension)(Math.pow(x.value, y.value), x.unit); + }, + percentage: function (n) { + return new(Dimension)(n.value * 100, '%'); + } +}); diff --git a/lib/less/functions/string.js b/lib/less/functions/string.js index 9851c891..a9547274 100644 --- a/lib/less/functions/string.js +++ b/lib/less/functions/string.js @@ -1,30 +1,33 @@ -module.exports = function(functions, tree) { - functions.functionRegistry.addMultiple({ - e: function (str) { - return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str.value); - }, - escape: function (str) { - return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); - }, - replace: function (string, pattern, replacement, flags) { - var result = string.value; +var Quoted = require("../tree/quoted.js"), + Anonymous = require("../tree/anonymous.js"), + JavaScript = require("../tree/javascript.js"), + functionRegistry = require("./function-registry.js"); - result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement.value); - return new(tree.Quoted)(string.quote || '', result, string.escaped); - }, - '%': function (string /* arg, arg, ...*/) { - var args = Array.prototype.slice.call(arguments, 1), - result = string.value; +functionRegistry.addMultiple({ + e: function (str) { + return new(Anonymous)(str instanceof JavaScript ? str.evaluated : str.value); + }, + escape: function (str) { + return new(Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29")); + }, + replace: function (string, pattern, replacement, flags) { + var result = string.value; - for (var i = 0; i < args.length; i++) { - /*jshint loopfunc:true */ - result = result.replace(/%[sda]/i, function(token) { - var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); - return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; - }); - } - result = result.replace(/%%/g, '%'); - return new(tree.Quoted)(string.quote || '', result, string.escaped); + result = result.replace(new RegExp(pattern.value, flags ? flags.value : ''), replacement.value); + return new(Quoted)(string.quote || '', result, string.escaped); + }, + '%': function (string /* arg, arg, ...*/) { + var args = Array.prototype.slice.call(arguments, 1), + result = string.value; + + for (var i = 0; i < args.length; i++) { + /*jshint loopfunc:true */ + result = result.replace(/%[sda]/i, function(token) { + var value = token.match(/s/i) ? args[i].value : args[i].toCSS(); + return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value; + }); } - }); -}; + result = result.replace(/%%/g, '%'); + return new(Quoted)(string.quote || '', result, string.escaped); + } +}); diff --git a/lib/less/functions/svg.js b/lib/less/functions/svg.js index 0cd71d57..439a2184 100644 --- a/lib/less/functions/svg.js +++ b/lib/less/functions/svg.js @@ -1,5 +1,11 @@ -module.exports = function(functions, tree, less) { - functions.functionRegistry.add("svg-gradient", function(direction) { +module.exports = function(less) { + var Dimension = require("../tree/dimension.js"), + Color = require("../tree/color.js"), + Anonymous = require("../tree/anonymous.js"), + URL = require("../tree/url.js"), + functionRegistry = require("./function-registry.js"); + + functionRegistry.add("svg-gradient", function(direction) { function throwArgumentDescriptor() { throw { type: "Argument", message: "svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]" }; @@ -53,7 +59,7 @@ module.exports = function(functions, tree, less) { position = undefined; } - if (!(color instanceof tree.Color) || (!((i === 0 || i+1 === stops.length) && position === undefined) && !(position instanceof tree.Dimension))) { + if (!(color instanceof Color) || (!((i === 0 || i+1 === stops.length) && position === undefined) && !(position instanceof Dimension))) { throwArgumentDescriptor(); } positionValue = position ? position.toCSS(renderEnv) : i === 0 ? "0%" : "100%"; @@ -72,6 +78,6 @@ module.exports = function(functions, tree, less) { } returner = "'data:image/svg+xml" + (useBase64 ? ";base64" : "") + "," + returner + "'"; - return new(tree.URL)(new(tree.Anonymous)(returner)); + return new(URL)(new(Anonymous)(returner)); }); }; diff --git a/lib/less/functions/types.js b/lib/less/functions/types.js index 04734388..dfb51b66 100644 --- a/lib/less/functions/types.js +++ b/lib/less/functions/types.js @@ -1,65 +1,71 @@ -var Keyword = require("../tree/keyword.js"); -module.exports = function(functions, tree) { - var isa = function (n, Type) { - return (n instanceof Type) ? Keyword.True : Keyword.False; - }, - isunit = function (n, unit) { - return (n instanceof tree.Dimension) && n.unit.is(unit.value || unit) ? Keyword.True : Keyword.False; - }; - functions.functionRegistry.addMultiple({ - iscolor: function (n) { - return isa(n, tree.Color); - }, - isnumber: function (n) { - return isa(n, tree.Dimension); - }, - isstring: function (n) { - return isa(n, tree.Quoted); - }, - iskeyword: function (n) { - return isa(n, tree.Keyword); - }, - isurl: function (n) { - return isa(n, tree.URL); - }, - ispixel: function (n) { - return isunit(n, 'px'); - }, - ispercentage: function (n) { - return isunit(n, '%'); - }, - isem: function (n) { - return isunit(n, 'em'); - }, - isunit: isunit, - 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?" : "") }; - } - if (unit) { - if (unit instanceof tree.Keyword) { - unit = unit.value; - } else { - unit = unit.toCSS(); - } - } else { - unit = ""; - } - return new(tree.Dimension)(val.value, unit); - }, - "get-unit": function (n) { - return new(tree.Anonymous)(n.unit); - }, - extract: function(values, index) { - index = index.value - 1; // (1-based index) - // handle non-array values as an array of length 1 - // return 'undefined' if index is invalid - return Array.isArray(values.value) ? - values.value[index] : Array(values)[index]; - }, - length: function(values) { - var n = Array.isArray(values.value) ? values.value.length : 1; - return new tree.Dimension(n); +var Keyword = require("../tree/keyword.js"), + Dimension = require("../tree/dimension.js"), + Color = require("../tree/color.js"), + Quoted = require("../tree/quoted.js"), + Anonymous = require("../tree/anonymous.js"), + URL = require("../tree/url.js"), + Operation = require("../tree/operation.js"), + functionRegistry = require("./function-registry.js"); + +var isa = function (n, Type) { + return (n instanceof Type) ? Keyword.True : Keyword.False; + }, + isunit = function (n, unit) { + return (n instanceof Dimension) && n.unit.is(unit.value || unit) ? Keyword.True : Keyword.False; + }; +functionRegistry.addMultiple({ + iscolor: function (n) { + return isa(n, Color); + }, + isnumber: function (n) { + return isa(n, Dimension); + }, + isstring: function (n) { + return isa(n, Quoted); + }, + iskeyword: function (n) { + return isa(n, Keyword); + }, + isurl: function (n) { + return isa(n, URL); + }, + ispixel: function (n) { + return isunit(n, 'px'); + }, + ispercentage: function (n) { + return isunit(n, '%'); + }, + isem: function (n) { + return isunit(n, 'em'); + }, + isunit: isunit, + unit: function (val, unit) { + if(!(val instanceof Dimension)) { + throw { type: "Argument", message: "the first argument to unit must be a number" + (val instanceof Operation ? ". Have you forgotten parenthesis?" : "") }; } - }); -}; + if (unit) { + if (unit instanceof Keyword) { + unit = unit.value; + } else { + unit = unit.toCSS(); + } + } else { + unit = ""; + } + return new(Dimension)(val.value, unit); + }, + "get-unit": function (n) { + return new(Anonymous)(n.unit); + }, + extract: function(values, index) { + index = index.value - 1; // (1-based index) + // handle non-array values as an array of length 1 + // return 'undefined' if index is invalid + return Array.isArray(values.value) ? + values.value[index] : Array(values)[index]; + }, + length: function(values) { + var n = Array.isArray(values.value) ? values.value.length : 1; + return new Dimension(n); + } +}); diff --git a/lib/less/non-node-index.js b/lib/less/non-node-index.js index 2f5bcb02..a14c1c33 100644 --- a/lib/less/non-node-index.js +++ b/lib/less/non-node-index.js @@ -6,7 +6,7 @@ var less = { less.tree = require('./tree/index.js'); less.visitor = require('./visitor/index.js')(less, less.tree); less.Parser = (require('./parser'))(less, less.tree, less.visitor); -less.functions = (require('./functions/index.js'))(less, less.tree); +less.functions = require('./functions/index.js')(less); less.contexts = require("./contexts.js"); less.tree.sourceMapOutput = require('./source-map-output.js')(less);