369 lines
11 KiB
JavaScript
369 lines
11 KiB
JavaScript
|
(function() {
|
||
|
var Gradient, OldValue, Value, isDirection, list, parser, range, utils,
|
||
|
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||
|
hasProp = {}.hasOwnProperty,
|
||
|
slice = [].slice;
|
||
|
|
||
|
OldValue = require('../old-value');
|
||
|
|
||
|
Value = require('../value');
|
||
|
|
||
|
utils = require('../utils');
|
||
|
|
||
|
parser = require('postcss-value-parser');
|
||
|
|
||
|
range = require('normalize-range');
|
||
|
|
||
|
list = require('postcss/lib/list');
|
||
|
|
||
|
isDirection = /top|left|right|bottom/gi;
|
||
|
|
||
|
Gradient = (function(superClass) {
|
||
|
extend(Gradient, superClass);
|
||
|
|
||
|
function Gradient() {
|
||
|
return Gradient.__super__.constructor.apply(this, arguments);
|
||
|
}
|
||
|
|
||
|
Gradient.names = ['linear-gradient', 'repeating-linear-gradient', 'radial-gradient', 'repeating-radial-gradient'];
|
||
|
|
||
|
Gradient.prototype.replace = function(string, prefix) {
|
||
|
var ast, changes, j, len, node, ref;
|
||
|
ast = parser(string);
|
||
|
ref = ast.nodes;
|
||
|
for (j = 0, len = ref.length; j < len; j++) {
|
||
|
node = ref[j];
|
||
|
if (node.type === 'function' && node.value === this.name) {
|
||
|
node.nodes = this.newDirection(node.nodes);
|
||
|
node.nodes = this.normalize(node.nodes);
|
||
|
if (prefix === '-webkit- old') {
|
||
|
changes = this.oldWebkit(node);
|
||
|
if (!changes) {
|
||
|
return;
|
||
|
}
|
||
|
} else {
|
||
|
node.nodes = this.convertDirection(node.nodes);
|
||
|
node.value = prefix + node.value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return ast.toString();
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.directions = {
|
||
|
top: 'bottom',
|
||
|
left: 'right',
|
||
|
bottom: 'top',
|
||
|
right: 'left'
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.oldDirections = {
|
||
|
'top': 'left bottom, left top',
|
||
|
'left': 'right top, left top',
|
||
|
'bottom': 'left top, left bottom',
|
||
|
'right': 'left top, right top',
|
||
|
'top right': 'left bottom, right top',
|
||
|
'top left': 'right bottom, left top',
|
||
|
'right top': 'left bottom, right top',
|
||
|
'right bottom': 'left top, right bottom',
|
||
|
'bottom right': 'left top, right bottom',
|
||
|
'bottom left': 'right top, left bottom',
|
||
|
'left top': 'right bottom, left top',
|
||
|
'left bottom': 'right top, left bottom'
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.replaceFirst = function() {
|
||
|
var params, prefix, words;
|
||
|
params = arguments[0], words = 2 <= arguments.length ? slice.call(arguments, 1) : [];
|
||
|
prefix = words.map(function(i) {
|
||
|
if (i === ' ') {
|
||
|
return {
|
||
|
type: 'space',
|
||
|
value: i
|
||
|
};
|
||
|
} else {
|
||
|
return {
|
||
|
type: 'word',
|
||
|
value: i
|
||
|
};
|
||
|
}
|
||
|
});
|
||
|
return prefix.concat(params.slice(1));
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.normalizeUnit = function(str, full) {
|
||
|
var deg, num;
|
||
|
num = parseFloat(str);
|
||
|
deg = (num / full) * 360;
|
||
|
return deg + "deg";
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.normalize = function(nodes) {
|
||
|
var num;
|
||
|
if (!nodes[0]) {
|
||
|
return nodes;
|
||
|
}
|
||
|
if (/-?\d+(.\d+)?grad/.test(nodes[0].value)) {
|
||
|
nodes[0].value = this.normalizeUnit(nodes[0].value, 400);
|
||
|
} else if (/-?\d+(.\d+)?rad/.test(nodes[0].value)) {
|
||
|
nodes[0].value = this.normalizeUnit(nodes[0].value, 2 * Math.PI);
|
||
|
} else if (/-?\d+(.\d+)?turn/.test(nodes[0].value)) {
|
||
|
nodes[0].value = this.normalizeUnit(nodes[0].value, 1);
|
||
|
} else if (nodes[0].value.indexOf('deg') !== -1) {
|
||
|
num = parseFloat(nodes[0].value);
|
||
|
num = range.wrap(0, 360, num);
|
||
|
nodes[0].value = num + "deg";
|
||
|
}
|
||
|
if (nodes[0].value === '0deg') {
|
||
|
nodes = this.replaceFirst(nodes, 'to', ' ', 'top');
|
||
|
} else if (nodes[0].value === '90deg') {
|
||
|
nodes = this.replaceFirst(nodes, 'to', ' ', 'right');
|
||
|
} else if (nodes[0].value === '180deg') {
|
||
|
nodes = this.replaceFirst(nodes, 'to', ' ', 'bottom');
|
||
|
} else if (nodes[0].value === '270deg') {
|
||
|
nodes = this.replaceFirst(nodes, 'to', ' ', 'left');
|
||
|
}
|
||
|
return nodes;
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.newDirection = function(params) {
|
||
|
var i, j, ref;
|
||
|
if (params[0].value === 'to') {
|
||
|
return params;
|
||
|
}
|
||
|
if (!isDirection.test(params[0].value)) {
|
||
|
return params;
|
||
|
}
|
||
|
params.unshift({
|
||
|
type: 'word',
|
||
|
value: 'to'
|
||
|
}, {
|
||
|
type: 'space',
|
||
|
value: ' '
|
||
|
});
|
||
|
for (i = j = 2, ref = params.length; 2 <= ref ? j < ref : j > ref; i = 2 <= ref ? ++j : --j) {
|
||
|
if (params[i].type === 'div') {
|
||
|
break;
|
||
|
}
|
||
|
if (params[i].type === 'word') {
|
||
|
params[i].value = this.revertDirection(params[i].value);
|
||
|
}
|
||
|
}
|
||
|
return params;
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.convertDirection = function(params) {
|
||
|
if (params.length > 0) {
|
||
|
if (params[0].value === 'to') {
|
||
|
this.fixDirection(params);
|
||
|
} else if (params[0].value.indexOf('deg') !== -1) {
|
||
|
this.fixAngle(params);
|
||
|
} else if (params[2].value === 'at') {
|
||
|
this.fixRadial(params);
|
||
|
}
|
||
|
}
|
||
|
return params;
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.fixDirection = function(params) {
|
||
|
var i, j, ref, results;
|
||
|
params.splice(0, 2);
|
||
|
results = [];
|
||
|
for (i = j = 0, ref = params.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
|
||
|
if (params[i].type === 'div') {
|
||
|
break;
|
||
|
}
|
||
|
if (params[i].type === 'word') {
|
||
|
results.push(params[i].value = this.revertDirection(params[i].value));
|
||
|
} else {
|
||
|
results.push(void 0);
|
||
|
}
|
||
|
}
|
||
|
return results;
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.fixAngle = function(params) {
|
||
|
var first;
|
||
|
first = params[0].value;
|
||
|
first = parseFloat(first);
|
||
|
first = Math.abs(450 - first) % 360;
|
||
|
first = this.roundFloat(first, 3);
|
||
|
return params[0].value = first + "deg";
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.fixRadial = function(params) {
|
||
|
var first, i, j, ref, second;
|
||
|
first = params[0];
|
||
|
second = [];
|
||
|
for (i = j = 4, ref = params.length; 4 <= ref ? j < ref : j > ref; i = 4 <= ref ? ++j : --j) {
|
||
|
if (params[i].type === 'div') {
|
||
|
break;
|
||
|
} else {
|
||
|
second.push(params[i]);
|
||
|
}
|
||
|
}
|
||
|
return params.splice.apply(params, [0, i].concat(slice.call(second), [params[i + 2]], [first]));
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.revertDirection = function(word) {
|
||
|
return this.directions[word.toLowerCase()] || word;
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.roundFloat = function(float, digits) {
|
||
|
return parseFloat(float.toFixed(digits));
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.oldWebkit = function(node) {
|
||
|
var i, j, k, len, len1, nodes, param, params, string;
|
||
|
nodes = node.nodes;
|
||
|
string = parser.stringify(node.nodes);
|
||
|
if (this.name !== 'linear-gradient') {
|
||
|
return false;
|
||
|
}
|
||
|
if (nodes[0] && nodes[0].value.indexOf('deg') !== -1) {
|
||
|
return false;
|
||
|
}
|
||
|
if (string.indexOf('px') !== -1) {
|
||
|
return false;
|
||
|
}
|
||
|
if (string.indexOf('-corner') !== -1) {
|
||
|
return false;
|
||
|
}
|
||
|
if (string.indexOf('-side') !== -1) {
|
||
|
return false;
|
||
|
}
|
||
|
params = [[]];
|
||
|
for (j = 0, len = nodes.length; j < len; j++) {
|
||
|
i = nodes[j];
|
||
|
params[params.length - 1].push(i);
|
||
|
if (i.type === 'div' && i.value === ',') {
|
||
|
params.push([]);
|
||
|
}
|
||
|
}
|
||
|
this.oldDirection(params);
|
||
|
this.colorStops(params);
|
||
|
node.nodes = [];
|
||
|
for (k = 0, len1 = params.length; k < len1; k++) {
|
||
|
param = params[k];
|
||
|
node.nodes = node.nodes.concat(param);
|
||
|
}
|
||
|
node.nodes.unshift({
|
||
|
type: 'word',
|
||
|
value: 'linear'
|
||
|
}, this.cloneDiv(node.nodes));
|
||
|
node.value = '-webkit-gradient';
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.oldDirection = function(params) {
|
||
|
var div, j, len, node, old, ref, words;
|
||
|
div = this.cloneDiv(params[0]);
|
||
|
if (params[0][0].value !== 'to') {
|
||
|
return params.unshift([
|
||
|
{
|
||
|
type: 'word',
|
||
|
value: this.oldDirections.bottom
|
||
|
}, div
|
||
|
]);
|
||
|
} else {
|
||
|
words = [];
|
||
|
ref = params[0].slice(2);
|
||
|
for (j = 0, len = ref.length; j < len; j++) {
|
||
|
node = ref[j];
|
||
|
if (node.type === 'word') {
|
||
|
words.push(node.value.toLowerCase());
|
||
|
}
|
||
|
}
|
||
|
words = words.join(' ');
|
||
|
old = this.oldDirections[words] || words;
|
||
|
return params[0] = [
|
||
|
{
|
||
|
type: 'word',
|
||
|
value: old
|
||
|
}, div
|
||
|
];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.cloneDiv = function(params) {
|
||
|
var i, j, len;
|
||
|
for (j = 0, len = params.length; j < len; j++) {
|
||
|
i = params[j];
|
||
|
if (i.type === 'div' && i.value === ',') {
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
return {
|
||
|
type: 'div',
|
||
|
value: ',',
|
||
|
after: ' '
|
||
|
};
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.colorStops = function(params) {
|
||
|
var color, div, i, j, len, param, pos, results, stop;
|
||
|
results = [];
|
||
|
for (i = j = 0, len = params.length; j < len; i = ++j) {
|
||
|
param = params[i];
|
||
|
if (i === 0) {
|
||
|
continue;
|
||
|
}
|
||
|
color = parser.stringify(param[0]);
|
||
|
if (param[1] && param[1].type === 'word') {
|
||
|
pos = param[1].value;
|
||
|
} else if (param[2] && param[2].type === 'word') {
|
||
|
pos = param[2].value;
|
||
|
}
|
||
|
stop = i === 1 && (!pos || pos === '0%') ? "from(" + color + ")" : i === params.length - 1 && (!pos || pos === '100%') ? "to(" + color + ")" : pos ? "color-stop(" + pos + ", " + color + ")" : "color-stop(" + color + ")";
|
||
|
div = param[param.length - 1];
|
||
|
params[i] = [
|
||
|
{
|
||
|
type: 'word',
|
||
|
value: stop
|
||
|
}
|
||
|
];
|
||
|
if (div.type === 'div' && div.value === ',') {
|
||
|
results.push(params[i].push(div));
|
||
|
} else {
|
||
|
results.push(void 0);
|
||
|
}
|
||
|
}
|
||
|
return results;
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.old = function(prefix) {
|
||
|
var regexp, string, type;
|
||
|
if (prefix === '-webkit-') {
|
||
|
type = this.name === 'linear-gradient' ? 'linear' : 'radial';
|
||
|
string = '-gradient';
|
||
|
regexp = utils.regexp("-webkit-(" + type + "-gradient|gradient\\(\\s*" + type + ")", false);
|
||
|
return new OldValue(this.name, prefix + this.name, string, regexp);
|
||
|
} else {
|
||
|
return Gradient.__super__.old.apply(this, arguments);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Gradient.prototype.add = function(decl, prefix) {
|
||
|
var p;
|
||
|
p = decl.prop;
|
||
|
if (p.indexOf('mask') !== -1) {
|
||
|
if (prefix === '-webkit-' || prefix === '-webkit- old') {
|
||
|
return Gradient.__super__.add.apply(this, arguments);
|
||
|
}
|
||
|
} else if (p === 'list-style' || p === 'list-style-image' || p === 'content') {
|
||
|
if (prefix === '-webkit-' || prefix === '-webkit- old') {
|
||
|
return Gradient.__super__.add.apply(this, arguments);
|
||
|
}
|
||
|
} else {
|
||
|
return Gradient.__super__.add.apply(this, arguments);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
return Gradient;
|
||
|
|
||
|
})(Value);
|
||
|
|
||
|
module.exports = Gradient;
|
||
|
|
||
|
}).call(this);
|