| Index: lib/src/prism/plugins/previewer-gradient/prism-previewer-gradient.js
 | 
| diff --git a/lib/src/prism/plugins/previewer-gradient/prism-previewer-gradient.js b/lib/src/prism/plugins/previewer-gradient/prism-previewer-gradient.js
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..11c2d0619e4ade3bde93ce094c81a8b4a0372f78
 | 
| --- /dev/null
 | 
| +++ b/lib/src/prism/plugins/previewer-gradient/prism-previewer-gradient.js
 | 
| @@ -0,0 +1,216 @@
 | 
| +(function() {
 | 
| +
 | 
| +	if (
 | 
| +		typeof self !== 'undefined' && !self.Prism ||
 | 
| +		typeof global !== 'undefined' && !global.Prism
 | 
| +	) {
 | 
| +		return;
 | 
| +	}
 | 
| +
 | 
| +	var languages = {
 | 
| +		'css': true,
 | 
| +		'less': true,
 | 
| +		'sass': [
 | 
| +			{
 | 
| +				lang: 'sass',
 | 
| +				before: 'punctuation',
 | 
| +				inside: 'inside',
 | 
| +				root: Prism.languages.sass && Prism.languages.sass['variable-line']
 | 
| +			},
 | 
| +			{
 | 
| +				lang: 'sass',
 | 
| +				before: 'punctuation',
 | 
| +				inside: 'inside',
 | 
| +				root: Prism.languages.sass && Prism.languages.sass['property-line']
 | 
| +			}
 | 
| +		],
 | 
| +		'scss': true,
 | 
| +		'stylus': [
 | 
| +			{
 | 
| +				lang: 'stylus',
 | 
| +				before: 'func',
 | 
| +				inside: 'rest',
 | 
| +				root: Prism.languages.stylus && Prism.languages.stylus['property-declaration'].inside
 | 
| +			},
 | 
| +			{
 | 
| +				lang: 'stylus',
 | 
| +				before: 'func',
 | 
| +				inside: 'rest',
 | 
| +				root: Prism.languages.stylus && Prism.languages.stylus['variable-declaration'].inside
 | 
| +			}
 | 
| +		]
 | 
| +	};
 | 
| +
 | 
| +	Prism.hooks.add('before-highlight', function (env) {
 | 
| +		if (env.language && languages[env.language] && !languages[env.language].initialized) {
 | 
| +			var lang = languages[env.language];
 | 
| +			if (Prism.util.type(lang) !== 'Array') {
 | 
| +				lang = [lang];
 | 
| +			}
 | 
| +			lang.forEach(function(lang) {
 | 
| +				var before, inside, root, skip;
 | 
| +				if (lang === true) {
 | 
| +					// Insert before color previewer if it exists
 | 
| +					before = Prism.plugins.Previewer && Prism.plugins.Previewer.byType['color'] ? 'color' : 'important';
 | 
| +					inside = env.language;
 | 
| +					lang = env.language;
 | 
| +				} else {
 | 
| +					before = lang.before || 'important';
 | 
| +					inside = lang.inside || lang.lang;
 | 
| +					root = lang.root || Prism.languages;
 | 
| +					skip = lang.skip;
 | 
| +					lang = env.language;
 | 
| +				}
 | 
| +
 | 
| +				if (!skip && Prism.languages[lang]) {
 | 
| +					Prism.languages.insertBefore(inside, before, {
 | 
| +						'gradient': {
 | 
| +							pattern: /(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\((?:(?:rgb|hsl)a?\(.+?\)|[^\)])+\)/gi,
 | 
| +							inside: {
 | 
| +								'function': /[\w-]+(?=\()/,
 | 
| +								'punctuation': /[(),]/
 | 
| +							}
 | 
| +						}
 | 
| +					}, root);
 | 
| +					env.grammar = Prism.languages[lang];
 | 
| +
 | 
| +					languages[env.language] = {initialized: true};
 | 
| +				}
 | 
| +			});
 | 
| +		}
 | 
| +	});
 | 
| +
 | 
| +	// Stores already processed gradients so that we don't
 | 
| +	// make the conversion every time the previewer is shown
 | 
| +	var cache = {};
 | 
| +
 | 
| +	/**
 | 
| +	 * Returns a W3C-valid linear gradient
 | 
| +	 * @param {string} prefix Vendor prefix if any ("-moz-", "-webkit-", etc.)
 | 
| +	 * @param {string} func Gradient function name ("linear-gradient")
 | 
| +	 * @param {string[]} values Array of the gradient function parameters (["0deg", "red 0%", "blue 100%"])
 | 
| +	 */
 | 
| +	var convertToW3CLinearGradient = function(prefix, func, values) {
 | 
| +		// Default value for angle
 | 
| +		var angle = '180deg';
 | 
| +
 | 
| +		if (/^(?:-?\d*\.?\d+(?:deg|rad)|to\b|top|right|bottom|left)/.test(values[0])) {
 | 
| +			angle = values.shift();
 | 
| +			if (angle.indexOf('to ') < 0) {
 | 
| +				// Angle uses old keywords
 | 
| +				// W3C syntax uses "to" + opposite keywords
 | 
| +				if (angle.indexOf('top') >= 0) {
 | 
| +					if (angle.indexOf('left') >= 0) {
 | 
| +						angle = 'to bottom right';
 | 
| +					} else if (angle.indexOf('right') >= 0) {
 | 
| +						angle = 'to bottom left';
 | 
| +					} else {
 | 
| +						angle = 'to bottom';
 | 
| +					}
 | 
| +				} else if (angle.indexOf('bottom') >= 0) {
 | 
| +					if (angle.indexOf('left') >= 0) {
 | 
| +						angle = 'to top right';
 | 
| +					} else if (angle.indexOf('right') >= 0) {
 | 
| +						angle = 'to top left';
 | 
| +					} else {
 | 
| +						angle = 'to top';
 | 
| +					}
 | 
| +				} else if (angle.indexOf('left') >= 0) {
 | 
| +					angle = 'to right';
 | 
| +				} else if (angle.indexOf('right') >= 0) {
 | 
| +					angle = 'to left';
 | 
| +				} else if (prefix) {
 | 
| +					// Angle is shifted by 90deg in prefixed gradients
 | 
| +					if (angle.indexOf('deg') >= 0) {
 | 
| +						angle = (90 - parseFloat(angle)) + 'deg';
 | 
| +					} else if (angle.indexOf('rad') >= 0) {
 | 
| +						angle = (Math.PI / 2 - parseFloat(angle)) + 'rad';
 | 
| +					}
 | 
| +				}
 | 
| +			}
 | 
| +		}
 | 
| +
 | 
| +		return func + '(' + angle + ',' + values.join(',') + ')';
 | 
| +	};
 | 
| +
 | 
| +	/**
 | 
| +	 * Returns a W3C-valid radial gradient
 | 
| +	 * @param {string} prefix Vendor prefix if any ("-moz-", "-webkit-", etc.)
 | 
| +	 * @param {string} func Gradient function name ("linear-gradient")
 | 
| +	 * @param {string[]} values Array of the gradient function parameters (["0deg", "red 0%", "blue 100%"])
 | 
| +	 */
 | 
| +	var convertToW3CRadialGradient = function(prefix, func, values) {
 | 
| +		if (values[0].indexOf('at') < 0) {
 | 
| +			// Looks like old syntax
 | 
| +
 | 
| +			// Default values
 | 
| +			var position = 'center';
 | 
| +			var shape = 'ellipse';
 | 
| +			var size = 'farthest-corner';
 | 
| +
 | 
| +			if (/\bcenter|top|right|bottom|left\b|^\d+/.test(values[0])) {
 | 
| +				// Found a position
 | 
| +				// Remove angle value, if any
 | 
| +				position = values.shift().replace(/\s*-?\d+(?:rad|deg)\s*/, '');
 | 
| +			}
 | 
| +			if (/\bcircle|ellipse|closest|farthest|contain|cover\b/.test(values[0])) {
 | 
| +				// Found a shape and/or size
 | 
| +				var shapeSizeParts = values.shift().split(/\s+/);
 | 
| +				if (shapeSizeParts[0] && (shapeSizeParts[0] === 'circle' || shapeSizeParts[0] === 'ellipse')) {
 | 
| +					shape = shapeSizeParts.shift();
 | 
| +				}
 | 
| +				if (shapeSizeParts[0]) {
 | 
| +					size = shapeSizeParts.shift();
 | 
| +				}
 | 
| +
 | 
| +				// Old keywords are converted to their synonyms
 | 
| +				if (size === 'cover') {
 | 
| +					size = 'farthest-corner';
 | 
| +				} else if (size === 'contain') {
 | 
| +					size = 'clothest-side';
 | 
| +				}
 | 
| +			}
 | 
| +
 | 
| +			return func + '(' + shape + ' ' + size + ' at ' + position + ',' + values.join(',') + ')';
 | 
| +		}
 | 
| +		return func + '(' + values.join(',') + ')';
 | 
| +	};
 | 
| +
 | 
| +	/**
 | 
| +	 * Converts a gradient to a W3C-valid one
 | 
| +	 * Does not support old webkit syntax (-webkit-gradient(linear...) and -webkit-gradient(radial...))
 | 
| +	 * @param {string} gradient The CSS gradient
 | 
| +	 */
 | 
| +	var convertToW3CGradient = function(gradient) {
 | 
| +		if (cache[gradient]) {
 | 
| +			return cache[gradient];
 | 
| +		}
 | 
| +		var parts = gradient.match(/^(\b|\B-[a-z]{1,10}-)((?:repeating-)?(?:linear|radial)-gradient)/);
 | 
| +		// "", "-moz-", etc.
 | 
| +		var prefix = parts && parts[1];
 | 
| +		// "linear-gradient", "radial-gradient", etc.
 | 
| +		var func = parts && parts[2];
 | 
| +
 | 
| +		var values = gradient.replace(/^(?:\b|\B-[a-z]{1,10}-)(?:repeating-)?(?:linear|radial)-gradient\(|\)$/g, '').split(/\s*,\s*/);
 | 
| +
 | 
| +		if (func.indexOf('linear') >= 0) {
 | 
| +			return cache[gradient] = convertToW3CLinearGradient(prefix, func, values);
 | 
| +		} else if (func.indexOf('radial') >= 0) {
 | 
| +			return cache[gradient] = convertToW3CRadialGradient(prefix, func, values);
 | 
| +		}
 | 
| +		return cache[gradient] = func + '(' + values.join(',') + ')';
 | 
| +	};
 | 
| +
 | 
| +
 | 
| +
 | 
| +	if (Prism.plugins.Previewer) {
 | 
| +		new Prism.plugins.Previewer('gradient', function(value) {
 | 
| +			this.firstChild.style.backgroundImage = '';
 | 
| +			this.firstChild.style.backgroundImage = convertToW3CGradient(value);
 | 
| +			return !!this.firstChild.style.backgroundImage;
 | 
| +		}, '*', function () {
 | 
| +			this._elt.innerHTML = '<div></div>';
 | 
| +		});
 | 
| +	}
 | 
| +
 | 
| +}());
 | 
| 
 |