gradient.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. (function() {
  2. var Gradient, OldValue, Value, isDirection, list, parser, range, utils,
  3. 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; },
  4. hasProp = {}.hasOwnProperty,
  5. slice = [].slice;
  6. OldValue = require('../old-value');
  7. Value = require('../value');
  8. utils = require('../utils');
  9. parser = require('postcss-value-parser');
  10. range = require('normalize-range');
  11. list = require('postcss/lib/list');
  12. isDirection = /top|left|right|bottom/gi;
  13. Gradient = (function(superClass) {
  14. extend(Gradient, superClass);
  15. function Gradient() {
  16. return Gradient.__super__.constructor.apply(this, arguments);
  17. }
  18. Gradient.names = ['linear-gradient', 'repeating-linear-gradient', 'radial-gradient', 'repeating-radial-gradient'];
  19. Gradient.prototype.replace = function(string, prefix) {
  20. var ast, changes, j, len, node, ref;
  21. ast = parser(string);
  22. ref = ast.nodes;
  23. for (j = 0, len = ref.length; j < len; j++) {
  24. node = ref[j];
  25. if (node.type === 'function' && node.value === this.name) {
  26. node.nodes = this.newDirection(node.nodes);
  27. node.nodes = this.normalize(node.nodes);
  28. if (prefix === '-webkit- old') {
  29. changes = this.oldWebkit(node);
  30. if (!changes) {
  31. return;
  32. }
  33. } else {
  34. node.nodes = this.convertDirection(node.nodes);
  35. node.value = prefix + node.value;
  36. }
  37. }
  38. }
  39. return ast.toString();
  40. };
  41. Gradient.prototype.directions = {
  42. top: 'bottom',
  43. left: 'right',
  44. bottom: 'top',
  45. right: 'left'
  46. };
  47. Gradient.prototype.oldDirections = {
  48. 'top': 'left bottom, left top',
  49. 'left': 'right top, left top',
  50. 'bottom': 'left top, left bottom',
  51. 'right': 'left top, right top',
  52. 'top right': 'left bottom, right top',
  53. 'top left': 'right bottom, left top',
  54. 'right top': 'left bottom, right top',
  55. 'right bottom': 'left top, right bottom',
  56. 'bottom right': 'left top, right bottom',
  57. 'bottom left': 'right top, left bottom',
  58. 'left top': 'right bottom, left top',
  59. 'left bottom': 'right top, left bottom'
  60. };
  61. Gradient.prototype.replaceFirst = function() {
  62. var params, prefix, words;
  63. params = arguments[0], words = 2 <= arguments.length ? slice.call(arguments, 1) : [];
  64. prefix = words.map(function(i) {
  65. if (i === ' ') {
  66. return {
  67. type: 'space',
  68. value: i
  69. };
  70. } else {
  71. return {
  72. type: 'word',
  73. value: i
  74. };
  75. }
  76. });
  77. return prefix.concat(params.slice(1));
  78. };
  79. Gradient.prototype.normalizeUnit = function(str, full) {
  80. var deg, num;
  81. num = parseFloat(str);
  82. deg = (num / full) * 360;
  83. return deg + "deg";
  84. };
  85. Gradient.prototype.normalize = function(nodes) {
  86. var num;
  87. if (!nodes[0]) {
  88. return nodes;
  89. }
  90. if (/-?\d+(.\d+)?grad/.test(nodes[0].value)) {
  91. nodes[0].value = this.normalizeUnit(nodes[0].value, 400);
  92. } else if (/-?\d+(.\d+)?rad/.test(nodes[0].value)) {
  93. nodes[0].value = this.normalizeUnit(nodes[0].value, 2 * Math.PI);
  94. } else if (/-?\d+(.\d+)?turn/.test(nodes[0].value)) {
  95. nodes[0].value = this.normalizeUnit(nodes[0].value, 1);
  96. } else if (nodes[0].value.indexOf('deg') !== -1) {
  97. num = parseFloat(nodes[0].value);
  98. num = range.wrap(0, 360, num);
  99. nodes[0].value = num + "deg";
  100. }
  101. if (nodes[0].value === '0deg') {
  102. nodes = this.replaceFirst(nodes, 'to', ' ', 'top');
  103. } else if (nodes[0].value === '90deg') {
  104. nodes = this.replaceFirst(nodes, 'to', ' ', 'right');
  105. } else if (nodes[0].value === '180deg') {
  106. nodes = this.replaceFirst(nodes, 'to', ' ', 'bottom');
  107. } else if (nodes[0].value === '270deg') {
  108. nodes = this.replaceFirst(nodes, 'to', ' ', 'left');
  109. }
  110. return nodes;
  111. };
  112. Gradient.prototype.newDirection = function(params) {
  113. var i, j, ref;
  114. if (params[0].value === 'to') {
  115. return params;
  116. }
  117. if (!isDirection.test(params[0].value)) {
  118. return params;
  119. }
  120. params.unshift({
  121. type: 'word',
  122. value: 'to'
  123. }, {
  124. type: 'space',
  125. value: ' '
  126. });
  127. for (i = j = 2, ref = params.length; 2 <= ref ? j < ref : j > ref; i = 2 <= ref ? ++j : --j) {
  128. if (params[i].type === 'div') {
  129. break;
  130. }
  131. if (params[i].type === 'word') {
  132. params[i].value = this.revertDirection(params[i].value);
  133. }
  134. }
  135. return params;
  136. };
  137. Gradient.prototype.convertDirection = function(params) {
  138. if (params.length > 0) {
  139. if (params[0].value === 'to') {
  140. this.fixDirection(params);
  141. } else if (params[0].value.indexOf('deg') !== -1) {
  142. this.fixAngle(params);
  143. } else if (params[2].value === 'at') {
  144. this.fixRadial(params);
  145. }
  146. }
  147. return params;
  148. };
  149. Gradient.prototype.fixDirection = function(params) {
  150. var i, j, ref, results;
  151. params.splice(0, 2);
  152. results = [];
  153. for (i = j = 0, ref = params.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) {
  154. if (params[i].type === 'div') {
  155. break;
  156. }
  157. if (params[i].type === 'word') {
  158. results.push(params[i].value = this.revertDirection(params[i].value));
  159. } else {
  160. results.push(void 0);
  161. }
  162. }
  163. return results;
  164. };
  165. Gradient.prototype.fixAngle = function(params) {
  166. var first;
  167. first = params[0].value;
  168. first = parseFloat(first);
  169. first = Math.abs(450 - first) % 360;
  170. first = this.roundFloat(first, 3);
  171. return params[0].value = first + "deg";
  172. };
  173. Gradient.prototype.fixRadial = function(params) {
  174. var first, i, j, ref, second;
  175. first = params[0];
  176. second = [];
  177. for (i = j = 4, ref = params.length; 4 <= ref ? j < ref : j > ref; i = 4 <= ref ? ++j : --j) {
  178. if (params[i].type === 'div') {
  179. break;
  180. } else {
  181. second.push(params[i]);
  182. }
  183. }
  184. return params.splice.apply(params, [0, i].concat(slice.call(second), [params[i + 2]], [first]));
  185. };
  186. Gradient.prototype.revertDirection = function(word) {
  187. return this.directions[word.toLowerCase()] || word;
  188. };
  189. Gradient.prototype.roundFloat = function(float, digits) {
  190. return parseFloat(float.toFixed(digits));
  191. };
  192. Gradient.prototype.oldWebkit = function(node) {
  193. var i, j, k, len, len1, nodes, param, params, string;
  194. nodes = node.nodes;
  195. string = parser.stringify(node.nodes);
  196. if (this.name !== 'linear-gradient') {
  197. return false;
  198. }
  199. if (nodes[0] && nodes[0].value.indexOf('deg') !== -1) {
  200. return false;
  201. }
  202. if (string.indexOf('px') !== -1) {
  203. return false;
  204. }
  205. if (string.indexOf('-corner') !== -1) {
  206. return false;
  207. }
  208. if (string.indexOf('-side') !== -1) {
  209. return false;
  210. }
  211. params = [[]];
  212. for (j = 0, len = nodes.length; j < len; j++) {
  213. i = nodes[j];
  214. params[params.length - 1].push(i);
  215. if (i.type === 'div' && i.value === ',') {
  216. params.push([]);
  217. }
  218. }
  219. this.oldDirection(params);
  220. this.colorStops(params);
  221. node.nodes = [];
  222. for (k = 0, len1 = params.length; k < len1; k++) {
  223. param = params[k];
  224. node.nodes = node.nodes.concat(param);
  225. }
  226. node.nodes.unshift({
  227. type: 'word',
  228. value: 'linear'
  229. }, this.cloneDiv(node.nodes));
  230. node.value = '-webkit-gradient';
  231. return true;
  232. };
  233. Gradient.prototype.oldDirection = function(params) {
  234. var div, j, len, node, old, ref, words;
  235. div = this.cloneDiv(params[0]);
  236. if (params[0][0].value !== 'to') {
  237. return params.unshift([
  238. {
  239. type: 'word',
  240. value: this.oldDirections.bottom
  241. }, div
  242. ]);
  243. } else {
  244. words = [];
  245. ref = params[0].slice(2);
  246. for (j = 0, len = ref.length; j < len; j++) {
  247. node = ref[j];
  248. if (node.type === 'word') {
  249. words.push(node.value.toLowerCase());
  250. }
  251. }
  252. words = words.join(' ');
  253. old = this.oldDirections[words] || words;
  254. return params[0] = [
  255. {
  256. type: 'word',
  257. value: old
  258. }, div
  259. ];
  260. }
  261. };
  262. Gradient.prototype.cloneDiv = function(params) {
  263. var i, j, len;
  264. for (j = 0, len = params.length; j < len; j++) {
  265. i = params[j];
  266. if (i.type === 'div' && i.value === ',') {
  267. return i;
  268. }
  269. }
  270. return {
  271. type: 'div',
  272. value: ',',
  273. after: ' '
  274. };
  275. };
  276. Gradient.prototype.colorStops = function(params) {
  277. var color, div, i, j, len, param, pos, results, stop;
  278. results = [];
  279. for (i = j = 0, len = params.length; j < len; i = ++j) {
  280. param = params[i];
  281. if (i === 0) {
  282. continue;
  283. }
  284. color = parser.stringify(param[0]);
  285. if (param[1] && param[1].type === 'word') {
  286. pos = param[1].value;
  287. } else if (param[2] && param[2].type === 'word') {
  288. pos = param[2].value;
  289. }
  290. 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 + ")";
  291. div = param[param.length - 1];
  292. params[i] = [
  293. {
  294. type: 'word',
  295. value: stop
  296. }
  297. ];
  298. if (div.type === 'div' && div.value === ',') {
  299. results.push(params[i].push(div));
  300. } else {
  301. results.push(void 0);
  302. }
  303. }
  304. return results;
  305. };
  306. Gradient.prototype.old = function(prefix) {
  307. var regexp, string, type;
  308. if (prefix === '-webkit-') {
  309. type = this.name === 'linear-gradient' ? 'linear' : 'radial';
  310. string = '-gradient';
  311. regexp = utils.regexp("-webkit-(" + type + "-gradient|gradient\\(\\s*" + type + ")", false);
  312. return new OldValue(this.name, prefix + this.name, string, regexp);
  313. } else {
  314. return Gradient.__super__.old.apply(this, arguments);
  315. }
  316. };
  317. Gradient.prototype.add = function(decl, prefix) {
  318. var p;
  319. p = decl.prop;
  320. if (p.indexOf('mask') !== -1) {
  321. if (prefix === '-webkit-' || prefix === '-webkit- old') {
  322. return Gradient.__super__.add.apply(this, arguments);
  323. }
  324. } else if (p === 'list-style' || p === 'list-style-image' || p === 'content') {
  325. if (prefix === '-webkit-' || prefix === '-webkit- old') {
  326. return Gradient.__super__.add.apply(this, arguments);
  327. }
  328. } else {
  329. return Gradient.__super__.add.apply(this, arguments);
  330. }
  331. };
  332. return Gradient;
  333. })(Value);
  334. module.exports = Gradient;
  335. }).call(this);