Source: colors.js

/**
 * colors.js is part of Aloha Editor project http://aloha-editor.org
 *
 * Aloha Editor is a WYSIWYG HTML5 inline editing library and editor.
 * Copyright (c) 2010-2014 Gentics Software GmbH, Vienna, Austria.
 * Contributors http://aloha-editor.org/contribution.php
 */
define([
	'dom',
	'ranges',
	'editing'
], /** @exports Colors */ function Colors(
	Dom,
	Ranges,
	Editing
) {
	'use strict';

	var COLOR_PREFIX = /^(#|rgba?|hsl)\(?([^\(\)]+)/i;
	var COMMA = /\s*,\s*/;

	/**
	 * Normalizes hexidecimal colors from
	 * #f34 to #ff3344
	 *
	 * @param  {string} color
	 * @return {string} Long version of hexidecimal color value
	 */
	function normalizeHex(color) {
		if (7 === color.length) {
			return color;
		}
		var r = color.substr(1, 1);
		var g = color.substr(2, 1);
		var b = color.substr(3, 1);
		return '#' + r + r + g + g + b + b;
	}

	/**
	 * Converts rgb color array to a hex color string.
	 *
	 * @param  {Array.<string>} rgb
	 * @return {string}
	 */
	function rgb2hex(rgb) {
		var r = parseInt(rgb[0], 10).toString(16);
		var g = parseInt(rgb[1], 10).toString(16);
		var b = parseInt(rgb[2], 10).toString(16);
		if (1 === r.length) {
			r += r;
		}
		if (1 === g.length) {
			g += g;
		}
		if (1 === b.length) {
			b += b;
		}
		return '#' + r + g + b;
	}

	/**
	 * Given a color string will normalize it to a hex color string.
	 *
	 * @param  {string} value
	 * @return {string}
	 */
	function hex(value) {
		var color = value.match(COLOR_PREFIX);
		switch (color && color[1]) {
		case '#':
			return normalizeHex(color[0]);
		case 'rgb':
		case 'rgba':
			return rgb2hex(color[2].split(COMMA));
		default:
			return null;
		}
	}

	/**
	 * Checks whether the two given colors are equal in value (if not in
	 * representation).
	 *
	 * isColorEqual('#f00', 'rgb(255,0,0)') === true
	 *
	 * @param  {string} colorA
	 * @param  {string} colorB
	 * @return {boolean}
	 */
	function isColorEqual(colorA, colorB) {
		return (
			(null == colorA || null == colorB)
				? colorA === colorB
				: hex(colorA) === hex(colorB)
		);
	}

	/**
	 * Gets the style of the start container of the given range.
	 *
	 * @param  {Range}  range
	 * @param  {string} property
	 * @return {string} Style value
	 */
	function getStyle(range, property) {
		var node = Dom.nodeAtOffset(range.startContainer, range.startOffset);
		return Dom.getComputedStyle(
			Dom.isTextNode(node) ? node.parentNode : node,
			property
		);
	}

	/**
	 * Gets the text color at the given range.
	 *
	 * @param  {Range}  range
	 * @return {string} Style color string
	 */
	function getTextColor(range) {
		return getStyle(range, 'color');
	}

	/**
	 * Sets the text color at the given range.
	 *
	 * @param {Range}  range
	 * @param {string} color
	 */
	function setTextColor(range, color) {
		Editing.format(range, 'color', color, isColorEqual);
	}

	/**
	 * Removes the text color at the given range.
	 *
	 * @param {Range} range
	 */
	function unsetTextColor(range) {
		var editable = Ranges.nearestEditingHost(range);
		if (editable) {
			setTextColor(range, Dom.getComputedStyle(editable, 'color'));
		}
	}

	/**
	 * Gets the background color at the given range.
	 *
	 * @param  {Range}  range
	 * @return {string} Style color string
	 */
	function getBackgroundColor(range) {
		return getStyle(range, 'background-color');
	}

	/**
	 * Sets the background color at the given range.
	 *
	 * @param {Range}  range
	 * @param {string} color
	 */
	function setBackgroundColor(range, color) {
		Editing.format(range, 'background-color', color, isColorEqual);
	}

	/**
	 * Removes the background color at the given range.
	 *
	 * @param {Range} range
	 */
	function unsetBackgroundColor(range) {
		var editable = Ranges.nearestEditingHost(range);
		if (editable) {
			setBackgroundColor(range, Dom.getComputedStyle(editable, 'background-color'));
		}
	}

	return {
		hex                  : hex,
		getTextColor         : getTextColor,
		setTextColor         : setTextColor,
		unsetTextColor       : unsetTextColor,
		getBackgroundColor   : getBackgroundColor,
		setBackgroundColor   : setBackgroundColor,
		unsetBackgroundColor : unsetBackgroundColor
	};
});