gallery/app/assets/javascripts/jquery.minicolors.js

1128 lines
34 KiB
JavaScript

//
// jQuery MiniColors: A tiny color picker built on jQuery
//
// Developed by Cory LaViska for A Beautiful Site, LLC
//
// Licensed under the MIT license: http://opensource.org/licenses/MIT
//
(function (factory) {
if(typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if(typeof exports === 'object') {
// Node/CommonJS
module.exports = factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
'use strict';
// Defaults
$.minicolors = {
defaults: {
animationSpeed: 50,
animationEasing: 'swing',
change: null,
changeDelay: 0,
control: 'hue',
defaultValue: '',
format: 'hex',
hide: null,
hideSpeed: 100,
inline: false,
keywords: '',
letterCase: 'lowercase',
opacity: false,
position: 'bottom',
show: null,
showSpeed: 100,
theme: 'default',
swatches: []
}
};
// Public methods
$.extend($.fn, {
minicolors: function(method, data) {
switch(method) {
// Destroy the control
case 'destroy':
$(this).each(function() {
destroy($(this));
});
return $(this);
// Hide the color picker
case 'hide':
hide();
return $(this);
// Get/set opacity
case 'opacity':
// Getter
if(data === undefined) {
// Getter
return $(this).attr('data-opacity');
} else {
// Setter
$(this).each(function() {
updateFromInput($(this).attr('data-opacity', data));
});
}
return $(this);
// Get an RGB(A) object based on the current color/opacity
case 'rgbObject':
return rgbObject($(this), method === 'rgbaObject');
// Get an RGB(A) string based on the current color/opacity
case 'rgbString':
case 'rgbaString':
return rgbString($(this), method === 'rgbaString');
// Get/set settings on the fly
case 'settings':
if(data === undefined) {
return $(this).data('minicolors-settings');
} else {
// Setter
$(this).each(function() {
var settings = $(this).data('minicolors-settings') || {};
destroy($(this));
$(this).minicolors($.extend(true, settings, data));
});
}
return $(this);
// Show the color picker
case 'show':
show($(this).eq(0));
return $(this);
// Get/set the hex color value
case 'value':
if(data === undefined) {
// Getter
return $(this).val();
} else {
// Setter
$(this).each(function() {
if(typeof(data) === 'object' && data !== null) {
if(data.opacity !== undefined) {
$(this).attr('data-opacity', keepWithin(data.opacity, 0, 1));
}
if(data.color) {
$(this).val(data.color);
}
} else {
$(this).val(data);
}
updateFromInput($(this));
});
}
return $(this);
// Initializes the control
default:
if(method !== 'create') data = method;
$(this).each(function() {
init($(this), data);
});
return $(this);
}
}
});
// Initialize input elements
function init(input, settings) {
var minicolors = $('<div class="minicolors" />');
var defaults = $.minicolors.defaults;
var name;
var size;
var swatches;
var swatch;
var swatchString;
var panel;
var i;
// Do nothing if already initialized
if(input.data('minicolors-initialized')) return;
// Handle settings
settings = $.extend(true, {}, defaults, settings);
// The wrapper
minicolors
.addClass('minicolors-theme-' + settings.theme)
.toggleClass('minicolors-with-opacity', settings.opacity);
// Custom positioning
if(settings.position !== undefined) {
$.each(settings.position.split(' '), function() {
minicolors.addClass('minicolors-position-' + this);
});
}
// Input size
if(settings.format === 'rgb') {
size = settings.opacity ? '25' : '20';
} else {
size = settings.keywords ? '11' : '7';
}
// The input
input
.addClass('minicolors-input')
.data('minicolors-initialized', false)
.data('minicolors-settings', settings)
.prop('size', size)
.wrap(minicolors)
.after(
'<div class="minicolors-panel minicolors-slider-' + settings.control + '">' +
'<div class="minicolors-slider minicolors-sprite">' +
'<div class="minicolors-picker"></div>' +
'</div>' +
'<div class="minicolors-opacity-slider minicolors-sprite">' +
'<div class="minicolors-picker"></div>' +
'</div>' +
'<div class="minicolors-grid minicolors-sprite">' +
'<div class="minicolors-grid-inner"></div>' +
'<div class="minicolors-picker"><div></div></div>' +
'</div>' +
'</div>'
);
// The swatch
if(!settings.inline) {
input.after('<span class="minicolors-swatch minicolors-sprite minicolors-input-swatch"><span class="minicolors-swatch-color"></span></span>');
input.next('.minicolors-input-swatch').on('click', function(event) {
event.preventDefault();
input.focus();
});
}
// Prevent text selection in IE
panel = input.parent().find('.minicolors-panel');
panel.on('selectstart', function() { return false; }).end();
// Swatches
if(settings.swatches && settings.swatches.length !== 0) {
panel.addClass('minicolors-with-swatches');
swatches = $('<ul class="minicolors-swatches"></ul>')
.appendTo(panel);
for(i = 0; i < settings.swatches.length; ++i) {
// allow for custom objects as swatches
if($.type(settings.swatches[i]) === 'object') {
name = settings.swatches[i].name;
swatch = settings.swatches[i].color;
} else {
name = '';
swatch = settings.swatches[i];
}
swatchString = swatch;
swatch = isRgb(swatch) ? parseRgb(swatch, true) : hex2rgb(parseHex(swatch, true));
$('<li class="minicolors-swatch minicolors-sprite"><span class="minicolors-swatch-color" title="' + name + '"></span></li>')
.appendTo(swatches)
.data('swatch-color', swatchString)
.find('.minicolors-swatch-color')
.css({
backgroundColor: rgb2hex(swatch),
opacity: swatch.a
});
settings.swatches[i] = swatch;
}
}
// Inline controls
if(settings.inline) input.parent().addClass('minicolors-inline');
updateFromInput(input, false);
input.data('minicolors-initialized', true);
}
// Returns the input back to its original state
function destroy(input) {
var minicolors = input.parent();
// Revert the input element
input
.removeData('minicolors-initialized')
.removeData('minicolors-settings')
.removeProp('size')
.removeClass('minicolors-input');
// Remove the wrap and destroy whatever remains
minicolors.before(input).remove();
}
// Shows the specified dropdown panel
function show(input) {
var minicolors = input.parent();
var panel = minicolors.find('.minicolors-panel');
var settings = input.data('minicolors-settings');
// Do nothing if uninitialized, disabled, inline, or already open
if(
!input.data('minicolors-initialized') ||
input.prop('disabled') ||
minicolors.hasClass('minicolors-inline') ||
minicolors.hasClass('minicolors-focus')
) return;
hide();
minicolors.addClass('minicolors-focus');
if (panel.animate) {
panel
.stop(true, true)
.fadeIn(settings.showSpeed, function () {
if (settings.show) settings.show.call(input.get(0));
});
} else {
panel.show();
if (settings.show) settings.show.call(input.get(0));
}
}
// Hides all dropdown panels
function hide() {
$('.minicolors-focus').each(function() {
var minicolors = $(this);
var input = minicolors.find('.minicolors-input');
var panel = minicolors.find('.minicolors-panel');
var settings = input.data('minicolors-settings');
if (panel.animate) {
panel.fadeOut(settings.hideSpeed, function () {
if (settings.hide) settings.hide.call(input.get(0));
minicolors.removeClass('minicolors-focus');
});
} else {
panel.hide();
if (settings.hide) settings.hide.call(input.get(0));
minicolors.removeClass('minicolors-focus');
}
});
}
// Moves the selected picker
function move(target, event, animate) {
var input = target.parents('.minicolors').find('.minicolors-input');
var settings = input.data('minicolors-settings');
var picker = target.find('[class$=-picker]');
var offsetX = target.offset().left;
var offsetY = target.offset().top;
var x = Math.round(event.pageX - offsetX);
var y = Math.round(event.pageY - offsetY);
var duration = animate ? settings.animationSpeed : 0;
var wx, wy, r, phi, styles;
// Touch support
if(event.originalEvent.changedTouches) {
x = event.originalEvent.changedTouches[0].pageX - offsetX;
y = event.originalEvent.changedTouches[0].pageY - offsetY;
}
// Constrain picker to its container
if(x < 0) x = 0;
if(y < 0) y = 0;
if(x > target.width()) x = target.width();
if(y > target.height()) y = target.height();
// Constrain color wheel values to the wheel
if(target.parent().is('.minicolors-slider-wheel') && picker.parent().is('.minicolors-grid')) {
wx = 75 - x;
wy = 75 - y;
r = Math.sqrt(wx * wx + wy * wy);
phi = Math.atan2(wy, wx);
if(phi < 0) phi += Math.PI * 2;
if(r > 75) {
r = 75;
x = 75 - (75 * Math.cos(phi));
y = 75 - (75 * Math.sin(phi));
}
x = Math.round(x);
y = Math.round(y);
}
// Move the picker
styles = {
top: y + 'px'
};
if(target.is('.minicolors-grid')) {
styles.left = x + 'px';
}
if (picker.animate) {
picker
.stop(true)
.animate(styles, duration, settings.animationEasing, function() {
updateFromControl(input, target);
});
} else {
picker
.css(styles);
updateFromControl(input, target);
}
}
// Sets the input based on the color picker values
function updateFromControl(input, target) {
function getCoords(picker, container) {
var left, top;
if(!picker.length || !container) return null;
left = picker.offset().left;
top = picker.offset().top;
return {
x: left - container.offset().left + (picker.outerWidth() / 2),
y: top - container.offset().top + (picker.outerHeight() / 2)
};
}
var hue, saturation, brightness, x, y, r, phi;
var hex = input.val();
var opacity = input.attr('data-opacity');
// Helpful references
var minicolors = input.parent();
var settings = input.data('minicolors-settings');
var swatch = minicolors.find('.minicolors-input-swatch');
// Panel objects
var grid = minicolors.find('.minicolors-grid');
var slider = minicolors.find('.minicolors-slider');
var opacitySlider = minicolors.find('.minicolors-opacity-slider');
// Picker objects
var gridPicker = grid.find('[class$=-picker]');
var sliderPicker = slider.find('[class$=-picker]');
var opacityPicker = opacitySlider.find('[class$=-picker]');
// Picker positions
var gridPos = getCoords(gridPicker, grid);
var sliderPos = getCoords(sliderPicker, slider);
var opacityPos = getCoords(opacityPicker, opacitySlider);
// Handle colors
if(target.is('.minicolors-grid, .minicolors-slider, .minicolors-opacity-slider')) {
// Determine HSB values
switch(settings.control) {
case 'wheel':
// Calculate hue, saturation, and brightness
x = (grid.width() / 2) - gridPos.x;
y = (grid.height() / 2) - gridPos.y;
r = Math.sqrt(x * x + y * y);
phi = Math.atan2(y, x);
if(phi < 0) phi += Math.PI * 2;
if(r > 75) {
r = 75;
gridPos.x = 69 - (75 * Math.cos(phi));
gridPos.y = 69 - (75 * Math.sin(phi));
}
saturation = keepWithin(r / 0.75, 0, 100);
hue = keepWithin(phi * 180 / Math.PI, 0, 360);
brightness = keepWithin(100 - Math.floor(sliderPos.y * (100 / slider.height())), 0, 100);
hex = hsb2hex({
h: hue,
s: saturation,
b: brightness
});
// Update UI
slider.css('backgroundColor', hsb2hex({ h: hue, s: saturation, b: 100 }));
break;
case 'saturation':
// Calculate hue, saturation, and brightness
hue = keepWithin(parseInt(gridPos.x * (360 / grid.width()), 10), 0, 360);
saturation = keepWithin(100 - Math.floor(sliderPos.y * (100 / slider.height())), 0, 100);
brightness = keepWithin(100 - Math.floor(gridPos.y * (100 / grid.height())), 0, 100);
hex = hsb2hex({
h: hue,
s: saturation,
b: brightness
});
// Update UI
slider.css('backgroundColor', hsb2hex({ h: hue, s: 100, b: brightness }));
minicolors.find('.minicolors-grid-inner').css('opacity', saturation / 100);
break;
case 'brightness':
// Calculate hue, saturation, and brightness
hue = keepWithin(parseInt(gridPos.x * (360 / grid.width()), 10), 0, 360);
saturation = keepWithin(100 - Math.floor(gridPos.y * (100 / grid.height())), 0, 100);
brightness = keepWithin(100 - Math.floor(sliderPos.y * (100 / slider.height())), 0, 100);
hex = hsb2hex({
h: hue,
s: saturation,
b: brightness
});
// Update UI
slider.css('backgroundColor', hsb2hex({ h: hue, s: saturation, b: 100 }));
minicolors.find('.minicolors-grid-inner').css('opacity', 1 - (brightness / 100));
break;
default:
// Calculate hue, saturation, and brightness
hue = keepWithin(360 - parseInt(sliderPos.y * (360 / slider.height()), 10), 0, 360);
saturation = keepWithin(Math.floor(gridPos.x * (100 / grid.width())), 0, 100);
brightness = keepWithin(100 - Math.floor(gridPos.y * (100 / grid.height())), 0, 100);
hex = hsb2hex({
h: hue,
s: saturation,
b: brightness
});
// Update UI
grid.css('backgroundColor', hsb2hex({ h: hue, s: 100, b: 100 }));
break;
}
// Handle opacity
if(settings.opacity) {
opacity = parseFloat(1 - (opacityPos.y / opacitySlider.height())).toFixed(2);
} else {
opacity = 1;
}
updateInput(input, hex, opacity);
}
else {
// Set swatch color
swatch.find('span').css({
backgroundColor: hex,
opacity: opacity
});
// Handle change event
doChange(input, hex, opacity);
}
}
// Sets the value of the input and does the appropriate conversions
// to respect settings, also updates the swatch
function updateInput(input, value, opacity) {
var rgb;
// Helpful references
var minicolors = input.parent();
var settings = input.data('minicolors-settings');
var swatch = minicolors.find('.minicolors-input-swatch');
if(settings.opacity) input.attr('data-opacity', opacity);
// Set color string
if(settings.format === 'rgb') {
// Returns RGB(A) string
// Checks for input format and does the conversion
if(isRgb(value)) {
rgb = parseRgb(value, true);
}
else {
rgb = hex2rgb(parseHex(value, true));
}
opacity = input.attr('data-opacity') === '' ? 1 : keepWithin(parseFloat(input.attr('data-opacity')).toFixed(2), 0, 1);
if(isNaN(opacity) || !settings.opacity) opacity = 1;
if(input.minicolors('rgbObject').a <= 1 && rgb && settings.opacity) {
// Set RGBA string if alpha
value = 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + parseFloat(opacity) + ')';
} else {
// Set RGB string (alpha = 1)
value = 'rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')';
}
} else {
// Returns hex color
// Checks for input format and does the conversion
if(isRgb(value)) {
value = rgbString2hex(value);
}
value = convertCase(value, settings.letterCase);
}
// Update value from picker
input.val(value);
// Set swatch color
swatch.find('span').css({
backgroundColor: value,
opacity: opacity
});
// Handle change event
doChange(input, value, opacity);
}
// Sets the color picker values from the input
function updateFromInput(input, preserveInputValue) {
var hex, hsb, opacity, keywords, alpha, value, x, y, r, phi;
// Helpful references
var minicolors = input.parent();
var settings = input.data('minicolors-settings');
var swatch = minicolors.find('.minicolors-input-swatch');
// Panel objects
var grid = minicolors.find('.minicolors-grid');
var slider = minicolors.find('.minicolors-slider');
var opacitySlider = minicolors.find('.minicolors-opacity-slider');
// Picker objects
var gridPicker = grid.find('[class$=-picker]');
var sliderPicker = slider.find('[class$=-picker]');
var opacityPicker = opacitySlider.find('[class$=-picker]');
// Determine hex/HSB values
if(isRgb(input.val())) {
// If input value is a rgb(a) string, convert it to hex color and update opacity
hex = rgbString2hex(input.val());
alpha = keepWithin(parseFloat(getAlpha(input.val())).toFixed(2), 0, 1);
if(alpha) {
input.attr('data-opacity', alpha);
}
} else {
hex = convertCase(parseHex(input.val(), true), settings.letterCase);
}
if(!hex){
hex = convertCase(parseInput(settings.defaultValue, true), settings.letterCase);
}
hsb = hex2hsb(hex);
// Get array of lowercase keywords
keywords = !settings.keywords ? [] : $.map(settings.keywords.split(','), function(a) {
return $.trim(a.toLowerCase());
});
// Set color string
if(input.val() !== '' && $.inArray(input.val().toLowerCase(), keywords) > -1) {
value = convertCase(input.val());
} else {
value = isRgb(input.val()) ? parseRgb(input.val()) : hex;
}
// Update input value
if(!preserveInputValue) input.val(value);
// Determine opacity value
if(settings.opacity) {
// Get from data-opacity attribute and keep within 0-1 range
opacity = input.attr('data-opacity') === '' ? 1 : keepWithin(parseFloat(input.attr('data-opacity')).toFixed(2), 0, 1);
if(isNaN(opacity)) opacity = 1;
input.attr('data-opacity', opacity);
swatch.find('span').css('opacity', opacity);
// Set opacity picker position
y = keepWithin(opacitySlider.height() - (opacitySlider.height() * opacity), 0, opacitySlider.height());
opacityPicker.css('top', y + 'px');
}
// Set opacity to zero if input value is transparent
if(input.val().toLowerCase() === 'transparent') {
swatch.find('span').css('opacity', 0);
}
// Update swatch
swatch.find('span').css('backgroundColor', hex);
// Determine picker locations
switch(settings.control) {
case 'wheel':
// Set grid position
r = keepWithin(Math.ceil(hsb.s * 0.75), 0, grid.height() / 2);
phi = hsb.h * Math.PI / 180;
x = keepWithin(75 - Math.cos(phi) * r, 0, grid.width());
y = keepWithin(75 - Math.sin(phi) * r, 0, grid.height());
gridPicker.css({
top: y + 'px',
left: x + 'px'
});
// Set slider position
y = 150 - (hsb.b / (100 / grid.height()));
if(hex === '') y = 0;
sliderPicker.css('top', y + 'px');
// Update panel color
slider.css('backgroundColor', hsb2hex({ h: hsb.h, s: hsb.s, b: 100 }));
break;
case 'saturation':
// Set grid position
x = keepWithin((5 * hsb.h) / 12, 0, 150);
y = keepWithin(grid.height() - Math.ceil(hsb.b / (100 / grid.height())), 0, grid.height());
gridPicker.css({
top: y + 'px',
left: x + 'px'
});
// Set slider position
y = keepWithin(slider.height() - (hsb.s * (slider.height() / 100)), 0, slider.height());
sliderPicker.css('top', y + 'px');
// Update UI
slider.css('backgroundColor', hsb2hex({ h: hsb.h, s: 100, b: hsb.b }));
minicolors.find('.minicolors-grid-inner').css('opacity', hsb.s / 100);
break;
case 'brightness':
// Set grid position
x = keepWithin((5 * hsb.h) / 12, 0, 150);
y = keepWithin(grid.height() - Math.ceil(hsb.s / (100 / grid.height())), 0, grid.height());
gridPicker.css({
top: y + 'px',
left: x + 'px'
});
// Set slider position
y = keepWithin(slider.height() - (hsb.b * (slider.height() / 100)), 0, slider.height());
sliderPicker.css('top', y + 'px');
// Update UI
slider.css('backgroundColor', hsb2hex({ h: hsb.h, s: hsb.s, b: 100 }));
minicolors.find('.minicolors-grid-inner').css('opacity', 1 - (hsb.b / 100));
break;
default:
// Set grid position
x = keepWithin(Math.ceil(hsb.s / (100 / grid.width())), 0, grid.width());
y = keepWithin(grid.height() - Math.ceil(hsb.b / (100 / grid.height())), 0, grid.height());
gridPicker.css({
top: y + 'px',
left: x + 'px'
});
// Set slider position
y = keepWithin(slider.height() - (hsb.h / (360 / slider.height())), 0, slider.height());
sliderPicker.css('top', y + 'px');
// Update panel color
grid.css('backgroundColor', hsb2hex({ h: hsb.h, s: 100, b: 100 }));
break;
}
// Fire change event, but only if minicolors is fully initialized
if(input.data('minicolors-initialized')) {
doChange(input, value, opacity);
}
}
// Runs the change and changeDelay callbacks
function doChange(input, value, opacity) {
var settings = input.data('minicolors-settings');
var lastChange = input.data('minicolors-lastChange');
var obj, sel, i;
// Only run if it actually changed
if(!lastChange || lastChange.value !== value || lastChange.opacity !== opacity) {
// Remember last-changed value
input.data('minicolors-lastChange', {
value: value,
opacity: opacity
});
// Check and select applicable swatch
if(settings.swatches && settings.swatches.length !== 0) {
if(!isRgb(value)) {
obj = hex2rgb(value);
}
else {
obj = parseRgb(value, true);
}
sel = -1;
for(i = 0; i < settings.swatches.length; ++i) {
if(obj.r === settings.swatches[i].r && obj.g === settings.swatches[i].g && obj.b === settings.swatches[i].b && obj.a === settings.swatches[i].a) {
sel = i;
break;
}
}
input.parent().find('.minicolors-swatches .minicolors-swatch').removeClass('selected');
if(sel !== -1) {
input.parent().find('.minicolors-swatches .minicolors-swatch').eq(i).addClass('selected');
}
}
// Fire change event
if(settings.change) {
if(settings.changeDelay) {
// Call after a delay
clearTimeout(input.data('minicolors-changeTimeout'));
input.data('minicolors-changeTimeout', setTimeout(function() {
settings.change.call(input.get(0), value, opacity);
}, settings.changeDelay));
} else {
// Call immediately
settings.change.call(input.get(0), value, opacity);
}
}
input.trigger('change').trigger('input');
}
}
// Generates an RGB(A) object based on the input's value
function rgbObject(input) {
var rgb,
opacity = $(input).attr('data-opacity');
if( isRgb($(input).val()) ) {
rgb = parseRgb($(input).val(), true);
} else {
var hex = parseHex($(input).val(), true);
rgb = hex2rgb(hex);
}
if( !rgb ) return null;
if( opacity !== undefined ) $.extend(rgb, { a: parseFloat(opacity) });
return rgb;
}
// Generates an RGB(A) string based on the input's value
function rgbString(input, alpha) {
var rgb,
opacity = $(input).attr('data-opacity');
if( isRgb($(input).val()) ) {
rgb = parseRgb($(input).val(), true);
} else {
var hex = parseHex($(input).val(), true);
rgb = hex2rgb(hex);
}
if( !rgb ) return null;
if( opacity === undefined ) opacity = 1;
if( alpha ) {
return 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + parseFloat(opacity) + ')';
} else {
return 'rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')';
}
}
// Converts to the letter case specified in settings
function convertCase(string, letterCase) {
return letterCase === 'uppercase' ? string.toUpperCase() : string.toLowerCase();
}
// Parses a string and returns a valid hex string when possible
function parseHex(string, expand) {
string = string.replace(/^#/g, '');
if(!string.match(/^[A-F0-9]{3,6}/ig)) return '';
if(string.length !== 3 && string.length !== 6) return '';
if(string.length === 3 && expand) {
string = string[0] + string[0] + string[1] + string[1] + string[2] + string[2];
}
return '#' + string;
}
// Parses a string and returns a valid RGB(A) string when possible
function parseRgb(string, obj) {
var values = string.replace(/[^\d,.]/g, '');
var rgba = values.split(',');
rgba[0] = keepWithin(parseInt(rgba[0], 10), 0, 255);
rgba[1] = keepWithin(parseInt(rgba[1], 10), 0, 255);
rgba[2] = keepWithin(parseInt(rgba[2], 10), 0, 255);
if(rgba[3] !== undefined) {
rgba[3] = keepWithin(parseFloat(rgba[3], 10), 0, 1);
}
// Return RGBA object
if( obj ) {
if (rgba[3] !== undefined) {
return {
r: rgba[0],
g: rgba[1],
b: rgba[2],
a: rgba[3]
};
} else {
return {
r: rgba[0],
g: rgba[1],
b: rgba[2]
};
}
}
// Return RGBA string
if(typeof(rgba[3]) !== 'undefined' && rgba[3] <= 1) {
return 'rgba(' + rgba[0] + ', ' + rgba[1] + ', ' + rgba[2] + ', ' + rgba[3] + ')';
} else {
return 'rgb(' + rgba[0] + ', ' + rgba[1] + ', ' + rgba[2] + ')';
}
}
// Parses a string and returns a valid color string when possible
function parseInput(string, expand) {
if(isRgb(string)) {
// Returns a valid rgb(a) string
return parseRgb(string);
} else {
return parseHex(string, expand);
}
}
// Keeps value within min and max
function keepWithin(value, min, max) {
if(value < min) value = min;
if(value > max) value = max;
return value;
}
// Checks if a string is a valid RGB(A) string
function isRgb(string) {
var rgb = string.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
return (rgb && rgb.length === 4) ? true : false;
}
// Function to get alpha from a RGB(A) string
function getAlpha(rgba) {
rgba = rgba.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+(\.\d{1,2})?|\.\d{1,2})[\s+]?/i);
return (rgba && rgba.length === 6) ? rgba[4] : '1';
}
// Converts an HSB object to an RGB object
function hsb2rgb(hsb) {
var rgb = {};
var h = Math.round(hsb.h);
var s = Math.round(hsb.s * 255 / 100);
var v = Math.round(hsb.b * 255 / 100);
if(s === 0) {
rgb.r = rgb.g = rgb.b = v;
} else {
var t1 = v;
var t2 = (255 - s) * v / 255;
var t3 = (t1 - t2) * (h % 60) / 60;
if(h === 360) h = 0;
if(h < 60) { rgb.r = t1; rgb.b = t2; rgb.g = t2 + t3; }
else if(h < 120) {rgb.g = t1; rgb.b = t2; rgb.r = t1 - t3; }
else if(h < 180) {rgb.g = t1; rgb.r = t2; rgb.b = t2 + t3; }
else if(h < 240) {rgb.b = t1; rgb.r = t2; rgb.g = t1 - t3; }
else if(h < 300) {rgb.b = t1; rgb.g = t2; rgb.r = t2 + t3; }
else if(h < 360) {rgb.r = t1; rgb.g = t2; rgb.b = t1 - t3; }
else { rgb.r = 0; rgb.g = 0; rgb.b = 0; }
}
return {
r: Math.round(rgb.r),
g: Math.round(rgb.g),
b: Math.round(rgb.b)
};
}
// Converts an RGB string to a hex string
function rgbString2hex(rgb){
rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
return (rgb && rgb.length === 4) ? '#' +
('0' + parseInt(rgb[1],10).toString(16)).slice(-2) +
('0' + parseInt(rgb[2],10).toString(16)).slice(-2) +
('0' + parseInt(rgb[3],10).toString(16)).slice(-2) : '';
}
// Converts an RGB object to a hex string
function rgb2hex(rgb) {
var hex = [
rgb.r.toString(16),
rgb.g.toString(16),
rgb.b.toString(16)
];
$.each(hex, function(nr, val) {
if(val.length === 1) hex[nr] = '0' + val;
});
return '#' + hex.join('');
}
// Converts an HSB object to a hex string
function hsb2hex(hsb) {
return rgb2hex(hsb2rgb(hsb));
}
// Converts a hex string to an HSB object
function hex2hsb(hex) {
var hsb = rgb2hsb(hex2rgb(hex));
if(hsb.s === 0) hsb.h = 360;
return hsb;
}
// Converts an RGB object to an HSB object
function rgb2hsb(rgb) {
var hsb = { h: 0, s: 0, b: 0 };
var min = Math.min(rgb.r, rgb.g, rgb.b);
var max = Math.max(rgb.r, rgb.g, rgb.b);
var delta = max - min;
hsb.b = max;
hsb.s = max !== 0 ? 255 * delta / max : 0;
if(hsb.s !== 0) {
if(rgb.r === max) {
hsb.h = (rgb.g - rgb.b) / delta;
} else if(rgb.g === max) {
hsb.h = 2 + (rgb.b - rgb.r) / delta;
} else {
hsb.h = 4 + (rgb.r - rgb.g) / delta;
}
} else {
hsb.h = -1;
}
hsb.h *= 60;
if(hsb.h < 0) {
hsb.h += 360;
}
hsb.s *= 100/255;
hsb.b *= 100/255;
return hsb;
}
// Converts a hex string to an RGB object
function hex2rgb(hex) {
hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);
return {
r: hex >> 16,
g: (hex & 0x00FF00) >> 8,
b: (hex & 0x0000FF)
};
}
// Handle events
$([document])
// Hide on clicks outside of the control
.on('mousedown.minicolors touchstart.minicolors', function(event) {
if(!$(event.target).parents().add(event.target).hasClass('minicolors')) {
hide();
}
})
// Start moving
.on('mousedown.minicolors touchstart.minicolors', '.minicolors-grid, .minicolors-slider, .minicolors-opacity-slider', function(event) {
var target = $(this);
event.preventDefault();
$(event.delegateTarget).data('minicolors-target', target);
move(target, event, true);
})
// Move pickers
.on('mousemove.minicolors touchmove.minicolors', function(event) {
var target = $(event.delegateTarget).data('minicolors-target');
if(target) move(target, event);
})
// Stop moving
.on('mouseup.minicolors touchend.minicolors', function() {
$(this).removeData('minicolors-target');
})
// Selected a swatch
.on('click.minicolors', '.minicolors-swatches li', function(event) {
event.preventDefault();
var target = $(this), input = target.parents('.minicolors').find('.minicolors-input'), color = target.data('swatch-color');
updateInput(input, color, getAlpha(color));
updateFromInput(input);
})
// Show panel when swatch is clicked
.on('mousedown.minicolors touchstart.minicolors', '.minicolors-input-swatch', function(event) {
var input = $(this).parent().find('.minicolors-input');
event.preventDefault();
show(input);
})
// Show on focus
.on('focus.minicolors', '.minicolors-input', function() {
var input = $(this);
if(!input.data('minicolors-initialized')) return;
show(input);
})
// Update value on blur
.on('blur.minicolors', '.minicolors-input', function() {
var input = $(this);
var settings = input.data('minicolors-settings');
var keywords;
var hex;
var rgba;
var swatchOpacity;
var value;
if(!input.data('minicolors-initialized')) return;
// Get array of lowercase keywords
keywords = !settings.keywords ? [] : $.map(settings.keywords.split(','), function(a) {
return $.trim(a.toLowerCase());
});
// Set color string
if(input.val() !== '' && $.inArray(input.val().toLowerCase(), keywords) > -1) {
value = input.val();
} else {
// Get RGBA values for easy conversion
if(isRgb(input.val())) {
rgba = parseRgb(input.val(), true);
} else {
hex = parseHex(input.val(), true);
rgba = hex ? hex2rgb(hex) : null;
}
// Convert to format
if(rgba === null) {
value = settings.defaultValue;
} else if(settings.format === 'rgb') {
value = settings.opacity ?
parseRgb('rgba(' + rgba.r + ',' + rgba.g + ',' + rgba.b + ',' + input.attr('data-opacity') + ')') :
parseRgb('rgb(' + rgba.r + ',' + rgba.g + ',' + rgba.b + ')');
} else {
value = rgb2hex(rgba);
}
}
// Update swatch opacity
swatchOpacity = settings.opacity ? input.attr('data-opacity') : 1;
if(value.toLowerCase() === 'transparent') swatchOpacity = 0;
input
.closest('.minicolors')
.find('.minicolors-input-swatch > span')
.css('opacity', swatchOpacity);
// Set input value
input.val(value);
// Is it blank?
if(input.val() === '') input.val(parseInput(settings.defaultValue, true));
// Adjust case
input.val(convertCase(input.val(), settings.letterCase));
})
// Handle keypresses
.on('keydown.minicolors', '.minicolors-input', function(event) {
var input = $(this);
if(!input.data('minicolors-initialized')) return;
switch(event.which) {
case 9: // tab
hide();
break;
case 13: // enter
case 27: // esc
hide();
input.blur();
break;
}
})
// Update on keyup
.on('keyup.minicolors', '.minicolors-input', function() {
var input = $(this);
if(!input.data('minicolors-initialized')) return;
updateFromInput(input, true);
})
// Update on paste
.on('paste.minicolors', '.minicolors-input', function() {
var input = $(this);
if(!input.data('minicolors-initialized')) return;
setTimeout(function() {
updateFromInput(input, true);
}, 1);
});
}));