Fully end to end encrypted anonymous chat program. Server only stores public key lookup for users and the encrypted messages. No credentials are transfered to the server, but kept in local browser storage. This allows 100% safe chatting. https://safechat.ch
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.

368 lines
6.7 KiB

/*!
* Stylus - RGBA
* Copyright (c) Automattic <developer.wordpress.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Node = require('./node')
, HSLA = require('./hsla')
, functions = require('../functions')
, adjust = functions.adjust
, nodes = require('./');
/**
* Initialize a new `RGBA` with the given r,g,b,a component values.
*
* @param {Number} r
* @param {Number} g
* @param {Number} b
* @param {Number} a
* @api public
*/
var RGBA = exports = module.exports = function RGBA(r,g,b,a){
Node.call(this);
this.r = clamp(r);
this.g = clamp(g);
this.b = clamp(b);
this.a = clampAlpha(a);
this.name = '';
this.rgba = this;
};
/**
* Inherit from `Node.prototype`.
*/
RGBA.prototype.__proto__ = Node.prototype;
/**
* Return an `RGBA` without clamping values.
*
* @param {Number} r
* @param {Number} g
* @param {Number} b
* @param {Number} a
* @return {RGBA}
* @api public
*/
RGBA.withoutClamping = function(r,g,b,a){
var rgba = new RGBA(0,0,0,0);
rgba.r = r;
rgba.g = g;
rgba.b = b;
rgba.a = a;
return rgba;
};
/**
* Return a clone of this node.
*
* @return {Node}
* @api public
*/
RGBA.prototype.clone = function(){
var clone = new RGBA(
this.r
, this.g
, this.b
, this.a);
clone.raw = this.raw;
clone.name = this.name;
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
*/
RGBA.prototype.toJSON = function(){
return {
__type: 'RGBA',
r: this.r,
g: this.g,
b: this.b,
a: this.a,
raw: this.raw,
name: this.name,
lineno: this.lineno,
column: this.column,
filename: this.filename
};
};
/**
* Return true.
*
* @return {Boolean}
* @api public
*/
RGBA.prototype.toBoolean = function(){
return nodes.true;
};
/**
* Return `HSLA` representation.
*
* @return {HSLA}
* @api public
*/
RGBA.prototype.__defineGetter__('hsla', function(){
return HSLA.fromRGBA(this);
});
/**
* Return hash.
*
* @return {String}
* @api public
*/
RGBA.prototype.__defineGetter__('hash', function(){
return this.toString();
});
/**
* Add r,g,b,a to the current component values.
*
* @param {Number} r
* @param {Number} g
* @param {Number} b
* @param {Number} a
* @return {RGBA} new node
* @api public
*/
RGBA.prototype.add = function(r,g,b,a){
return new RGBA(
this.r + r
, this.g + g
, this.b + b
, this.a + a);
};
/**
* Subtract r,g,b,a from the current component values.
*
* @param {Number} r
* @param {Number} g
* @param {Number} b
* @param {Number} a
* @return {RGBA} new node
* @api public
*/
RGBA.prototype.sub = function(r,g,b,a){
return new RGBA(
this.r - r
, this.g - g
, this.b - b
, a == 1 ? this.a : this.a - a);
};
/**
* Multiply rgb components by `n`.
*
* @param {String} n
* @return {RGBA} new node
* @api public
*/
RGBA.prototype.multiply = function(n){
return new RGBA(
this.r * n
, this.g * n
, this.b * n
, this.a);
};
/**
* Divide rgb components by `n`.
*
* @param {String} n
* @return {RGBA} new node
* @api public
*/
RGBA.prototype.divide = function(n){
return new RGBA(
this.r / n
, this.g / n
, this.b / n
, this.a);
};
/**
* Operate on `right` with the given `op`.
*
* @param {String} op
* @param {Node} right
* @return {Node}
* @api public
*/
RGBA.prototype.operate = function(op, right){
if ('in' != op) right = right.first
switch (op) {
case 'is a':
if ('string' == right.nodeName && 'color' == right.string) {
return nodes.true;
}
break;
case '+':
switch (right.nodeName) {
case 'unit':
var n = right.val;
switch (right.type) {
case '%': return adjust(this, new nodes.String('lightness'), right);
case 'deg': return this.hsla.adjustHue(n).rgba;
default: return this.add(n,n,n,0);
}
case 'rgba':
return this.add(right.r, right.g, right.b, right.a);
case 'hsla':
return this.hsla.add(right.h, right.s, right.l);
}
break;
case '-':
switch (right.nodeName) {
case 'unit':
var n = right.val;
switch (right.type) {
case '%': return adjust(this, new nodes.String('lightness'), new nodes.Unit(-n, '%'));
case 'deg': return this.hsla.adjustHue(-n).rgba;
default: return this.sub(n,n,n,0);
}
case 'rgba':
return this.sub(right.r, right.g, right.b, right.a);
case 'hsla':
return this.hsla.sub(right.h, right.s, right.l);
}
break;
case '*':
switch (right.nodeName) {
case 'unit':
return this.multiply(right.val);
}
break;
case '/':
switch (right.nodeName) {
case 'unit':
return this.divide(right.val);
}
break;
}
return Node.prototype.operate.call(this, op, right);
};
/**
* Return #nnnnnn, #nnn, or rgba(n,n,n,n) string representation of the color.
*
* @return {String}
* @api public
*/
RGBA.prototype.toString = function(){
function pad(n) {
return n < 16
? '0' + n.toString(16)
: n.toString(16);
}
// special case for transparent named color
if ('transparent' == this.name)
return this.name;
if (1 == this.a) {
var r = pad(this.r)
, g = pad(this.g)
, b = pad(this.b);
// Compress
if (r[0] == r[1] && g[0] == g[1] && b[0] == b[1]) {
return '#' + r[0] + g[0] + b[0];
} else {
return '#' + r + g + b;
}
} else {
return 'rgba('
+ this.r + ','
+ this.g + ','
+ this.b + ','
+ (+this.a.toFixed(3)) + ')';
}
};
/**
* Return a `RGBA` from the given `hsla`.
*
* @param {HSLA} hsla
* @return {RGBA}
* @api public
*/
exports.fromHSLA = function(hsla){
var h = hsla.h / 360
, s = hsla.s / 100
, l = hsla.l / 100
, a = hsla.a;
var m2 = l <= .5 ? l * (s + 1) : l + s - l * s
, m1 = l * 2 - m2;
var r = hue(h + 1/3) * 0xff
, g = hue(h) * 0xff
, b = hue(h - 1/3) * 0xff;
function hue(h) {
if (h < 0) ++h;
if (h > 1) --h;
if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
if (h * 2 < 1) return m2;
if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;
return m1;
}
return new RGBA(r,g,b,a);
};
/**
* Clamp `n` >= 0 and <= 255.
*
* @param {Number} n
* @return {Number}
* @api private
*/
function clamp(n) {
return Math.max(0, Math.min(n.toFixed(0), 255));
}
/**
* Clamp alpha `n` >= 0 and <= 1.
*
* @param {Number} n
* @return {Number}
* @api private
*/
function clampAlpha(n) {
return Math.max(0, Math.min(n, 1));
}