UNPKG

grapesjs_codeapps

Version:

Free and Open Source Web Builder Framework/SC Modification

1,786 lines (1,577 loc) 70.4 kB
// 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'>&#9660;</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)