grapesjs_codeapps
Version:
Free and Open Source Web Builder Framework/SC Modification
1,786 lines (1,577 loc) • 70.4 kB
JavaScript
// Without jquery I have to update few stuff
//
// Spectrum Colorpicker v1.8.0
// https://github.com/bgrins/spectrum
// Author: Brian Grinstead
// License: MIT
export default function($, undefined) {
'use strict';
var defaultOpts = {
// Callbacks
beforeShow: noop,
move: noop,
change: noop,
show: noop,
hide: noop,
// Options
color: false,
flat: false,
showInput: false,
allowEmpty: false,
showButtons: true,
clickoutFiresChange: true,
showInitial: false,
showPalette: false,
showPaletteOnly: false,
hideAfterPaletteSelect: false,
togglePaletteOnly: false,
showSelectionPalette: true,
localStorageKey: false,
appendTo: 'body',
maxSelectionSize: 7,
cancelText: 'cancel',
chooseText: 'choose',
togglePaletteMoreText: 'more',
togglePaletteLessText: 'less',
clearText: 'Clear Color Selection',
noColorSelectedText: 'No Color Selected',
preferredFormat: false,
className: '', // Deprecated - use containerClassName and replacerClassName instead.
containerClassName: '',
replacerClassName: '',
showAlpha: false,
theme: 'sp-light',
palette: [
[
'#ffffff',
'#000000',
'#ff0000',
'#ff8000',
'#ffff00',
'#008000',
'#0000ff',
'#4b0082',
'#9400d3'
]
],
selectionPalette: [],
disabled: false,
offset: null
},
spectrums = [],
IE = !!/msie/i.exec(window.navigator.userAgent),
rgbaSupport = (function() {
function contains(str, substr) {
return !!~('' + str).indexOf(substr);
}
var elem = document.createElement('div');
var style = elem.style;
style.cssText = 'background-color:rgba(0,0,0,.5)';
return (
contains(style.backgroundColor, 'rgba') ||
contains(style.backgroundColor, 'hsla')
);
})(),
replaceInput = [
"<div class='sp-replacer'>",
"<div class='sp-preview'><div class='sp-preview-inner'></div></div>",
"<div class='sp-dd'>▼</div>",
'</div>'
].join(''),
markup = (function() {
// IE does not support gradients with multiple stops, so we need to simulate
// that for the rainbow slider with 8 divs that each have a single gradient
var gradientFix = '';
if (IE) {
for (var i = 1; i <= 6; i++) {
gradientFix += "<div class='sp-" + i + "'></div>";
}
}
return [
"<div class='sp-container sp-hidden'>",
"<div class='sp-palette-container'>",
"<div class='sp-palette sp-thumb sp-cf'></div>",
"<div class='sp-palette-button-container sp-cf'>",
"<button type='button' class='sp-palette-toggle'></button>",
'</div>',
'</div>',
"<div class='sp-picker-container'>",
"<div class='sp-top sp-cf'>",
"<div class='sp-fill'></div>",
"<div class='sp-top-inner'>",
"<div class='sp-color'>",
"<div class='sp-sat'>",
"<div class='sp-val'>",
"<div class='sp-dragger'></div>",
'</div>',
'</div>',
'</div>',
"<div class='sp-clear sp-clear-display'>",
'</div>',
"<div class='sp-hue'>",
"<div class='sp-slider'></div>",
gradientFix,
'</div>',
'</div>',
"<div class='sp-alpha'><div class='sp-alpha-inner'><div class='sp-alpha-handle'></div></div></div>",
'</div>',
"<div class='sp-input-container sp-cf'>",
"<input class='sp-input' type='text' spellcheck='false' />",
'</div>',
"<div class='sp-initial sp-thumb sp-cf'></div>",
"<div class='sp-button-container sp-cf'>",
"<a class='sp-cancel' href='#'></a>",
"<button type='button' class='sp-choose'></button>",
'</div>',
'</div>',
'</div>'
].join('');
})();
function paletteTemplate(p, color, className, opts) {
var html = [];
for (var i = 0; i < p.length; i++) {
var current = p[i];
if (current) {
var tiny = tinycolor(current);
var c =
tiny.toHsl().l < 0.5
? 'sp-thumb-el sp-thumb-dark'
: 'sp-thumb-el sp-thumb-light';
c += tinycolor.equals(color, current) ? ' sp-thumb-active' : '';
var formattedString = tiny.toString(opts.preferredFormat || 'rgb');
var swatchStyle = rgbaSupport
? 'background-color:' + tiny.toRgbString()
: 'filter:' + tiny.toFilter();
html.push(
'<span title="' +
formattedString +
'" data-color="' +
tiny.toRgbString() +
'" class="' +
c +
'"><span class="sp-thumb-inner" style="' +
swatchStyle +
';"></span></span>'
);
} else {
var cls = 'sp-clear-display';
html.push(
$('<div />')
.append(
$(
'<span data-color="" style="background-color:transparent;" class="' +
cls +
'"></span>'
).attr('title', opts.noColorSelectedText)
)
.html()
);
}
}
return "<div class='sp-cf " + className + "'>" + html.join('') + '</div>';
}
function hideAll() {
for (var i = 0; i < spectrums.length; i++) {
if (spectrums[i]) {
spectrums[i].hide();
}
}
}
function instanceOptions(o, callbackContext) {
var opts = $.extend({}, defaultOpts, o);
opts.callbacks = {
move: bind(opts.move, callbackContext),
change: bind(opts.change, callbackContext),
show: bind(opts.show, callbackContext),
hide: bind(opts.hide, callbackContext),
beforeShow: bind(opts.beforeShow, callbackContext)
};
return opts;
}
function spectrum(element, o) {
var opts = instanceOptions(o, element),
flat = opts.flat,
showSelectionPalette = opts.showSelectionPalette,
localStorageKey = opts.localStorageKey,
theme = opts.theme,
callbacks = opts.callbacks,
resize = throttle(reflow, 10),
visible = false,
isDragging = false,
dragWidth = 0,
dragHeight = 0,
dragHelperHeight = 0,
slideHeight = 0,
slideWidth = 0,
alphaWidth = 0,
alphaSlideHelperWidth = 0,
slideHelperHeight = 0,
currentHue = 0,
currentSaturation = 0,
currentValue = 0,
currentAlpha = 1,
palette = [],
paletteArray = [],
paletteLookup = {},
selectionPalette = opts.selectionPalette.slice(0),
maxSelectionSize = opts.maxSelectionSize,
draggingClass = 'sp-dragging',
shiftMovementDirection = null;
var doc = element.ownerDocument,
body = doc.body,
boundElement = $(element),
disabled = false,
container = $(markup, doc).addClass(theme),
pickerContainer = container.find('.sp-picker-container'),
dragger = container.find('.sp-color'),
dragHelper = container.find('.sp-dragger'),
slider = container.find('.sp-hue'),
slideHelper = container.find('.sp-slider'),
alphaSliderInner = container.find('.sp-alpha-inner'),
alphaSlider = container.find('.sp-alpha'),
alphaSlideHelper = container.find('.sp-alpha-handle'),
textInput = container.find('.sp-input'),
paletteContainer = container.find('.sp-palette'),
initialColorContainer = container.find('.sp-initial'),
cancelButton = container.find('.sp-cancel'),
clearButton = container.find('.sp-clear'),
chooseButton = container.find('.sp-choose'),
toggleButton = container.find('.sp-palette-toggle'),
isInput = boundElement.is('input'),
isInputTypeColor =
isInput &&
boundElement.attr('type') === 'color' &&
inputTypeColorSupport(),
shouldReplace = isInput && !flat,
replacer = shouldReplace
? $(replaceInput)
.addClass(theme)
.addClass(opts.className)
.addClass(opts.replacerClassName)
: $([]),
offsetElement = shouldReplace ? replacer : boundElement,
previewElement = replacer.find('.sp-preview-inner'),
initialColor = opts.color || (isInput && boundElement.val()),
colorOnShow = false,
currentPreferredFormat = opts.preferredFormat,
clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange,
isEmpty = !initialColor,
allowEmpty = opts.allowEmpty && !isInputTypeColor;
function applyOptions() {
if (opts.showPaletteOnly) {
opts.showPalette = true;
}
toggleButton.text(
opts.showPaletteOnly
? opts.togglePaletteMoreText
: opts.togglePaletteLessText
);
if (opts.palette) {
palette = opts.palette.slice(0);
paletteArray = $.isArray(palette[0]) ? palette : [palette];
paletteLookup = {};
for (var i = 0; i < paletteArray.length; i++) {
for (var j = 0; j < paletteArray[i].length; j++) {
var rgb = tinycolor(paletteArray[i][j]).toRgbString();
paletteLookup[rgb] = true;
}
}
}
container.toggleClass('sp-flat', flat);
container.toggleClass('sp-input-disabled', !opts.showInput);
container.toggleClass('sp-alpha-enabled', opts.showAlpha);
container.toggleClass('sp-clear-enabled', allowEmpty);
container.toggleClass('sp-buttons-disabled', !opts.showButtons);
container.toggleClass(
'sp-palette-buttons-disabled',
!opts.togglePaletteOnly
);
container.toggleClass('sp-palette-disabled', !opts.showPalette);
container.toggleClass('sp-palette-only', opts.showPaletteOnly);
container.toggleClass('sp-initial-disabled', !opts.showInitial);
container.addClass(opts.className).addClass(opts.containerClassName);
reflow();
}
function initialize() {
if (IE) {
container.find('*:not(input)').attr('unselectable', 'on');
}
applyOptions();
if (shouldReplace) {
boundElement.after(replacer).hide();
}
if (!allowEmpty) {
clearButton.hide();
}
if (flat) {
boundElement.after(container).hide();
} else {
var appendTo =
opts.appendTo === 'parent' ? boundElement.parent() : $(opts.appendTo);
if (appendTo.length !== 1) {
appendTo = $('body');
}
appendTo.append(container);
}
updateSelectionPaletteFromStorage();
offsetElement.bind('click.spectrum touchstart.spectrum', function(e) {
if (!disabled) {
toggle();
}
e.stopPropagation();
if (!$(e.target).is('input')) {
e.preventDefault();
}
});
if (boundElement.is(':disabled') || opts.disabled === true) {
disable();
}
// Prevent clicks from bubbling up to document. This would cause it to be hidden.
container.click(stopPropagation);
// Handle user typed input
textInput.change(setFromTextInput);
textInput.bind('paste', function() {
setTimeout(setFromTextInput, 1);
});
textInput.keydown(function(e) {
if (e.keyCode == 13) {
setFromTextInput();
}
});
cancelButton.text(opts.cancelText);
cancelButton.bind('click.spectrum', function(e) {
e.stopPropagation();
e.preventDefault();
revert();
hide();
});
clearButton.attr('title', opts.clearText);
clearButton.bind('click.spectrum', function(e) {
e.stopPropagation();
e.preventDefault();
isEmpty = true;
move();
if (flat) {
//for the flat style, this is a change event
updateOriginalInput(true);
}
});
chooseButton.text(opts.chooseText);
chooseButton.bind('click.spectrum', function(e) {
e.stopPropagation();
e.preventDefault();
if (IE && textInput.is(':focus')) {
textInput.trigger('change');
}
if (isValid()) {
updateOriginalInput(true);
hide();
}
});
toggleButton.text(
opts.showPaletteOnly
? opts.togglePaletteMoreText
: opts.togglePaletteLessText
);
toggleButton.bind('click.spectrum', function(e) {
e.stopPropagation();
e.preventDefault();
opts.showPaletteOnly = !opts.showPaletteOnly;
// To make sure the Picker area is drawn on the right, next to the
// Palette area (and not below the palette), first move the Palette
// to the left to make space for the picker, plus 5px extra.
// The 'applyOptions' function puts the whole container back into place
// and takes care of the button-text and the sp-palette-only CSS class.
if (!opts.showPaletteOnly && !flat) {
container.css('left', '-=' + (pickerContainer.outerWidth(true) + 5));
}
applyOptions();
});
draggable(
alphaSlider,
function(dragX, dragY, e) {
currentAlpha = dragX / alphaWidth;
isEmpty = false;
if (e.shiftKey) {
currentAlpha = Math.round(currentAlpha * 10) / 10;
}
move();
},
dragStart,
dragStop
);
draggable(
slider,
function(dragX, dragY) {
currentHue = parseFloat(dragY / slideHeight);
isEmpty = false;
if (!opts.showAlpha) {
currentAlpha = 1;
}
move();
},
dragStart,
dragStop
);
draggable(
dragger,
function(dragX, dragY, e) {
// shift+drag should snap the movement to either the x or y axis.
if (!e.shiftKey) {
shiftMovementDirection = null;
} else if (!shiftMovementDirection) {
var oldDragX = currentSaturation * dragWidth;
var oldDragY = dragHeight - currentValue * dragHeight;
var furtherFromX =
Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY);
shiftMovementDirection = furtherFromX ? 'x' : 'y';
}
var setSaturation =
!shiftMovementDirection || shiftMovementDirection === 'x';
var setValue =
!shiftMovementDirection || shiftMovementDirection === 'y';
if (setSaturation) {
currentSaturation = parseFloat(dragX / dragWidth);
}
if (setValue) {
currentValue = parseFloat((dragHeight - dragY) / dragHeight);
}
isEmpty = false;
if (!opts.showAlpha) {
currentAlpha = 1;
}
move();
},
dragStart,
dragStop
);
if (!!initialColor) {
set(initialColor);
// In case color was black - update the preview UI and set the format
// since the set function will not run (default color is black).
updateUI();
currentPreferredFormat =
opts.preferredFormat || tinycolor(initialColor).format;
addColorToSelectionPalette(initialColor);
} else {
updateUI();
}
if (flat) {
show();
}
function paletteElementClick(e) {
if (e.data && e.data.ignore) {
set(
$(e.target)
.closest('.sp-thumb-el')
.data('color')
);
move();
} else {
set(
$(e.target)
.closest('.sp-thumb-el')
.data('color')
);
move();
updateOriginalInput(true);
if (opts.hideAfterPaletteSelect) {
hide();
}
}
return false;
}
var paletteEvent = IE
? 'mousedown.spectrum'
: 'click.spectrum touchstart.spectrum';
paletteContainer.delegate(
'.sp-thumb-el',
paletteEvent,
paletteElementClick
);
initialColorContainer.delegate(
'.sp-thumb-el:nth-child(1)',
paletteEvent,
{ ignore: true },
paletteElementClick
);
}
function updateSelectionPaletteFromStorage() {
if (localStorageKey && window.localStorage) {
// Migrate old palettes over to new format. May want to remove this eventually.
try {
var oldPalette = window.localStorage[localStorageKey].split(',#');
if (oldPalette.length > 1) {
delete window.localStorage[localStorageKey];
$.each(oldPalette, function(i, c) {
addColorToSelectionPalette(c);
});
}
} catch (e) {}
try {
selectionPalette = window.localStorage[localStorageKey].split(';');
} catch (e) {}
}
}
function addColorToSelectionPalette(color) {
if (showSelectionPalette) {
var rgb = tinycolor(color).toRgbString();
if (!paletteLookup[rgb] && $.inArray(rgb, selectionPalette) === -1) {
selectionPalette.push(rgb);
while (selectionPalette.length > maxSelectionSize) {
selectionPalette.shift();
}
}
if (localStorageKey && window.localStorage) {
try {
window.localStorage[localStorageKey] = selectionPalette.join(';');
} catch (e) {}
}
}
}
function getUniqueSelectionPalette() {
var unique = [];
if (opts.showPalette) {
for (var i = 0; i < selectionPalette.length; i++) {
var rgb = tinycolor(selectionPalette[i]).toRgbString();
if (!paletteLookup[rgb]) {
unique.push(selectionPalette[i]);
}
}
}
return unique.reverse().slice(0, opts.maxSelectionSize);
}
function drawPalette() {
var currentColor = get();
var html = $.map(paletteArray, function(palette, i) {
return paletteTemplate(
palette,
currentColor,
'sp-palette-row sp-palette-row-' + i,
opts
);
});
updateSelectionPaletteFromStorage();
if (selectionPalette) {
html.push(
paletteTemplate(
getUniqueSelectionPalette(),
currentColor,
'sp-palette-row sp-palette-row-selection',
opts
)
);
}
paletteContainer.html(html.join(''));
}
function drawInitial() {
if (opts.showInitial) {
var initial = colorOnShow;
var current = get();
initialColorContainer.html(
paletteTemplate(
[initial, current],
current,
'sp-palette-row-initial',
opts
)
);
}
}
function dragStart() {
if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) {
reflow();
}
isDragging = true;
container.addClass(draggingClass);
shiftMovementDirection = null;
boundElement.trigger('dragstart.spectrum', [get()]);
}
function dragStop() {
isDragging = false;
container.removeClass(draggingClass);
boundElement.trigger('dragstop.spectrum', [get()]);
}
function setFromTextInput() {
var value = textInput.val();
if ((value === null || value === '') && allowEmpty) {
set(null);
updateOriginalInput(true);
} else {
var tiny = tinycolor(value);
if (tiny.isValid()) {
set(tiny);
updateOriginalInput(true);
} else {
textInput.addClass('sp-validation-error');
}
}
}
function toggle() {
if (visible) {
hide();
} else {
show();
}
}
function show() {
var event = $.Event('beforeShow.spectrum');
if (visible) {
reflow();
return;
}
boundElement.trigger(event, [get()]);
if (callbacks.beforeShow(get()) === false || event.isDefaultPrevented()) {
return;
}
hideAll();
visible = true;
var $doc = $(doc);
$doc.bind('keydown.spectrum', onkeydown);
$doc.bind('click.spectrum', clickout);
$(window).bind('resize.spectrum', resize);
replacer.addClass('sp-active');
container.removeClass('sp-hidden');
reflow();
updateUI();
colorOnShow = get();
drawInitial();
callbacks.show(colorOnShow);
boundElement.trigger('show.spectrum', [colorOnShow]);
}
function onkeydown(e) {
// Close on ESC
if (e.keyCode === 27) {
hide();
}
}
function clickout(e) {
// Return on right click.
if (e.button == 2) {
return;
}
// If a drag event was happening during the mouseup, don't hide
// on click.
if (isDragging) {
return;
}
if (clickoutFiresChange) {
updateOriginalInput(true);
} else {
revert();
}
hide();
}
function hide() {
// Return if hiding is unnecessary
if (!visible || flat) {
return;
}
visible = false;
$(doc).unbind('keydown.spectrum', onkeydown);
$(doc).unbind('click.spectrum', clickout);
$(window).unbind('resize.spectrum', resize);
replacer.removeClass('sp-active');
container.addClass('sp-hidden');
callbacks.hide(get());
boundElement.trigger('hide.spectrum', [get()]);
}
function revert() {
set(colorOnShow, true);
}
function set(color, ignoreFormatChange) {
if (tinycolor.equals(color, get())) {
// Update UI just in case a validation error needs
// to be cleared.
updateUI();
return;
}
var newColor, newHsv;
if (!color && allowEmpty) {
isEmpty = true;
} else {
isEmpty = false;
newColor = tinycolor(color);
newHsv = newColor.toHsv();
currentHue = (newHsv.h % 360) / 360;
currentSaturation = newHsv.s;
currentValue = newHsv.v;
currentAlpha = newHsv.a;
}
updateUI();
if (newColor && newColor.isValid() && !ignoreFormatChange) {
currentPreferredFormat = opts.preferredFormat || newColor.getFormat();
}
}
function get(opts) {
opts = opts || {};
if (allowEmpty && isEmpty) {
return null;
}
return tinycolor.fromRatio(
{
h: currentHue,
s: currentSaturation,
v: currentValue,
a: Math.round(currentAlpha * 100) / 100
},
{ format: opts.format || currentPreferredFormat }
);
}
function isValid() {
return !textInput.hasClass('sp-validation-error');
}
function move() {
updateUI();
callbacks.move(get());
boundElement.trigger('move.spectrum', [get()]);
}
function updateUI() {
textInput.removeClass('sp-validation-error');
updateHelperLocations();
// Update dragger background color (gradients take care of saturation and value).
var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 });
dragger.css('background-color', flatColor.toHexString());
// Get a format that alpha will be included in (hex and names ignore alpha)
var format = currentPreferredFormat;
if (currentAlpha < 1 && !(currentAlpha === 0 && format === 'name')) {
if (
format === 'hex' ||
format === 'hex3' ||
format === 'hex6' ||
format === 'name'
) {
format = 'rgb';
}
}
var realColor = get({ format: format }),
displayColor = '';
//reset background info for preview element
previewElement.removeClass('sp-clear-display');
previewElement.css('background-color', 'transparent');
if (!realColor && allowEmpty) {
// Update the replaced elements background with icon indicating no color selection
previewElement.addClass('sp-clear-display');
} else {
var realHex = realColor.toHexString(),
realRgb = realColor.toRgbString();
// Update the replaced elements background color (with actual selected color)
if (rgbaSupport || realColor.alpha === 1) {
previewElement.css('background-color', realRgb);
} else {
previewElement.css('background-color', 'transparent');
previewElement.css('filter', realColor.toFilter());
}
if (opts.showAlpha) {
var rgb = realColor.toRgb();
rgb.a = 0;
var realAlpha = tinycolor(rgb).toRgbString();
var gradient =
'linear-gradient(left, ' + realAlpha + ', ' + realHex + ')';
if (IE) {
alphaSliderInner.css(
'filter',
tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex)
);
} else {
alphaSliderInner.css('background', '-webkit-' + gradient);
alphaSliderInner.css('background', '-moz-' + gradient);
alphaSliderInner.css('background', '-ms-' + gradient);
// Use current syntax gradient on unprefixed property.
alphaSliderInner.css(
'background',
'linear-gradient(to right, ' + realAlpha + ', ' + realHex + ')'
);
}
}
displayColor = realColor.toString(format);
}
// Update the text entry input as it changes happen
if (opts.showInput) {
textInput.val(displayColor);
}
if (opts.showPalette) {
drawPalette();
}
drawInitial();
}
function updateHelperLocations() {
var s = currentSaturation;
var v = currentValue;
if (allowEmpty && isEmpty) {
//if selected color is empty, hide the helpers
alphaSlideHelper.hide();
slideHelper.hide();
dragHelper.hide();
} else {
//make sure helpers are visible
alphaSlideHelper.show();
slideHelper.show();
dragHelper.show();
// Where to show the little circle in that displays your current selected color
var dragX = s * dragWidth;
var dragY = dragHeight - v * dragHeight;
dragX = Math.max(
-dragHelperHeight,
Math.min(dragWidth - dragHelperHeight, dragX - dragHelperHeight)
);
dragY = Math.max(
-dragHelperHeight,
Math.min(dragHeight - dragHelperHeight, dragY - dragHelperHeight)
);
dragHelper.css({
top: dragY + 'px',
left: dragX + 'px'
});
var alphaX = currentAlpha * alphaWidth;
alphaSlideHelper.css({
left: alphaX - alphaSlideHelperWidth / 2 + 'px'
});
// Where to show the bar that displays your current selected hue
var slideY = currentHue * slideHeight;
slideHelper.css({
top: slideY - slideHelperHeight + 'px'
});
}
}
function updateOriginalInput(fireCallback) {
var color = get(),
displayColor = '',
hasChanged = !tinycolor.equals(color, colorOnShow);
if (color) {
displayColor = color.toString(currentPreferredFormat);
// Update the selection palette with the current color
addColorToSelectionPalette(color);
}
if (isInput) {
boundElement.val(displayColor);
}
if (fireCallback && hasChanged) {
callbacks.change(color);
boundElement.trigger('change', [color]);
}
}
function reflow() {
if (!visible) {
return; // Calculations would be useless and wouldn't be reliable anyways
}
dragWidth = dragger.width();
dragHeight = dragger.height();
dragHelperHeight = dragHelper.height();
slideWidth = slider.width();
slideHeight = slider.height();
slideHelperHeight = slideHelper.height();
alphaWidth = alphaSlider.width();
alphaSlideHelperWidth = alphaSlideHelper.width();
if (!flat) {
container.css('position', 'absolute');
if (opts.offset) {
container.offset(opts.offset);
} else {
container.offset(getOffset(container, offsetElement));
}
}
updateHelperLocations();
if (opts.showPalette) {
drawPalette();
}
boundElement.trigger('reflow.spectrum');
}
function destroy() {
boundElement.show();
offsetElement.unbind('click.spectrum touchstart.spectrum');
container.remove();
replacer.remove();
spectrums[spect.id] = null;
}
function option(optionName, optionValue) {
if (optionName === undefined) {
return $.extend({}, opts);
}
if (optionValue === undefined) {
return opts[optionName];
}
opts[optionName] = optionValue;
if (optionName === 'preferredFormat') {
currentPreferredFormat = opts.preferredFormat;
}
applyOptions();
}
function enable() {
disabled = false;
boundElement.attr('disabled', false);
offsetElement.removeClass('sp-disabled');
}
function disable() {
hide();
disabled = true;
boundElement.attr('disabled', true);
offsetElement.addClass('sp-disabled');
}
function setOffset(coord) {
opts.offset = coord;
reflow();
}
initialize();
var spect = {
show: show,
hide: hide,
toggle: toggle,
reflow: reflow,
option: option,
enable: enable,
disable: disable,
offset: setOffset,
set: function(c) {
set(c);
updateOriginalInput();
},
get: get,
destroy: destroy,
container: container
};
spect.id = spectrums.push(spect) - 1;
return spect;
}
/**
* checkOffset - get the offset below/above and left/right element depending on screen position
* Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js
*/
function getOffset(picker, input) {
var extraY = 0;
var dpWidth = picker.outerWidth();
var dpHeight = picker.outerHeight();
var inputHeight = input.outerHeight();
var doc = picker[0].ownerDocument;
var docElem = doc.documentElement;
var cW = docElem.clientWidth;
var cH = docElem.clientHeight;
var scL = $(doc).scrollLeft();
var scT = $(doc).scrollTop();
var viewWidth = cW + scL;
var viewHeight = cH + scT;
var offset = input.offset();
offset.top += inputHeight;
offset.left -= Math.min(
offset.left,
offset.left + dpWidth > viewWidth && viewWidth > dpWidth
? Math.abs(offset.left + dpWidth - viewWidth)
: 0
);
offset.top -= Math.min(
offset.top,
offset.top + dpHeight > viewHeight && viewHeight > dpHeight
? Math.abs(dpHeight + inputHeight - extraY)
: extraY
);
return offset;
}
/**
* noop - do nothing
*/
function noop() {}
/**
* stopPropagation - makes the code only doing this a little easier to read in line
*/
function stopPropagation(e) {
e.stopPropagation();
}
/**
* Create a function bound to a given object
* Thanks to underscore.js
*/
function bind(func, obj) {
var slice = Array.prototype.slice;
var args = slice.call(arguments, 2);
return function() {
return func.apply(obj, args.concat(slice.call(arguments)));
};
}
/**
* Lightweight drag helper. Handles containment within the element, so that
* when dragging, the x is within [0,element.width] and y is within [0,element.height]
*/
function draggable(element, onmove, onstart, onstop) {
onmove = onmove || function() {};
onstart = onstart || function() {};
onstop = onstop || function() {};
var doc = document;
var dragging = false;
var offset = {};
var maxHeight = 0;
var maxWidth = 0;
var hasTouch = 'ontouchstart' in window;
var duringDragEvents = {};
duringDragEvents['selectstart'] = prevent;
duringDragEvents['dragstart'] = prevent;
duringDragEvents['touchmove mousemove'] = move;
duringDragEvents['touchend mouseup'] = stop;
function prevent(e) {
if (e.stopPropagation) {
e.stopPropagation();
}
if (e.preventDefault) {
e.preventDefault();
}
e.returnValue = false;
}
function move(e) {
if (dragging) {
// Mouseup happened outside of window
if (IE && doc.documentMode < 9 && !e.button) {
return stop();
}
var t0 = e && e.touches && e.touches[0];
var pageX = (t0 && t0.pageX) || e.pageX;
var pageY = (t0 && t0.pageY) || e.pageY;
var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth));
var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight));
if (hasTouch) {
// Stop scrolling in iOS
prevent(e);
}
onmove.apply(element, [dragX, dragY, e]);
}
}
function start(e) {
var rightclick = e.which ? e.which == 3 : e.button == 2;
if (!rightclick && !dragging) {
if (onstart.apply(element, arguments) !== false) {
dragging = true;
maxHeight = $(element).height();
maxWidth = $(element).width();
offset = $(element).offset();
$(doc).bind(duringDragEvents);
$(doc.body).addClass('sp-dragging');
move(e);
prevent(e);
}
}
}
function stop() {
if (dragging) {
$(doc).unbind(duringDragEvents);
$(doc.body).removeClass('sp-dragging');
// Wait a tick before notifying observers to allow the click event
// to fire in Chrome.
setTimeout(function() {
onstop.apply(element, arguments);
}, 0);
}
dragging = false;
}
$(element).bind('touchstart mousedown', start);
}
function throttle(func, wait, debounce) {
var timeout;
return function() {
var context = this,
args = arguments;
var throttler = function() {
timeout = null;
func.apply(context, args);
};
if (debounce) clearTimeout(timeout);
if (debounce || !timeout) timeout = setTimeout(throttler, wait);
};
}
function inputTypeColorSupport() {
return $.fn.spectrum.inputTypeColorSupport();
}
/**
* Define a jQuery plugin
*/
var dataID = 'spectrum.id';
$.fn.spectrum = function(opts, extra) {
if (typeof opts == 'string') {
var returnValue = this;
var args = Array.prototype.slice.call(arguments, 1);
this.each(function() {
var spect = spectrums[$(this).data(dataID)];
if (spect) {
var method = spect[opts];
if (!method) {
throw new Error("Spectrum: no such method: '" + opts + "'");
}
if (opts == 'get') {
returnValue = spect.get();
} else if (opts == 'container') {
returnValue = spect.container;
} else if (opts == 'option') {
returnValue = spect.option.apply(spect, args);
} else if (opts == 'destroy') {
spect.destroy();
$(this).removeData(dataID);
} else {
method.apply(spect, args);
}
}
});
return returnValue;
}
// Initializing a new instance of spectrum
return this.spectrum('destroy').each(function() {
var options = $.extend({}, opts, $(this).data());
var spect = spectrum(this, options);
$(this).data(dataID, spect.id);
});
};
$.fn.spectrum.load = true;
$.fn.spectrum.loadOpts = {};
$.fn.spectrum.draggable = draggable;
$.fn.spectrum.defaults = defaultOpts;
$.fn.spectrum.inputTypeColorSupport = function inputTypeColorSupport() {
if (typeof inputTypeColorSupport._cachedResult === 'undefined') {
var colorInput = $("<input type='color'/>")[0]; // if color element is supported, value will default to not null
inputTypeColorSupport._cachedResult =
colorInput.type === 'color' && colorInput.value !== '';
}
return inputTypeColorSupport._cachedResult;
};
$.spectrum = {};
$.spectrum.localization = {};
$.spectrum.palettes = {};
$.fn.spectrum.processNativeColorInputs = function() {
var colorInputs = $('input[type=color]');
if (colorInputs.length && !inputTypeColorSupport()) {
colorInputs.spectrum({
preferredFormat: 'hex6'
});
}
};
// TinyColor v1.1.2
// https://github.com/bgrins/TinyColor
// Brian Grinstead, MIT License
//(function() {
var trimLeft = /^[\s,#]+/,
trimRight = /\s+$/,
tinyCounter = 0,
math = Math,
mathRound = math.round,
mathMin = math.min,
mathMax = math.max,
mathRandom = math.random;
var tinycolor = function(color, opts) {
color = color ? color : '';
opts = opts || {};
// If input is already a tinycolor, return itself
if (color instanceof tinycolor) {
return color;
}
// If we are called as a function, call using new instead
if (!(this instanceof tinycolor)) {
return new tinycolor(color, opts);
}
var rgb = inputToRGB(color);
(this._originalInput = color),
(this._r = rgb.r),
(this._g = rgb.g),
(this._b = rgb.b),
(this._a = rgb.a),
(this._roundA = mathRound(100 * this._a) / 100),
(this._format = opts.format || rgb.format);
this._gradientType = opts.gradientType;
// Don't let the range of [0,255] come back in [0,1].
// Potentially lose a little bit of precision here, but will fix issues where
// .5 gets interpreted as half of the total, instead of half of 1
// If it was supposed to be 128, this was already taken care of by `inputToRgb`
if (this._r < 1) {
this._r = mathRound(this._r);
}
if (this._g < 1) {
this._g = mathRound(this._g);
}
if (this._b < 1) {
this._b = mathRound(this._b);
}
this._ok = rgb.ok;
this._tc_id = tinyCounter++;
};
tinycolor.prototype = {
isDark: function() {
return this.getBrightness() < 128;
},
isLight: function() {
return !this.isDark();
},
isValid: function() {
return this._ok;
},
getOriginalInput: function() {
return this._originalInput;
},
getFormat: function() {
return this._format;
},
getAlpha: function() {
return this._a;
},
getBrightness: function() {
var rgb = this.toRgb();
return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
},
setAlpha: function(value) {
this._a = boundAlpha(value);
this._roundA = mathRound(100 * this._a) / 100;
return this;
},
toHsv: function() {
var hsv = rgbToHsv(this._r, this._g, this._b);
return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a };
},
toHsvString: function() {
var hsv = rgbToHsv(this._r, this._g, this._b);
var h = mathRound(hsv.h * 360),
s = mathRound(hsv.s * 100),
v = mathRound(hsv.v * 100);
return this._a == 1
? 'hsv(' + h + ', ' + s + '%, ' + v + '%)'
: 'hsva(' + h + ', ' + s + '%, ' + v + '%, ' + this._roundA + ')';
},
toHsl: function() {
var hsl = rgbToHsl(this._r, this._g, this._b);
return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a };
},
toHslString: function() {
var hsl = rgbToHsl(this._r, this._g, this._b);
var h = mathRound(hsl.h * 360),
s = mathRound(hsl.s * 100),
l = mathRound(hsl.l * 100);
return this._a == 1
? 'hsl(' + h + ', ' + s + '%, ' + l + '%)'
: 'hsla(' + h + ', ' + s + '%, ' + l + '%, ' + this._roundA + ')';
},
toHex: function(allow3Char) {
return rgbToHex(this._r, this._g, this._b, allow3Char);
},
toHexString: function(allow3Char) {
return '#' + this.toHex(allow3Char);
},
toHex8: function() {
return rgbaToHex(this._r, this._g, this._b, this._a);
},
toHex8String: function() {
return '#' + this.toHex8();
},
toRgb: function() {
return {
r: mathRound(this._r),
g: mathRound(this._g),
b: mathRound(this._b),
a: this._a
};
},
toRgbString: function() {
return this._a == 1
? 'rgb(' +
mathRound(this._r) +
', ' +
mathRound(this._g) +
', ' +
mathRound(this._b) +
')'
: 'rgba(' +
mathRound(this._r) +
', ' +
mathRound(this._g) +
', ' +
mathRound(this._b) +
', ' +
this._roundA +
')';
},
toPercentageRgb: function() {
return {
r: mathRound(bound01(this._r, 255) * 100) + '%',
g: mathRound(bound01(this._g, 255) * 100) + '%',
b: mathRound(bound01(this._b, 255) * 100) + '%',
a: this._a
};
},
toPercentageRgbString: function() {
return this._a == 1
? 'rgb(' +
mathRound(bound01(this._r, 255) * 100) +
'%, ' +
mathRound(bound01(this._g, 255) * 100) +
'%, ' +
mathRound(bound01(this._b, 255) * 100) +
'%)'
: 'rgba(' +
mathRound(bound01(this._r, 255) * 100) +
'%, ' +
mathRound(bound01(this._g, 255) * 100) +
'%, ' +
mathRound(bound01(this._b, 255) * 100) +
'%, ' +
this._roundA +
')';
},
toName: function() {
if (this._a === 0) {
return 'transparent';
}
if (this._a < 1) {
return false;
}
return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false;
},
toFilter: function(secondColor) {
var hex8String = '#' + rgbaToHex(this._r, this._g, this._b, this._a);
var secondHex8String = hex8String;
var gradientType = this._gradientType ? 'GradientType = 1, ' : '';
if (secondColor) {
var s = tinycolor(secondColor);
secondHex8String = s.toHex8String();
}
return (
'progid:DXImageTransform.Microsoft.gradient(' +
gradientType +
'startColorstr=' +
hex8String +
',endColorstr=' +
secondHex8String +
')'
);
},
toString: function(format) {
var formatSet = !!format;
format = format || this._format;
var formattedString = false;
var hasAlpha = this._a < 1 && this._a >= 0;
var needsAlphaFormat =
!formatSet &&
hasAlpha &&
(format === 'hex' ||
format === 'hex6' ||
format === 'hex3' ||
format === 'name');
if (needsAlphaFormat) {
// Special case for "transparent", all other non-alpha formats
// will return rgba when there is transparency.
if (format === 'name' && this._a === 0) {
return this.toName();
}
return this.toRgbString();
}
if (format === 'rgb') {
formattedString = this.toRgbString();
}
if (format === 'prgb') {
formattedString = this.toPercentageRgbString();
}
if (format === 'hex' || format === 'hex6') {
formattedString = this.toHexString();
}
if (format === 'hex3') {
formattedString = this.toHexString(true);
}
if (format === 'hex8') {
formattedString = this.toHex8String();
}
if (format === 'name') {
formattedString = this.toName();
}
if (format === 'hsl') {
formattedString = this.toHslString();
}
if (format === 'hsv') {
formattedString = this.toHsvString();
}
return formattedString || this.toHexString();
},
_applyModification: function(fn, args) {
var color = fn.apply(null, [this].concat([].slice.call(args)));
this._r = color._r;
this._g = color._g;
this._b = color._b;
this.setAlpha(color._a);
return this;
},
lighten: function() {
return this._applyModification(lighten, arguments);
},
brighten: function() {
return this._applyModification(brighten, arguments);
},
darken: function() {
return this._applyModification(darken, arguments);
},
desaturate: function() {
return this._applyModification(desaturate, arguments);
},
saturate: function() {
return this._applyModification(saturate, arguments);
},
greyscale: function() {
return this._applyModification(greyscale, arguments);
},
spin: function() {
return this._applyModification(spin, arguments);
},
_applyCombination: function(fn, args) {
return fn.apply(null, [this].concat([].slice.call(args)));
},
analogous: function() {
return this._applyCombination(analogous, arguments);
},
complement: function() {
return this._applyCombination(complement, arguments);
},
monochromatic: function() {
return this._applyCombination(monochromatic, arguments);
},
splitcomplement: function() {
return this._applyCombination(splitcomplement, arguments);
},
triad: function() {
return this._applyCombination(triad, arguments);
},
tetrad: function() {
return this._applyCombination(tetrad, arguments);
}
};
// If input is an object, force 1 into "1.0" to handle ratios properly
// String input requires "1.0" as input, so 1 will be treated as 1
tinycolor.fromRatio = function(color, opts) {
if (typeof color == 'object') {
var newColor = {};
for (var i in color) {
if (color.hasOwnProperty(i)) {
if (i === 'a') {
newColor[i] = color[i];
} else {
newColor[i] = convertToPercentage(color[i]);
}
}
}
color = newColor;
}
return tinycolor(color, opts);
};
// Given a string or object, convert that input to RGB
// Possible string inputs:
//
// "red"
// "#f00" or "f00"
// "#ff0000" or "ff0000"
// "#ff000000" or "ff000000"
// "rgb 255 0 0" or "rgb (255, 0, 0)"
// "rgb 1.0 0 0" or "rgb (1, 0, 0)"
// "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1"
// "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1"
// "hsl(0, 100%, 50%)" or "hsl 0 100% 50%"
// "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1"
// "hsv(0, 100%, 100%)" or "hsv 0 100% 100%"
//
function inputToRGB(color) {
var rgb = { r: 0, g: 0, b: 0 };
var a = 1;
var ok = false;
var format = false;
if (typeof color == 'string') {
color = stringInputToObject(color);
}
if (typeof color == 'object') {
if (
color.hasOwnProperty('r') &&
color.hasOwnProperty('g') &&
color.hasOwnProperty('b')
) {
rgb = rgbToRgb(color.r, color.g, color.b);
ok = true;
format = String(color.r).substr(-1) === '%' ? 'prgb' : 'rgb';
} else if (
color.hasOwnProperty('h') &&
color.hasOwnProperty('s') &&
color.hasOwnProperty('v')
) {
color.s = convertToPercentage(color.s);
color.v = convertToPercentage(color.v);
rgb = hsvToRgb(color.h, color.s, color.v);
ok = true;
format = 'hsv';
} else if (
color.hasOwnProperty('h') &&
color.hasOwnProperty('s') &&
color.hasOwnProperty('l')
) {
color.s = convertToPercentage(color.s);
color.l = convertToPercentage(color.l);
rgb = hslToRgb(color.h, color.s, color.l);
ok = true;
format = 'hsl';
}
if (color.hasOwnProperty('a')) {
a = color.a;
}
}
a = boundAlpha(a);
return {
ok: ok,
format: color.format || format,
r: mathMin(255, mathMax(rgb.r, 0)),
g: mathMin(255, mathMax(rgb.g, 0)),
b: mathMin(255, mathMax(rgb.b, 0)),
a: a
};
}
// Conversion Functions
// --------------------
// `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from:
// <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript>
// `rgbToRgb`
// Handle bounds / percentage checking to conform to CSS color spec
// <http://www.w3.org/TR/css3-color/>
// *Assumes:* r, g, b in [0, 255] or [0, 1]
// *Returns:* { r, g, b } in [0, 255]
function rgbToRgb(r, g, b) {
return {
r: bound01(r, 255) * 255,
g: bound01(g, 255) * 255,
b: bound01(b, 255) * 255
};
}
// `rgbToHsl`
// Converts an RGB color value to HSL.
// *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]
// *Returns:* { h, s, l } in [0,1]
function rgbToHsl(r, g, b) {
r = bound01(r, 255);
g = bound01(g, 255);
b = bound01(b, 255);
var max = mathMax(r, g, b),
min = mathMin(r, g, b);
var h,
s,
l = (max + min) / 2;
if (max == min) {
h = s = 0; // achromatic
} else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
return { h: h, s: s, l: l };
}
// `hslToRgb`
// Converts an HSL color value to RGB.
// *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]
// *Returns:* { r, g, b } in the set [0, 255]
function hslToRgb(h, s, l) {
var r, g, b;
h = bound01(h, 360);
s = bound01(s, 100);
l = bound01(l, 100);
function hue2rgb(p, q, t)