alpaca
Version:
Alpaca provides the easiest and fastest way to generate interactive forms for the web and mobile devices. It runs simply as HTML5 or more elaborately using Bootstrap, jQuery Mobile or jQuery UI. Alpaca uses Handlebars to process JSON schema and provide
1,184 lines • 57.7 kB
JavaScript
/*
* Pick-a-Color JS v1.2.3
* Copyright 2013 Lauren Sperber and Broadstreet Ads
* https://github.com/lauren/pick-a-color/blob/master/LICENSE
*/
;(function ($) {
"use strict";
$.fn.pickAColor = function (options) {
// capabilities
var supportsTouch = 'ontouchstart' in window,
smallScreen = (parseInt($(window).width(),10) < 767) ? true : false,
supportsLocalStorage = 'localStorage' in window && window.localStorage !== null &&
typeof JSON === 'object', // don't use LS if JSON is not available
isIELT10 = document.all && !window.atob, // OH NOES!
startEvent = supportsTouch ? "touchstart.pickAColor" : "mousedown.pickAColor",
moveEvent = supportsTouch ? "touchmove.pickAColor" : "mousemove.pickAColor",
endEvent = supportsTouch ? "touchend.pickAColor" : "mouseup.pickAColor",
clickEvent = supportsTouch ? "touchend.pickAColor" : "click.pickAColor",
dragEvent = "dragging.pickAColor",
endDragEvent = "endDrag.pickAColor";
// settings
var settings = $.extend({
showSpectrum : true,
showSavedColors : true,
saveColorsPerElement : false,
fadeMenuToggle : true,
showAdvanced : true,
showBasicColors : true,
showHexInput : true,
allowBlank : false,
inlineDropdown : false,
basicColors : {
white : 'fff',
red : 'f00',
orange : 'f60',
yellow : 'ff0',
green : '008000',
blue : '00f',
purple : '800080',
black : '000'
}
}, options);
// override showBasicColors showAdvanced isn't shown
if (!settings.showAdvanced && !settings.showBasicColors) {
settings.showBasicColors = true;
}
var useTabs = (settings.showSavedColors && settings.showAdvanced) ||
(settings.showBasicColors && settings.showSavedColors) ||
(settings.showBasicColors && settings.showAdvanced);
// so much markup
var markupAfterInput = function () {
var $markup = $("<div>").addClass("input-group-btn"),
$dropdownButton = $("<button type='button'>").addClass("btn btn-default color-dropdown dropdown-toggle"),
$dropdownColorPreview = $("<span>").addClass("color-preview current-color"),
$dropdownCaret = $("<span>").addClass("caret"),
$dropdownContainer = $("<div>").addClass("color-menu dropdown-menu");
if (settings.inlineDropdown) {
$dropdownContainer.addClass("color-menu--inline");
}
if (!settings.showHexInput) {
$dropdownButton.addClass("no-hex");
$dropdownContainer.addClass("no-hex");
}
$markup.append($dropdownButton.append($dropdownColorPreview).append($dropdownCaret));
if (!useTabs && !settings.showSpectrum) {
$dropdownContainer.addClass("small");
}
if (useTabs) {
var $tabContainer = $("<div>").addClass("color-menu-tabs"),
savedColorsClass = settings.showBasicColors ? "savedColors-tab tab" : "savedColors-tab tab tab-active";
if (settings.showBasicColors) {
$tabContainer.append($("<span>").addClass("basicColors-tab tab tab-active").
append($("<a>").text("Basic Colors")));
}
if (settings.showSavedColors) {
$tabContainer.append($("<span>").addClass(savedColorsClass).append($("<a>").text("Saved Colors")));
}
if (settings.showAdvanced) {
$tabContainer.append($("<span>").addClass("advanced-tab tab").
append($("<a>").text("Advanced")));
}
$dropdownContainer.append($tabContainer);
}
if (settings.showBasicColors) {
var $basicColors = $("<div>").addClass("basicColors-content active-content");
if (settings.showSpectrum) {
$basicColors.append($("<h6>").addClass("color-menu-instructions").
text("Tap spectrum or drag band to change color"));
}
var $listContainer = $("<ul>").addClass("basic-colors-list");
$.each(settings.basicColors, function (index,value) {
var $thisColor = $("<li>").addClass("color-item"),
$thisLink = $("<a>").addClass(index + " color-link"),
$colorPreview = $("<span>").addClass("color-preview " + index),
$colorLabel = $("<span>").addClass("color-label").text(index);
$thisLink.append($colorPreview, $colorLabel);
$colorPreview.append();
if (value[0] !== '#') {
value = '#'+value;
}
$colorPreview.css('background-color', value);
if (settings.showSpectrum) {
var $thisSpectrum = $("<span>").addClass("color-box spectrum-" + index);
if (isIELT10) {
$.each([0,1], function (i) {
if (value !== "fff" && index !== "000")
$thisSpectrum.append($("<span>").addClass(index + "-spectrum-" + i +
" ie-spectrum"));
});
}
var $thisHighlightBand = $("<span>").addClass("highlight-band");
$.each([0,1,2], function () {
$thisHighlightBand.append($("<span>").addClass("highlight-band-stripe"));
});
$thisLink.append($thisSpectrum.append($thisHighlightBand));
}
$listContainer.append($thisColor.append($thisLink));
});
$dropdownContainer.append($basicColors.append($listContainer));
}
if (settings.showSavedColors) {
var savedColorsActiveClass = settings.showBasicColors ? 'inactive-content' : 'active-content',
$savedColors = $("<div>").addClass("savedColors-content").addClass(savedColorsActiveClass);
$savedColors.append($("<p>").addClass("saved-colors-instructions").
text("Type in a color or use the spectrums to lighten or darken an existing color."));
$dropdownContainer.append($savedColors);
}
if (settings.showAdvanced) {
var advancedColorsActiveClass = settings.showBasicColors || settings.showSavedColors ? 'inactive-content' : 'active-content';
var $advanced = $("<div>").addClass("advanced-content").addClass(advancedColorsActiveClass).
append($("<h6>").addClass("advanced-instructions").text("Tap spectrum or drag band to change color")),
$advancedList = $("<ul>").addClass("advanced-list"),
$hueItem = $("<li>").addClass("hue-item"),
$hueContent = $("<span>").addClass("hue-text").
text("Hue: ").append($("<span>").addClass("hue-value").text("0"));
var $hueSpectrum = $("<span>").addClass("color-box spectrum-hue");
if (isIELT10) {
$.each([0,1,2,3,4,5,6], function (i) {
$hueSpectrum.append($("<span>").addClass("hue-spectrum-" + i +
" ie-spectrum hue"));
});
}
var $hueHighlightBand = $("<span>").addClass("highlight-band");
$.each([0,1,2], function () {
$hueHighlightBand.append($("<span>").addClass("highlight-band-stripe"));
});
$advancedList.append($hueItem.append($hueContent).append($hueSpectrum.append($hueHighlightBand)));
var $lightnessItem = $("<li>").addClass("lightness-item"),
$lightnessSpectrum = $("<span>").addClass("color-box spectrum-lightness"),
$lightnessContent = $("<span>").addClass("lightness-text").
text("Lightness: ").append($("<span>").addClass("lightness-value").text("50%"));
if (isIELT10) {
$.each([0,1], function (i) {
$lightnessSpectrum.append($("<span>").addClass("lightness-spectrum-" + i +
" ie-spectrum"));
});
}
var $lightnessHighlightBand = $("<span>").addClass("highlight-band");
$.each([0,1,2], function () {
$lightnessHighlightBand.append($("<span>").addClass("highlight-band-stripe"));
});
$advancedList.append($lightnessItem.
append($lightnessContent).append($lightnessSpectrum.append($lightnessHighlightBand)));
var $saturationItem = $("<li>").addClass("saturation-item"),
$saturationSpectrum = $("<span>").addClass("color-box spectrum-saturation");
if (isIELT10) {
$.each([0,1], function (i) {
$saturationSpectrum.append($("<span>").addClass("saturation-spectrum-" + i +
" ie-spectrum"));
});
}
var $saturationHighlightBand = $("<span>").addClass("highlight-band");
$.each([0,1,2], function () {
$saturationHighlightBand.append($("<span>").addClass("highlight-band-stripe"));
});
var $saturationContent = $("<span>").addClass("saturation-text").
text("Saturation: ").append($("<span>").addClass("saturation-value").text("100%"));
$advancedList.append($saturationItem.append($saturationContent).append($saturationSpectrum.
append($saturationHighlightBand)));
var $previewItem = $("<li>").addClass("preview-item").append($("<span>").
addClass("preview-text").text("Preview")),
$preview = $("<span>").addClass("color-preview advanced").
append("<button class='color-select btn btn-mini advanced' type='button'>Select</button>");
$advancedList.append($previewItem.append($preview));
$dropdownContainer.append($advanced.append($advancedList));
}
$markup.append($dropdownContainer);
return $markup;
};
var myColorVars = {};
var myStyleVars = {
rowsInDropdown : 8,
maxColsInDropdown : 2
};
if (settings.showSavedColors) { // if we're saving colors...
var allSavedColors = []; // make an array for all saved colors
if (supportsLocalStorage && localStorage.allSavedColors) { // look for them in LS
allSavedColors = JSON.parse(localStorage.allSavedColors);
// if there's a saved_colors cookie...
} else if (document.cookie.match("pickAColorSavedColors-allSavedColors=")) {
var theseCookies = document.cookie.split(";"); // split cookies into an array...
$.each(theseCookies, function (index) { // find the savedColors cookie!
if (theseCookies[index].match("pickAColorSavedColors-allSavedColors=")) {
allSavedColors = theseCookies[index].split("=")[1].split(",");
}
});
}
}
// methods
var methods = {
initialize: function (index) {
var $thisEl = $(this),
$thisParent,
myId,
defaultColor;
// if there's no name on the input field, create one, then use it as the myID
if (!$thisEl.attr("name")) {
$thisEl.attr("name","pick-a-color-" + index);
}
myId = $thisEl.attr("name");
// enforce .pick-a-color class on input
$thisEl.addClass("pick-a-color");
// convert default color to valid hex value
if (settings.allowBlank) {
// convert to Hex only if the field init value is not blank
if (!$thisEl.val().match(/^\s+$|^$/)) {
myColorVars.defaultColor = tinycolor($thisEl.val()).toHex();
myColorVars.typedColor = myColorVars.defaultColor;
$thisEl.val(myColorVars.defaultColor);
}
} else {
myColorVars.defaultColor = tinycolor($thisEl.val()).toHex();
myColorVars.typedColor = myColorVars.defaultColor;
$thisEl.val(myColorVars.defaultColor);
}
// wrap initializing input field with unique div and add hex symbol and post-input markup
$($thisEl).wrap('<div class="input-group pick-a-color-markup" id="' + myId + '">');
$thisParent = $($thisEl.parent());
if (settings.showHexInput) {
$thisParent.prepend('<span class="hex-pound input-group-addon">#</span>').append(markupAfterInput());
} else {
$thisParent.append(markupAfterInput());
}
// hide input for noinput option
if (!settings.showHexInput) {
$thisEl.attr("type","hidden");
}
},
updatePreview: function ($thisEl) {
if (!settings.allowBlank) {
myColorVars.typedColor = tinycolor($thisEl.val()).toHex();
$thisEl.siblings(".input-group-btn").find(".current-color").css("background-color",
"#" + myColorVars.typedColor);
} else {
myColorVars.typedColor = $thisEl.val().match(/^\s+$|^$/) ? '' : tinycolor($thisEl.val()).toHex();
if (myColorVars.typedColor === '') {
$thisEl.siblings(".input-group-btn").find(".current-color").css("background",
"none");
} else {
$thisEl.siblings(".input-group-btn").find(".current-color").css("background-color",
"#" + myColorVars.typedColor);
}
}
},
// must be called with apply and an arguments array like [{thisEvent}]
pressPreviewButton: function () {
var thisEvent = arguments[0].thisEvent;
thisEvent.stopPropagation();
methods.toggleDropdown(thisEvent.target);
},
openDropdown: function (button,menu) {
$(".color-menu").each(function () { // check all the other color menus...
var $thisEl = $(this);
if ($thisEl.css("display") === "block") { // if one is open,
// find its color preview button
var thisColorPreviewButton = $thisEl.parents(".input-group-btn");
methods.closeDropdown(thisColorPreviewButton,$thisEl); // close it
}
});
if (settings.fadeMenuToggle && !supportsTouch) { //fades look terrible in mobile
$(menu).fadeIn("fast");
} else {
$(menu).show();
}
$(button).addClass("open");
},
closeDropdown: function (button,menu) {
if (settings.fadeMenuToggle && !supportsTouch) { //fades look terrible in mobile
$(menu).fadeOut("fast");
} else {
$(menu).css("display","none");
}
$(button).removeClass("open");
},
// can only be called with apply. requires an arguments array like:
// [{button, menu}]
closeDropdownIfOpen: function () {
var button = arguments[0].button,
menu = arguments[0].menu;
if (menu.css("display") === "block") {
methods.closeDropdown(button,menu);
}
},
toggleDropdown: function (element) {
var $container = $(element).parents(".pick-a-color-markup"),
$input = $container.find("input"),
$button = $container.find(".input-group-btn"),
$menu = $container.find(".color-menu");
if (!$input.is(":disabled") && $menu.css("display") === "none") {
methods.openDropdown($button,$menu);
} else {
methods.closeDropdown($button,$menu);
}
},
tabbable: function () {
var $this_el = $(this),
$myContainer = $this_el.parents(".pick-a-color-markup");
$this_el.click(function () {
var $this_el = $(this),
// interpret the associated content class from the tab class and get that content div
contentClass = $this_el.attr("class").split(" ")[0].split("-")[0] + "-content",
myContent = $this_el.parents(".dropdown-menu").find("." + contentClass);
if (!$this_el.hasClass("tab-active")) { // make all active tabs inactive
$myContainer.find(".tab-active").removeClass("tab-active");
// toggle visibility of active content
$myContainer.find(".active-content").
removeClass("active-content").addClass("inactive-content");
$this_el.addClass("tab-active"); // make current tab and content active
$(myContent).addClass("active-content").removeClass("inactive-content");
}
});
},
// takes a color and the current position of the color band,
// returns the value by which the color should be multiplied to
// get the color currently being highlighted by the band
getColorMultiplier: function (spectrumType,position,tab) {
// position of the color band as a percentage of the width of the color box
var spectrumWidth = (tab === "basic") ? parseInt($(".color-box").first().width(),10) :
parseInt($(".advanced-list").find(".color-box").first().width(),10);
if (spectrumWidth === 0) { // in case the width isn't set correctly
if (tab === "basic") {
spectrumWidth = supportsTouch ? 160 : 200;
} else {
spectrumWidth = supportsTouch ? 160 : 300;
}
}
var halfSpectrumWidth = spectrumWidth / 2,
percentOfBox = position / spectrumWidth;
// for spectrums that lighten and darken, recalculate percent of box relative
// to the half of spectrum the highlight band is currently in
if (spectrumType === "bidirectional") {
return (percentOfBox <= 0.5) ?
(1 - (position / halfSpectrumWidth)) / 2 :
-((position - halfSpectrumWidth) / halfSpectrumWidth) / 2;
// now that we're treating each half as an individual spectrum, both are darkenRight
} else {
return (spectrumType === "darkenRight") ? -(percentOfBox / 2) : (percentOfBox / 2);
}
},
// modifyHSLLightness based on ligten/darken in LESS
// https://github.com/cloudhead/less.js/blob/master/dist/less-1.3.3.js#L1763
modifyHSLLightness: function (HSL,multiplier) {
var hsl = HSL;
hsl.l += multiplier;
hsl.l = Math.min(Math.max(0,hsl.l),1);
return tinycolor(hsl).toHslString();
},
// defines the area within which an element can be moved
getMoveableArea: function ($element) {
var dimensions = {},
$elParent = $element.parent(),
myWidth = $element.outerWidth(),
parentWidth = $elParent.width(), // don't include borders for parent width
parentLocation = $elParent.offset();
dimensions.minX = parentLocation.left;
dimensions.maxX = parentWidth - myWidth; //subtract myWidth to avoid pushing out of parent
return dimensions;
},
moveHighlightBand: function ($highlightBand, moveableArea, e) {
var hbWidth = $(".highlight-band").first().outerWidth(),
threeFourthsHBWidth = hbWidth * 0.75,
mouseX = supportsTouch ? e.originalEvent.pageX : e.pageX, // find the mouse!
// mouse position relative to width of highlight-band
newPosition = mouseX - moveableArea.minX - threeFourthsHBWidth;
// don't move beyond moveable area
newPosition = Math.max(0,(Math.min(newPosition,moveableArea.maxX)));
$highlightBand.css("position", "absolute");
$highlightBand.css("left", newPosition);
},
horizontallyDraggable: function () {
$(this).on(startEvent, function (event) {
event.preventDefault();
var $this_el = $(event.delegateTarget);
$this_el.css("cursor","-webkit-grabbing");
$this_el.css("cursor","-moz-grabbing");
var dimensions = methods.getMoveableArea($this_el);
$(document).on(moveEvent, function (e) {
$this_el.trigger(dragEvent);
methods.moveHighlightBand($this_el, dimensions, e);
}).on(endEvent, function(event) {
$(document).off(moveEvent); // for desktop
$(document).off(dragEvent);
$this_el.css("cursor","-webkit-grab");
$this_el.css("cursor","-moz-grab");
$this_el.trigger(endDragEvent);
$(document).off(endEvent);
});
}).on(endEvent, function(event) {
event.stopPropagation();
$(document).off(moveEvent); // for mobile
$(document).off(dragEvent);
});
},
modifyHighlightBand: function ($highlightBand,colorMultiplier,spectrumType) {
var darkGrayHSL = { h: 0, s:0, l: 0.05 },
bwMidHSL = { h: 0, s:0, l: 0.5 },
// change to color of band is opposite of change to color of spectrum
hbColorMultiplier = -colorMultiplier,
hbsColorMultiplier = hbColorMultiplier * 10, // needs to be either black or white
$hbStripes = $highlightBand.find(".highlight-band-stripe"),
newBandColor = (spectrumType === "lightenRight") ?
methods.modifyHSLLightness(bwMidHSL,hbColorMultiplier) :
methods.modifyHSLLightness(darkGrayHSL,hbColorMultiplier);
$highlightBand.css("border-color", newBandColor);
$hbStripes.css("background-color", newBandColor);
},
// must be called with apply and expects an arguments array like
// [{type: "basic"}] or [{type: "advanced", hsl: {h,s,l}}]
calculateHighlightedColor: function () {
var $thisEl = $(this),
$thisParent = $thisEl.parent(),
hbWidth = $(".highlight-band").first().outerWidth(),
halfHBWidth = hbWidth / 2,
tab = arguments[0].type,
spectrumType,
colorHsl,
currentHue,
currentSaturation,
$advancedPreview,
$saturationSpectrum,
$hueSpectrum,
$lightnessValue;
if (tab === "basic") {
// get the class of the parent color box and slice off "spectrum"
var colorName = $thisParent.attr("class").split("-")[2],
colorHex = settings.basicColors[colorName];
colorHsl = tinycolor(colorHex).toHsl();
switch(colorHex) {
case "fff":
spectrumType = "darkenRight";
break;
case "000":
spectrumType = "lightenRight";
break;
default:
spectrumType = "bidirectional";
}
} else {
// re-set current L value to 0.5 because the color multiplier ligtens
// and darkens against the baseline value
var $advancedContainer = $thisEl.parents(".advanced-list");
currentSaturation = arguments[0].hsl.s;
$hueSpectrum = $advancedContainer.find(".spectrum-hue");
currentHue = arguments[0].hsl.h;
$saturationSpectrum = $advancedContainer.find(".spectrum-saturation");
$lightnessValue = $advancedContainer.find(".lightness-value");
$advancedPreview = $advancedContainer.find(".color-preview");
colorHsl = {"h": arguments[0].hsl.h, "l": 0.5, "s": arguments[0].hsl.s};
spectrumType = "bidirectional";
}
// midpoint of the current left position of the color band
var highlightBandLocation = parseInt($thisEl.css("left"),10) + halfHBWidth,
colorMultiplier = methods.getColorMultiplier(spectrumType,highlightBandLocation,tab),
highlightedColor = methods.modifyHSLLightness(colorHsl,colorMultiplier),
highlightedHex = "#" + tinycolor(highlightedColor).toHex(),
highlightedLightnessString = highlightedColor.split("(")[1].split(")")[0].split(",")[2],
highlightedLightness = (parseInt(highlightedLightnessString.split("%")[0], 10)) / 100;
if (tab === "basic") {
$thisParent.siblings(".color-preview").css("background-color",highlightedHex);
// replace the color label with a 'select' button
$thisParent.prev('.color-label').replaceWith(
'<button class="color-select btn btn-mini" type="button">Select</button>');
if (spectrumType !== "darkenRight") {
methods.modifyHighlightBand($thisEl,colorMultiplier,spectrumType);
}
} else {
$advancedPreview.css("background-color",highlightedHex);
$lightnessValue.text(highlightedLightnessString);
methods.updateSaturationStyles($saturationSpectrum,currentHue,highlightedLightness);
methods.updateHueStyles($hueSpectrum,currentSaturation,highlightedLightness);
methods.modifyHighlightBand($(".advanced-content .highlight-band"),colorMultiplier,spectrumType);
}
return (tab === "basic") ? tinycolor(highlightedColor).toHex() : highlightedLightness;
},
updateSavedColorPreview: function (elements) {
$.each(elements, function (index) {
var $this_el = $(elements[index]),
thisColor = $this_el.attr("class");
$this_el.find(".color-preview").css("background-color",thisColor);
});
},
updateSavedColorMarkup: function ($savedColorsContent,mySavedColors) {
mySavedColors = mySavedColors ? mySavedColors : allSavedColors;
if (settings.showSavedColors && mySavedColors.length > 0) {
if (!settings.saveColorsPerElement) {
$savedColorsContent = $(".savedColors-content");
mySavedColors = allSavedColors;
}
var maxSavedColors = myStyleVars.rowsInDropdown * myStyleVars.maxColsInDropdown;
mySavedColors = mySavedColors.slice(0,maxSavedColors);
var $col0 = $("<ul>").addClass("saved-color-col 0"),
$col1 = $("<ul>").addClass("saved-color-col 1");
$.each(mySavedColors, function (index,value) {
var $this_li = $("<li>").addClass("color-item"),
$this_link = $("<a>").addClass(value);
$this_link.append($("<span>").addClass("color-preview"));
$this_link.append($("<span>").addClass("color-label").text(value));
$this_li.append($this_link);
if (index % 2 === 0) {
$col0.append($this_li);
} else {
$col1.append($this_li);
}
});
$savedColorsContent.html($col0);
$savedColorsContent.append($col1);
var savedColorLinks = $($savedColorsContent).find("a");
methods.updateSavedColorPreview(savedColorLinks);
}
},
setSavedColorsCookie: function (savedColors,savedColorsDataAttr) {
var now = new Date(),
tenYearsInMilliseconds = 315360000000,
expiresOn = new Date(now.getTime() + tenYearsInMilliseconds);
expiresOn = expiresOn.toGMTString();
if (typeof savedColorsDataAttr === "undefined") {
document.cookie = "pickAColorSavedColors-allSavedColors=" + savedColors +
";expires=" + expiresOn;
} else {
document.cookie = "pickAColorSavedColors-" + savedColorsDataAttr + "=" +
savedColors + "; expires=" + expiresOn;
}
},
saveColorsToLocalStorage: function (savedColors,savedColorsDataAttr) {
if (supportsLocalStorage) {
// if there is no data attribute, save to allSavedColors
if (typeof savedColorsDataAttr === "undefined") {
try {
localStorage.allSavedColors = JSON.stringify(savedColors);
}
catch(e) {
localStorage.clear();
}
} else { // otherwise save to a data attr-specific item
try {
localStorage["pickAColorSavedColors-" + savedColorsDataAttr] =
JSON.stringify(savedColors);
}
catch(e) {
localStorage.clear();
}
}
} else {
methods.setSavedColorsCookie(savedColors,savedColorsDataAttr);
}
},
removeFromArray: function (array, item) {
if ($.inArray(item,array) !== -1) { // make sure it's in there
array.splice($.inArray(item,array),1);
}
},
updateSavedColors: function (color,savedColors,savedColorsDataAttr) {
methods.removeFromArray(savedColors,color);
savedColors.unshift(color);
methods.saveColorsToLocalStorage(savedColors,savedColorsDataAttr);
},
// when settings.saveColorsPerElement, colors are saved to both mySavedColors and
// allSavedColors so they will be avail to color pickers with no savedColorsDataAttr
addToSavedColors: function (color,mySavedColorsInfo,$mySavedColorsContent) {
if (settings.showSavedColors && color !== undefined) { // make sure we're saving colors
if (color[0] != "#") {
color = "#" + color;
}
methods.updateSavedColors(color,allSavedColors);
if (settings.saveColorsPerElement) { // if we're saving colors per element...
var mySavedColors = mySavedColorsInfo.colors,
dataAttr = mySavedColorsInfo.dataAttr;
methods.updateSavedColors(color,mySavedColors,dataAttr);
methods.updateSavedColorMarkup($mySavedColorsContent,mySavedColors);
} else { // if not saving per element, update markup with allSavedColors
methods.updateSavedColorMarkup($mySavedColorsContent,allSavedColors);
}
}
},
// handles selecting a color from the basic menu of colors.
// must be called with apply and relies on an arguments array like:
// [{els, savedColorsInfo}]
selectFromBasicColors: function () {
var selectedColor = $(this).find("span:first").css("background-color"),
myElements = arguments[0].els,
mySavedColorsInfo = arguments[0].savedColorsInfo;
selectedColor = tinycolor(selectedColor).toHex();
$(myElements.thisEl).val(selectedColor);
$(myElements.thisEl).trigger("change");
methods.updatePreview(myElements.thisEl);
methods.addToSavedColors(selectedColor,mySavedColorsInfo,myElements.savedColorsContent);
methods.closeDropdown(myElements.colorPreviewButton,myElements.colorMenu); // close the dropdown
},
// handles user clicking or tapping on spectrum to select a color.
// must be called with apply and relies on an arguments array like:
// [{thisEvent, savedColorsInfo, els, mostRecentClick}]
tapSpectrum: function () {
var thisEvent = arguments[0].thisEvent,
mySavedColorsInfo = arguments[0].savedColorsInfo,
myElements = arguments[0].els,
mostRecentClick = arguments[0].mostRecentClick;
thisEvent.stopPropagation(); // stop this click from closing the dropdown
var $highlightBand = $(this).find(".highlight-band"),
dimensions = methods.getMoveableArea($highlightBand);
if (supportsTouch) {
methods.moveHighlightBand($highlightBand, dimensions, mostRecentClick);
} else {
methods.moveHighlightBand($highlightBand, dimensions, thisEvent);
}
var highlightedColor = methods.calculateHighlightedColor.apply($highlightBand, [{type: "basic"}]);
methods.addToSavedColors(highlightedColor,mySavedColorsInfo,myElements.savedColorsContent);
// update touch instructions
myElements.touchInstructions.html("Press 'select' to choose this color");
},
// bind to mousedown/touchstart, execute provied function if the top of the
// window has not moved when there is a mouseup/touchend
// must be called with apply and an arguments array like:
// [{thisFunction, theseArguments}]
executeUnlessScrolled: function () {
var thisFunction = arguments[0].thisFunction,
theseArguments = arguments[0].theseArguments,
windowTopPosition,
mostRecentClick;
$(this).on(startEvent, function (e) {
windowTopPosition = $(window).scrollTop(); // save to see if user is scrolling in mobile
mostRecentClick = e;
}).on(clickEvent, function (event) {
var distance = windowTopPosition - $(window).scrollTop();
if (supportsTouch && (Math.abs(distance) > 0)) {
return false;
} else {
theseArguments.thisEvent = event; //add the click event to the arguments object
theseArguments.mostRecentClick = mostRecentClick; //add start event to the arguments object
thisFunction.apply($(this), [theseArguments]);
}
});
},
updateSaturationStyles: function (spectrum, hue, lightness) {
var lightnessString = (lightness * 100).toString() + "%",
start = "#" + tinycolor("hsl(" + hue + ",0%," + lightnessString).toHex(),
mid = "#" + tinycolor("hsl(" + hue + ",50%," + lightnessString).toHex(),
end = "#" + tinycolor("hsl(" + hue + ",100%," + lightnessString).toHex(),
fullSpectrumString = "",
standard = $.each(["-webkit-linear-gradient","-o-linear-gradient"], function(index,value) {
fullSpectrumString += "background-image: " + value + "(left, " + start + " 0%, " + mid + " 50%, " + end + " 100%);";
}),
ieSpectrum0 = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + start + "', endColorstr='" +
mid + "', GradientType=1)",
ieSpectrum1 = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + mid + "', endColorstr='" +
end + "', GradientType=1)";
fullSpectrumString =
"background-image: -moz-linear-gradient(left center, " + start + " 0%, " + mid + " 50%, " + end + " 100%);" +
"background-image: linear-gradient(to right, " + start + " 0%, " + mid + " 50%, " + end + " 100%); " +
"background-image: -webkit-gradient(linear, left top, right top," +
"color-stop(0, " + start + ")," + "color-stop(0.5, " + mid + ")," + "color-stop(1, " + end + "));" +
fullSpectrumString;
if (isIELT10) {
var $spectrum0 = $(spectrum).find(".saturation-spectrum-0");
var $spectrum1 = $(spectrum).find(".saturation-spectrum-1");
$spectrum0.css("filter",ieSpectrum0);
$spectrum1.css("filter",ieSpectrum1);
} else {
spectrum.attr("style",fullSpectrumString);
}
},
updateLightnessStyles: function (spectrum, hue, saturation) {
var saturationString = (saturation * 100).toString() + "%",
start = "#" + tinycolor("hsl(" + hue + "," + saturationString + ",100%)").toHex(),
mid = "#" + tinycolor("hsl(" + hue + "," + saturationString + ",50%)").toHex(),
end = "#" + tinycolor("hsl(" + hue + "," + saturationString + ",0%)").toHex(),
fullSpectrumString = "",
standard = $.each(["-webkit-linear-gradient","-o-linear-gradient"], function(index, value) {
fullSpectrumString += "background-image: " + value + "(left, " + start + " 0%, " + mid + " 50%, "
+ end + " 100%);";
}),
ieSpectrum0 = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + start + "', endColorstr='" +
mid + "', GradientType=1)",
ieSpectrum1 = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + mid + "', endColorstr='" +
end + "', GradientType=1)";
fullSpectrumString =
"background-image: -moz-linear-gradient(left center, " + start + " 0%, " + mid + " 50%, " + end + " 100%); " +
"background-image: linear-gradient(to right, " + start + " 0%, " + mid + " 50%, " + end + " 100%); " +
"background-image: -webkit-gradient(linear, left top, right top," +
" color-stop(0, " + start + ")," + " color-stop(0.5, " + mid + ")," + " color-stop(1, " + end + ")); " +
fullSpectrumString;
if (isIELT10) {
var $spectrum0 = $(spectrum).find(".lightness-spectrum-0");
var $spectrum1 = $(spectrum).find(".lightness-spectrum-1");
$spectrum0.css("filter",ieSpectrum0);
$spectrum1.css("filter",ieSpectrum1);
} else {
spectrum.attr("style",fullSpectrumString);
}
},
updateHueStyles: function (spectrum, saturation, lightness) {
var saturationString = (saturation * 100).toString() + "%",
lightnessString = (lightness * 100).toString() + "%",
color1 = "#" + tinycolor("hsl(0," + saturationString + "," + lightnessString + ")").toHex(),
color2 = "#" + tinycolor("hsl(60," + saturationString + "," + lightnessString + ")").toHex(),
color3 = "#" + tinycolor("hsl(120," + saturationString + "," + lightnessString + ")").toHex(),
color4 = "#" + tinycolor("hsl(180," + saturationString + "," + lightnessString + ")").toHex(),
color5 = "#" + tinycolor("hsl(240," + saturationString + "," + lightnessString + ")").toHex(),
color6 = "#" + tinycolor("hsl(300," + saturationString + "," + lightnessString + ")").toHex(),
color7 = "#" + tinycolor("hsl(0," + saturationString + "," + lightnessString + ")").toHex(),
ieSpectrum0 = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + color1 + "', endColorstr='" +
color2 + "', GradientType=1)",
ieSpectrum1 = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + color2 + "', endColorstr='" +
color3 + "', GradientType=1)",
ieSpectrum2 = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + color3 + "', endColorstr='" +
color4 + "', GradientType=1)",
ieSpectrum3 = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + color4 + "', endColorstr='" +
color5 + "', GradientType=1)",
ieSpectrum4 = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + color5 + "', endColorstr='" +
color6 + "', GradientType=1)",
ieSpectrum5 = "progid:DXImageTransform.Microsoft.gradient(startColorstr='" + color6 + "', endColorstr='" +
color7 + "', GradientType=1)",
fullSpectrumString = "",
standard = $.each(["-webkit-linear-gradient","-o-linear-gradient"], function(index,value) {
fullSpectrumString += "background-image: " + value + "(left, " + color1 + " 0%, " + color2 + " 17%, " +
color3 + " 24%, " + color4 + " 51%, " + color5 + " 68%, " + color6 + " 85%, " + color7 + " 100%);";
});
fullSpectrumString += "background-image: -webkit-gradient(linear, left top, right top," +
"color-stop(0%, " + color1 + ")," + "color-stop(17%, " + color2 + ")," + "color-stop(34%, " + color3 + ")," +
"color-stop(51%, " + color4 + ")," + "color-stop(68%, " + color5 + ")," + "color-stop(85%, " + color6 + ")," +
"color-stop(100%, " + color7 + "));" +
"background-image: linear-gradient(to right, " + color1 + " 0%, " + color2 + " 17%, " + color3 + " 24%," +
color4 + " 51%," + color5 + " 68%," + color6 + " 85%," + color7 + " 100%); " +
"background-image: -moz-linear-gradient(left center, " +
color1 + " 0%, " + color2 + " 17%, " + color3 + " 24%, " + color4 + " 51%, " + color5 + " 68%, " +
color6 + " 85%, " + color7 + " 100%);";
if (isIELT10) {
var $spectrum0 = $(spectrum).find(".hue-spectrum-0"),
$spectrum1 = $(spectrum).find(".hue-spectrum-1"),
$spectrum2 = $(spectrum).find(".hue-spectrum-2"),
$spectrum3 = $(spectrum).find(".hue-spectrum-3"),
$spectrum4 = $(spectrum).find(".hue-spectrum-4"),
$spectrum5 = $(spectrum).find(".hue-spectrum-5");
$spectrum0.css("filter",ieSpectrum0);
$spectrum1.css("filter",ieSpectrum1);
$spectrum2.css("filter",ieSpectrum2);
$spectrum3.css("filter",ieSpectrum3);
$spectrum4.css("filter",ieSpectrum4);
$spectrum5.css("filter",ieSpectrum5);
} else {
spectrum.attr("style",fullSpectrumString);
}
},
// takes the position of a highlight band on the hue spectrum and finds highlighted hue
// and updates the background of the lightness and saturation spectrums
// relies on apply and an arguments array like [{h, s, l}]
getHighlightedHue: function () {
var $thisEl = $(this),
hbWidth = $thisEl.outerWidth(),
halfHBWidth = hbWidth / 2,
position = parseInt($thisEl.css("left"),10) + halfHBWidth,
$advancedContainer = $thisEl.parents(".advanced-list"),
$advancedPreview = $advancedContainer.find(".color-preview"),
$lightnessSpectrum = $advancedContainer.find(".spectrum-lightness"),
$saturationSpectrum = $advancedContainer.find(".spectrum-saturation"),
spectrumWidth = parseInt($advancedContainer.find(".color-box").first().width(),10),
$hueValue = $advancedContainer.find(".hue-value"),
currentLightness = arguments[0].l,
currentSaturation = arguments[0].s,
saturationString = (currentSaturation * 100).toString() + "%",
lightnessString = (currentLightness * 100).toString() + "%";
if (spectrumWidth === 0) { // in case the width isn't set correctly
spectrumWidth = supportsTouch ? 160 : 300;
}
var hue = Math.floor((position/spectrumWidth) * 360),
color = "hsl(" + hue + "," + saturationString + "," + lightnessString + ")";
color = "#" + tinycolor(color).toHex();
$advancedPreview.css("background-color",color);
$hueValue.text(hue);
methods.updateLightnessStyles($lightnessSpectrum,hue,currentSaturation);
methods.updateSaturationStyles($saturationSpectrum,hue,currentLightness);
return hue;
},
// relies on apply and an arguments array like [{h, s, l}]
getHighlightedSaturation: function () {
var $thisEl = $(this),
hbWidth = $thisEl.outerWidth(),
halfHBWidth = hbWidth / 2,
position = parseInt($thisEl.css("left"),10) + halfHBWidth,
$advancedContainer = $thisEl.parents(".advanced-list"),
$advancedPreview = $advancedContainer.find(".color-preview"),
$lightnessSpectrum = $advancedContainer.find(".spectrum-lightness"),
$hueSpectrum = $advancedContainer.find(".spectrum-hue"),
$saturationValue = $advancedContainer.find(".saturation-value"),
spectrumWidth = parseInt($advancedContainer.find(".color-box").first().width(),10),
currentLightness = arguments[0].l,
lightnessString = (currentLightness * 100).toString() + "%",
currentHue = arguments[0].h;
if (spectrumWidth === 0) { // in case the width isn't set correctly
spectrumWidth = supportsTouch ? 160 : 300;
}
var saturation = position/spectrumWidth,
saturationString = Math.round((saturation * 100)).toString() + "%",
color = "hsl(" + currentHue + "," + saturationString + "," + lightnessString + ")";
color = "#" + tinycolor(color).toHex();
$advancedPreview.css("background-color",color);
$saturationValue.text(saturationString);
methods.updateLightnessStyles($lightnessSpectrum,currentHue,saturation);
methods.updateHueStyles($hueSpectrum,saturation,currentLightness);
return saturation;
},
updateAdvancedInstructions: function (instructionsEl) {
instructionsEl.html("Press the color preview to choose this color");
}
};
return this.each(function (index) {
methods.initialize.apply(this,[index]);
// commonly used DOM elements for each color picker
var myElements = {
thisEl: $(this),
thisWrapper: $(this).parent(),
colorTextInput: $(this).find("input"),
colorMenuLinks: $(this).parent().find(".color-menu li a"),
colorPreviewButton: $(this).parent().find(".input-group-btn"),
colorMenu: $(this).parent().find(".color-menu"),
colorSpectrums: $(this).parent().find(".color-box"),
basicSpectrums: $(this).parent().find(".basicColors-content .color-box"),
touchInstructions: $(this).parent().find(".color-menu-instructions"),
advancedInstructions: $(this).parent().find(".advanced-instructions"),
highlightBands: $(this).parent().find(".highlight-band"),
basicHighlightBands: $(this).parent().find(".basicColors-content .highlight-band")
};
var mostRecentClick, // for storing click events when needed
windowTopPosition, // for storing the position of the top of the window when needed
advancedStatus,
mySavedColorsInfo;
if (useTabs) {
myElements.tabs = myElements.thisWrapper.find(".tab");
}
if (settings.showSavedColors) {
myElements.savedColorsContent = myElements.thisWrapper.find(".savedColors-content");
if (settings.saveColorsPerElement) { // when saving colors for each color picker...
mySavedColorsInfo = {
colors: [],
dataObj: $(this).data()
};
$.each(mySavedColorsInfo.dataObj, function (key) {
mySavedColorsInfo.dataAttr = key;
});
// get this picker's colors from local storage if possible
if (supportsLocalStorage && localStorage["pickAColorSavedColors-" +
mySavedColorsInfo.dataAttr]) {
mySavedColorsInfo.colors = JSON.parse(localStorage["pickAColorSavedColors-" +
mySavedColorsInfo.dataAttr]);
// otherwise, get them from cookies
} else if (document.cookie.match("pickAColorSavedColors-" +
mySavedColorsInfo.dataAttr)) {
var theseCookies = document.cookie.split(";"); // an array of cookies...
for (var i=0; i < theseCookies.length; i++) {
if (theseCookies[i].match(mySavedColorsInfo.dataAttr)) {
mySavedColorsInfo.colors = theseCookies[i].split("=")[1].split(",");
}
}
} else { // if no data-attr specific colors are in local storage OR cookies...
mySavedColorsInfo.colors = allSavedColors; // use mySavedColors
}
}
}
if (settings.showAdvanced) {
advancedStatus = {
h: 0,
s: 1,
l: 0.5
};
myElements.advancedSpectrums = myElements.thisWrapper.find(".advanced-list").find(".color-box");
myElements.advancedHighlightBands = myElements.thisWrapper.find(".advanced-list").find(".highlight-band");
myElements.hueSpectrum = myElements.thisWrapper.find(".spectrum-hue");
myElements.lightnessSpectrum = myElements.thisWrapper.find(".spectrum-lightness");
myElements.saturationSpectrum = myElements.thisWrapper.find(".spectrum-saturation");
myElements.hueHighlightBand = myElements.thisWrapper.find(".spectrum-hue .highlight-band");
myElements.lightnessHighlightBand = myElements.thisWrapper.find(".spectrum-lightness .highlight-band");
myElements.saturationHighlightBand = myElements.thisWrapper.find(".spectrum-saturation .highlight-band");
myElements.advancedPreview = myElements.thisWrapper.find(".advanced-content .color-preview");
}
// add the default color to saved colors
methods.addToSavedColors(myColorVars.defaultColor,mySavedColorsInfo,myElements.savedColorsContent);
methods.updatePreview(myElements.thisEl);
//input field focus: clear content
// input field blur: update preview, restore previous content if no value entered
myElements.thisEl.focus(function () {
var $thisEl = $(this);
myColorVars.typedColor = $thisEl.val(); // update with the current
if (!settings.allowBlank) {
$thisEl.val(""); //clear the field on focus
}
methods.toggleDropdown(myElements.colorPreviewButton,myElements.ColorMenu);
}).blur(function () {
var $thisEl = $(this);
myColorVars.newValue = $thisEl.val(); // on blur, check the field's value
// if the field is empty, put the original value back in the field
if (myColorVars.newValue.match(/^\s+$|^$/)) {
if (!settings.allowBlank) {
$thisEl.val(myColorVars.typedColor);
}
} else { // otherwise...
myColorVars.newValue = tinycolor(myColorVars.newValue).toHex(); // convert to hex
$thisEl.val(myColorVars.newValue); // put the new value in the field
// save to saved colors
methods.addToSavedColors(myColorVars.newValue,mySavedColorsInfo,myElements.savedColorsContent);
}
methods.toggleDropdown(myElements.colorPreviewButton,myElements.ColorMenu);
methods.updatePreview($thisEl); // update preview
});
// toggle visibility of dropdown menu when you click or press the preview button
methods.executeUnlessScrolled.apply(myElements.colorPreviewButton,
[{"thisFunction": methods.pressPreviewButton, "theseArguments" : {}}]);
// any touch or click outside of a dropdown should close all dropdowns
methods.executeUnlessScrolled.apply($(document), [{"thisFunction": methods.closeDropdownIfOpen,
"theseArguments": {"button": myElements.colorPreviewButton, "menu": myElements.colorMenu}}]);
// prevent click/touchend to color-menu or color-text input from closing dropdown
myElements.colorMenu.on(clickEvent, function (e) {
e.stopPropagation();
});
myElements.thisEl.on(clickEvent, function(e) {
e.stopPropagation();
});
// update field and close menu when selecting from basic dropdown
methods.executeUnlessScrolled.apply(myElements.colorMenuLinks, [{"thisFunction": methods.selectFromBasicColors,
"theseArguments": {"els": myElements, "savedColorsInfo": mySavedColorsInfo}}]);
if (useTabs) { // make tabs tabbable
methods.tabbable.apply(myElements.tabs);
}
if (settings.showSpectrum || settings.showAdvanced) {
methods.horizontallyDraggable.apply(myElements.highlightBands);
}
// for using the light/dark spectrums
if (settings.showSpectrum) {
// move the highlight band when you click on a spectrum
methods.executeUnlessScrolled.apply(myElements.basicSpectrums, [{"thisFunction": methods.tapSpectrum,
"theseArguments": {"savedColorsInfo": mySavedColorsInfo, "els": myElements}}]);
$(myElements.basicHighlightBands).on(dragEvent,function (event) {
var $thisEl = event.target;
methods.calculateHighlightedColor.apply(this, [{type: "basic"}]);
}).on(endDragEvent, function (event) {
var $thisEl = event.delegateTarget;
var finalColor = methods.calculateHighlightedColor.apply($thisEl, [{type: "basic"}]);
methods.addToSavedColors(finalColor,mySavedColorsInfo,myElements.savedColorsContent);
});
}
if (settings.showAdvanced) {
// for dragging advanced sliders
$(myElements.hueHighlightBand).on(dragEvent, function(event) {
advancedStatus.h = methods.getHighlightedHue.apply(this, [advancedStatus]);
});
$(myElements.lightnessHighlightBand).on(dragEvent, function() {
methods.calculateHighlightedColor.apply(this, [{"type": "advanced", "hsl": advancedStatus}]);
}).on(endEvent, function () {
advancedStatus.l = methods.calculateHighlightedColor.apply(this, [{"type": "advanced", "hsl": advancedStatus}]);
});
$(myElements.saturationHighlightBand).on(dragEvent, function() {
methods.getHighlightedSaturation.apply(this, [advancedStatus]);
}).on(endDragEvent, function () {
advancedStatus.s = methods.getHighlightedSaturation.apply(this, [advancedStatus]);
});
$(myElements.advancedHighlightBand).on(endDragEvent, function () {
methods.updateAdvancedInstructions(myElements.advancedInstructions);
});
// for clicking/tapping advanced sliders
$(myElements.lightnessSpectrum).click( function (event) {
event.stopPropagation(); // stop this click from closing the dropdown
var $highlightBand = $(this).find(".highlight-band"),
dimensions = methods.getMoveableArea($highlightBand);
methods.moveHighlightBand($highlightBand, dimensions, event);
advancedStatus.l = methods.calculateHighlightedColor.apply($highlightBand, [{"type": "advanced", "hsl": advancedStatus}]);
});
$(myElements.hueSpectrum).click( function (event) {
event.stopPropagation(); // stop this click from closing the dropdown
var $highlightBand = $(this).find(".highlight-band"),
dimensions = methods.getMoveableArea($highlightBand);
methods.moveHighlightBand($highlightBand, dimensions, event);
advancedStatus.h = methods.getHighlightedHue.apply($highlightBand, [advancedStatus]);
});
$(myElements.saturationSpectrum).click( function (event) {
event.stopPropagation(); // stop this click from closing the dropdown
var $highlightBand = $(this).find(".highlight-band"),
dimensions = methods.getMoveableArea($highlightBand);
methods.moveHighlightBand($highlightBand, dimensions, event);
advancedStatus.s = methods.getHighlightedSaturation.apply($highlightBand, [advancedStatus]);
});
$(myElements.advancedSpectrums).click( function () {
methods.updateAdvancedInstructions(myElements.advancedInstructions);
});
//for clicking advanced color preview
$(myElements.advancedPreview).click( function () {
var selectedColor = tinycolor($(this).css("background-color")).toHex();
$(myElements.thisEl).val(selectedColor);
$(myElements.thisEl).trigger("change");
methods.updatePreview(myElements.thisEl);
methods.addToSavedColors(selectedColor,mySavedColorsInfo,myElements.savedColorsContent);
methods.closeDropdown(myElements.colorPreviewButton,myElements.colorMenu); // close the dropdown
});
}
// for using saved colors
if (settings.showSavedColors) {
// make the links in saved colors work
$(myElements.savedColorsContent).click( function (event) {
var $thisEl = $(event.target);
// make sure click happened on a link or span
if ($thisEl.is("SPAN") || $thisEl.is("A")) {
//grab the color the link's class or span's parent link's class
var selectedColor = $thisEl.is("SPAN") ?
$thisEl.parent().attr("class").split("#")[1] :
$thisEl.attr("class").split("#")[1];
$(myElements.thisEl).val(selectedColor);
$(myElements.thisEl).trigger("change");
methods.updatePreview(myElements.thisEl);
methods.closeDropdown(myElements.colorPreviewButton,myElements.colorMenu);
methods.addToSavedColors(selectedColor,mySavedColorsInfo,myElements.savedColorsContent);
}
});
// update saved color markup with content from localStorage or cookies, if available
if (!settings.saveColorsPerElement) {
methods.updateSavedColorMarkup(myElements.savedColorsContent,allSavedColors);
} else if (settings.saveColorsPerElement) {
methods.updateSavedColorMarkup(myElements.savedColorsContent,mySavedColorsInfo.colors);
}
}
});
};
})(jQuery);