--- /dev/null
+/**
+ * jQuery Wheel Color Picker
+ *
+ * https://raffer.one/projects/jquery-wheelcolorpicker
+ *
+ * Author : Fajar Chandra
+ * Date : 2018.02.09
+ *
+ * Copyright © 2011-2018 Fajar Chandra. All rights reserved.
+ * Released under MIT License.
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+(function ($) {
+
+ /**
+ * Function: wheelColorPicker
+ *
+ * The wheelColorPicker plugin wrapper. Firing all functions and
+ * setting/getting all options in this plugin should be called via
+ * this function.
+ *
+ * Before that, if wheelColorPicker instance is not yet initialized,
+ * this will initialize ColorPicker widget.
+ *
+ * This function will look for the options parameter passed in, and
+ * try to do something as specified in this order:
+ * 1. If no argument is passed, then initialize the plugin or do nothing
+ * 2. If object is passed, then call setOptions()
+ * 3. If string is passed, then try to fire a method with that name
+ * 4. If string is passed and no method matches the name, then try
+ * to set/get an option with that name. If a setter/getter method
+ * available (i.e. setSomething), it will set/get that option via that method.
+ */
+ $.fn.wheelColorPicker = function() {
+ var returnValue = this; // Allows method chaining
+
+ // Separate first argument and the rest..
+ // First argument is used to determine function/option name
+ // e.g. wheelColorPicker('setColor', { r: 0, g: 0, b: 1 })
+ if(arguments.length > 0) {
+ var shift = [].shift;
+ var firstArg = shift.apply(arguments);
+ var firstArgUc = (typeof firstArg === "string") ? firstArg.charAt(0).toUpperCase() + firstArg.slice(1) : firstArg;
+ }
+ else {
+ var firstArg = undefined;
+ var firstArgUc = undefined;
+ }
+ var args = arguments;
+
+
+ this.each(function() {
+
+ // Grab ColorPicker object instance
+ var instance = $(this).data('jQWCP.instance');
+
+ // Initialize if not yet created
+ if(instance == undefined || instance == null) {
+ // Get init options
+ var options = {};
+ if(typeof firstArg === "object") {
+ options = firstArg;
+ }
+
+ instance = new WCP.ColorPicker(this, options);
+ $(this).data('jQWCP.instance', instance);
+ }
+
+ /// What to do? ///
+
+ // No arguments provided, do nothing
+ // wheelColorPicker()
+ if(firstArg === undefined || typeof firstArg === "object") {
+ }
+
+ // Call a method
+ // wheelColorPicker('show')
+ else if(typeof instance[firstArg] === "function") {
+ //console.log('method');
+ var ret = instance[firstArg].apply(instance, args);
+
+ // If instance is not returned, no method chaining
+ if(ret !== instance) {
+ returnValue = ret;
+ return false;
+ }
+ }
+
+ // Try option setter
+ // wheelColorPicker('color', '#ff00aa')
+ else if(typeof instance['set'+firstArgUc] === "function" && args.length > 0) {
+ //console.log('setter');
+ var ret = instance['set'+firstArgUc].apply(instance, args);
+
+ // If instance is not returned, no method chaining
+ if(ret !== instance) {
+ returnValue = ret;
+ return false;
+ }
+ }
+
+ // Try option getter
+ // wheelColorPicker('color')
+ else if(typeof instance['get'+firstArgUc] === "function") {
+ //console.log('getter');
+ var ret = instance['get'+firstArgUc].apply(instance, args);
+
+ // If instance is not returned, no method chaining
+ if(ret !== instance) {
+ returnValue = ret;
+ return false;
+ }
+ }
+
+ // Set option value
+ // wheelColorPicker('format', 'hex')
+ else if(instance.options[firstArg] !== undefined && args.length > 0) {
+ //console.log('set option');
+ instance.options[firstArg] = args[0];
+ }
+
+ // Get option value
+ // wheelColorPicker('format')
+ else if(instance.options[firstArg] !== undefined) {
+ //console.log('get option');
+ returnValue = instance.options[firstArg];
+ return false;
+ }
+
+ // Nothing matches, throw error
+ else {
+ $.error( 'Method/option named ' + firstArg + ' does not exist on jQuery.wheelColorPicker' );
+ }
+
+ });
+
+ return returnValue;
+ };
+
+
+
+ /******************************************************************/
+
+ /////////////////////////////////////////
+ // Shorthand for $.fn.wheelColorPicker //
+ /////////////////////////////////////////
+ var WCP = $.fn.wheelColorPicker;
+ /////////////////////////////////////////
+
+ /**
+ * Object: defaults
+ *
+ * Contains default options for the wheelColorPicker plugin.
+ *
+ * Member properties:
+ *
+ * format - <string> Color naming style. See colorToRgb for all
+ * available formats.
+ * live - <boolean> Enable dynamic slider gradients.
+ * preview - <boolean> Enable live color preview on input field
+ * userinput - (Deprecated) <boolean> Enable picking color by typing directly
+ * validate - <boolean> When userinput is enabled, force the value to be
+ * a valid format. If user input an invalid color, the value
+ * will be reverted to last valid color.
+ * autoResize - <boolean> Automatically resize container width.
+ * If set to false, you could manually adjust size with CSS.
+ * autoFormat - <boolean> Automatically convert input value to
+ * specified format. For example, if format is "rgb",
+ * "#ff0000" will automatically converted into "rgb(255,0,0)".
+ * color - <object|string> Initial value in any of supported color
+ * value format or as an object. Setting this value will
+ * override the current input value.
+ * alpha - (Deprecated) <boolean> Force the color picker to use alpha value
+ * despite its selected color format. This option is
+ * deprecated. Use sliders = "a" instead.
+ * inverseLabel - (deprecated) Boolean use inverse color for
+ * input label instead of black/white color.
+ * preserveWheel - Boolean preserve color wheel shade when slider
+ * position changes. If set to true, changing
+ * color wheel from black will reset selectedColor.val
+ * (shade) to 1.
+ * interactive - Boolean enable interactive sliders where slider bar
+ * gradients change dynamically as user drag a slider
+ * handle. Set to false if this affect performance.
+ * See also 'quality' option if you wish to keep
+ * interactive slider but with reduced quality.
+ * cssClass - Object CSS Classes to be added to the color picker.
+ * layout - String [block|popup] Layout mode.
+ * animDuration - Number Duration for transitions such as fade-in
+ * and fade-out.
+ * quality - Rendering details quality. The normal quality is 1.
+ * Setting less than 0.1 may make the sliders ugly,
+ * while setting the value too high might affect performance.
+ * sliders - String combination of sliders. If null then the color
+ * picker will show default values, which is "wvp" for
+ * normal color or "wvap" for color with alpha value.
+ * Possible combinations are "whsvrgbap".
+ * Order of letters will affect slider positions.
+ * sliderLabel - Boolean Show labels for each slider.
+ * sliderValue - Boolean Show numeric value of each slider.
+ * hideKeyboard - Boolean Keep input blurred to avoid on screen keyboard appearing.
+ * If this is set to true, avoid assigning handler to blur event.
+ * rounding - Round the alpha value to N decimal digits. Default is 2.
+ * Set -1 to disable rounding.
+ * mobile - Display mobile-friendly layout when opened in mobile device.
+ * mobileWidth - Max screen width to use mobile layout instead of default one.
+ * mobileAutoScroll - Automatically scroll the page if focused input element
+ * gets obstructed by color picker dialog.
+ * htmlOptions - Load options from HTML attributes.
+ * To set options using HTML attributes,
+ * prefix these options with 'data-wcp-' as attribute names.
+ * snap - Snap color wheel and slider on 0, 0.5, and 1.0
+ * snapTolerance - Snap if slider position falls within defined
+ * tolerance value.
+ */
+ WCP.defaults = {
+ format: 'hex', /* 1.x */
+ preview: false, /* 1.x */
+ live: true, /* 2.0 */
+ userinput: true, /* DEPRECATED 1.x */
+ validate: true, /* 1.x */
+ autoResize: true, /* 3.0 */
+ autoFormat: true, /* 3.0 */
+ //color: null, /* DEPRECATED 1.x */ /* OBSOLETE 3.0 */ /* Init-time only */
+ //alpha: null, /* DEPRECATED 1.x */ /* OBSOLETE 3.0 */ /* See methods.alpha */
+ preserveWheel: null, /* DEPRECATED 1.x */ /* Use live */
+ cssClass: '', /* 2.0 */
+ layout: 'popup', /* 2.0 */ /* Init-time only */
+ animDuration: 200, /* 2.0 */
+ quality: 1, /* 2.0 */
+ sliders: null, /* 2.0 */
+ //sliderLabel: true, /* 2.0 */ /* NOT IMPLEMENTED */
+ //sliderValue: false, /* 2.0 */ /* NOT IMPLEMENTED */
+ rounding: 2, /* 2.3 */
+ mobile: true, /* 3.0 */
+ mobileWidth: 480, /* 3.0 */
+ hideKeyboard: false, /* 2.4 */
+ htmlOptions: true, /* 2.3 */
+ snap: false, /* 2.5 */
+ snapTolerance: 0.05 /* 2.5 */
+ };
+
+
+
+ /******************************************************************/
+
+ //////////////////////////////
+ // STATIC OBJECTS AND FLAGS //
+ //////////////////////////////
+
+ /*
+ * Note: To determine input position (top and left), use the following:
+ * WCP.ORIGIN.top + this.input.getBoundingClientRect().top
+ * instead of using $(this.input).offset().top because on mobile browsers
+ * (chrome) jQuery's offset() function returns wrong value.
+ */
+
+ /// Top left of the page is not on (0,0), making window.scrollX/Y and offset() useless
+ /// See WCP.ORIGIN
+ WCP.BUG_RELATIVE_PAGE_ORIGIN = false;
+
+ /// Coordinate of the top left page (mobile chrome workaround)
+ WCP.ORIGIN = { left: 0, top: 0 };
+
+
+ /******************************************************************/
+
+ //////////////////////
+ // HELPER FUNCTIONS //
+ //////////////////////
+
+ /**
+ * Function: colorToStr
+ *
+ * Since 2.0
+ *
+ * Convert color object to string in specified format
+ *
+ * Available formats:
+ * - hex
+ * - hexa
+ * - css
+ * - cssa
+ * - rgb
+ * - rgb%
+ * - rgba
+ * - rgba%
+ * - hsv
+ * - hsv%
+ * - hsva
+ * - hsva%
+ * - hsb
+ * - hsb%
+ * - hsba
+ * - hsba%
+ */
+ WCP.colorToStr = function( color, format ) {
+ var result = "";
+ switch( format ) {
+ case 'css':
+ result = "#";
+ case 'hex':
+ var r = Math.round(color.r * 255).toString(16);
+ if( r.length == 1) {
+ r = "0" + r;
+ }
+ var g = Math.round(color.g * 255).toString(16);
+ if( g.length == 1) {
+ g = "0" + g;
+ }
+ var b = Math.round(color.b * 255).toString(16);
+ if( b.length == 1) {
+ b = "0" + b;
+ }
+ result += r + g + b;
+ break;
+
+ case 'cssa':
+ result = "#";
+ case 'hexa':
+ var r = Math.round(color.r * 255).toString(16);
+ if( r.length == 1) {
+ r = "0" + r;
+ }
+ var g = Math.round(color.g * 255).toString(16);
+ if( g.length == 1) {
+ g = "0" + g;
+ }
+ var b = Math.round(color.b * 255).toString(16);
+ if( b.length == 1) {
+ b = "0" + b;
+ }
+ var a = Math.round(color.a * 255).toString(16);
+ if( a.length == 1) {
+ a = "0" + a;
+ }
+ result += r + g + b + a;
+ break;
+
+ case 'rgb':
+ result = "rgb(" +
+ Math.round(color.r * 255) + "," +
+ Math.round(color.g * 255) + "," +
+ Math.round(color.b * 255) + ")";
+ break;
+
+ case 'rgb%':
+ result = "rgb(" +
+ (color.r * 100) + "%," +
+ (color.g * 100) + "%," +
+ (color.b * 100) + "%)";
+ break;
+
+ case 'rgba':
+ result = "rgba(" +
+ Math.round(color.r * 255) + "," +
+ Math.round(color.g * 255) + "," +
+ Math.round(color.b * 255) + "," +
+ color.a + ")";
+ break;
+
+ case 'rgba%':
+ result = "rgba(" +
+ (color.r * 100) + "%," +
+ (color.g * 100) + "%," +
+ (color.b * 100) + "%," +
+ (color.a * 100) + "%)";
+ break;
+
+ case 'hsv':
+ result = "hsv(" +
+ (color.h * 360) + "," +
+ color.s + "," +
+ color.v + ")";
+ break;
+
+ case 'hsv%':
+ result = "hsv(" +
+ (color.h * 100) + "%," +
+ (color.s * 100) + "%," +
+ (color.v * 100) + "%)";
+ break;
+
+ case 'hsva':
+ result = "hsva(" +
+ (color.h * 360) + "," +
+ color.s + "," +
+ color.v + "," +
+ color.a + ")";
+ break;
+
+ case 'hsva%':
+ result = "hsva(" +
+ (color.h * 100) + "%," +
+ (color.s * 100) + "%," +
+ (color.v * 100) + "%," +
+ (color.a * 100) + "%)";
+ break;
+
+
+ case 'hsb':
+ result = "hsb(" +
+ color.h + "," +
+ color.s + "," +
+ color.v + ")";
+ break;
+
+ case 'hsb%':
+ result = "hsb(" +
+ (color.h * 100) + "%," +
+ (color.s * 100) + "%," +
+ (color.v * 100) + "%)";
+ break;
+
+ case 'hsba':
+ result = "hsba(" +
+ color.h + "," +
+ color.s + "," +
+ color.v + "," +
+ color.a + ")";
+ break;
+
+ case 'hsba%':
+ result = "hsba(" +
+ (color.h * 100) + "%," +
+ (color.s * 100) + "%," +
+ (color.v * 100) + "%," +
+ (color.a * 100) + "%)";
+ break;
+
+ }
+ return result;
+ };
+
+
+ /**
+ * Function: strToColor
+ *
+ * Since 2.0
+ *
+ * Convert string to color object.
+ * Please note that if RGB color is supplied, the returned value
+ * will only contain RGB.
+ *
+ * If invalid string is supplied, FALSE will be returned.
+ */
+ WCP.strToColor = function( val ) {
+ var color = { a: 1 };
+ var tmp;
+ var hasAlpha;
+
+ // #fff
+ // #ffff
+ if(
+ val.match(/^#[0-9a-f]{3}$/i) != null ||
+ val.match(/^#[0-9a-f]{4}$/i)
+ ) {
+ if( isNaN( color.r = parseInt(val.substr(1, 1), 16) * 17 / 255 ) ) {
+ return false;
+ }
+ if( isNaN( color.g = parseInt(val.substr(2, 1), 16) * 17 / 255 ) ) {
+ return false;
+ }
+ if( isNaN( color.b = parseInt(val.substr(3, 1), 16) * 17 / 255 ) ) {
+ return false;
+ }
+
+ // Alpha
+ if(val.length == 5) {
+ if( isNaN( color.a = parseInt(val.substr(4, 1), 16) * 17 / 255 ) ) {
+ return false;
+ }
+ }
+ }
+
+ // fff
+ // ffff
+ else if(
+ val.match(/^[0-9a-f]{3}$/i) != null ||
+ val.match(/^[0-9a-f]{4}$/i) != null
+ ) {
+ if( isNaN( color.r = parseInt(val.substr(0, 1), 16) * 17 / 255 ) ) {
+ return false;
+ }
+ if( isNaN( color.g = parseInt(val.substr(1, 1), 16) * 17 / 255 ) ) {
+ return false;
+ }
+ if( isNaN( color.b = parseInt(val.substr(2, 1), 16) * 17 / 255 ) ) {
+ return false;
+ }
+
+ // Alpha
+ if(val.length == 4) {
+ if( isNaN( color.a = parseInt(val.substr(3, 1), 16) * 17 / 255 ) ) {
+ return false;
+ }
+ }
+ }
+
+ // #ffffff
+ // #ffffffff
+ else if(
+ val.match(/^#[0-9a-f]{6}$/i) != null ||
+ val.match(/^#[0-9a-f]{8}$/i) != null
+ ) {
+ if( isNaN( color.r = parseInt(val.substr(1, 2), 16) / 255 ) ) {
+ return false;
+ }
+ if( isNaN( color.g = parseInt(val.substr(3, 2), 16) / 255 ) ) {
+ return false;
+ }
+ if( isNaN( color.b = parseInt(val.substr(5, 2), 16) / 255 ) ) {
+ return false;
+ }
+
+ // Alpha
+ if(val.length == 9) {
+ if( isNaN( color.a = parseInt(val.substr(7, 2), 16) / 255 ) ) {
+ return false;
+ }
+ }
+ }
+
+ // ffffff
+ // ffffffff
+ else if(
+ val.match(/^[0-9a-f]{6}$/i) != null ||
+ val.match(/^[0-9a-f]{8}$/i) != null
+ ) {
+ if( isNaN( color.r = parseInt(val.substr(0, 2), 16) / 255 ) ) {
+ return false;
+ }
+ if( isNaN( color.g = parseInt(val.substr(2, 2), 16) / 255 ) ) {
+ return false;
+ }
+ if( isNaN( color.b = parseInt(val.substr(4, 2), 16) / 255 ) ) {
+ return false;
+ }
+
+ // Alpha
+ if(val.length == 8) {
+ if( isNaN( color.a = parseInt(val.substr(6, 2), 16) / 255 ) ) {
+ return false;
+ }
+ }
+ }
+
+ // rgb(100%,100%,100%)
+ // rgba(100%,100%,100%,100%)
+ // rgba(255,255,255,1)
+ // rgba(100%,1, 0.5,.2)
+ else if(
+ val.match(/^rgba\s*\(\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*,\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*,\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*,\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*\)$/i) != null ||
+ val.match(/^rgb\s*\(\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*,\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*,\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*\)$/i) != null
+ ) {
+ if(val.match(/a/i) != null) {
+ hasAlpha = true;
+ }
+ else {
+ hasAlpha = false;
+ }
+
+ tmp = val.substring(val.indexOf('(')+1, val.indexOf(','));
+ if( tmp.charAt( tmp.length-1 ) == '%') {
+ if( isNaN( color.r = parseFloat(tmp) / 100 ) ) {
+ return false;
+ }
+ }
+ else {
+ if( isNaN( color.r = parseInt(tmp) / 255 ) ) {
+ return false;
+ }
+ }
+
+ tmp = val.substring(val.indexOf(',')+1, val.indexOf(',', val.indexOf(',')+1));
+ if( tmp.charAt( tmp.length-1 ) == '%') {
+ if( isNaN( color.g = parseFloat(tmp) / 100 ) ) {
+ return false;
+ }
+ }
+ else {
+ if( isNaN( color.g = parseInt(tmp) / 255 ) ) {
+ return false;
+ }
+ }
+
+ if(hasAlpha) {
+ tmp = val.substring(val.indexOf(',', val.indexOf(',')+1)+1, val.lastIndexOf(','));
+ }
+ else {
+ tmp = val.substring(val.lastIndexOf(',')+1, val.lastIndexOf(')'));
+ }
+ if( tmp.charAt( tmp.length-1 ) == '%') {
+ if( isNaN( color.b = parseFloat(tmp) / 100 ) ) {
+ return false;
+ }
+ }
+ else {
+ if( isNaN( color.b = parseInt(tmp) / 255 ) ) {
+ return false;
+ }
+ }
+
+ if(hasAlpha) {
+ tmp = val.substring(val.lastIndexOf(',')+1, val.lastIndexOf(')'));
+ if( tmp.charAt( tmp.length-1 ) == '%') {
+ if( isNaN( color.a = parseFloat(tmp) / 100 ) ) {
+ return false;
+ }
+ }
+ else {
+ if( isNaN( color.a = parseFloat(tmp) ) ) {
+ return false;
+ }
+ }
+ }
+ }
+
+ // hsv(100%,100%,100%)
+ // hsva(100%,100%,100%,100%)
+ // hsv(360,1,1,1)
+ // hsva(360,1, 0.5,.2)
+ // hsb(100%,100%,100%)
+ // hsba(100%,100%,100%,100%)
+ // hsb(360,1,1,1)
+ // hsba(360,1, 0.5,.2)
+ else if(
+ val.match(/^hsva\s*\(\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*,\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*,\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*,\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*\)$/i) != null ||
+ val.match(/^hsv\s*\(\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*,\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*,\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*\)$/i) != null ||
+ val.match(/^hsba\s*\(\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*,\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*,\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*,\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*\)$/i) != null ||
+ val.match(/^hsb\s*\(\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*,\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*,\s*([0-9\.]+%|[01]?\.?[0-9]*)\s*\)$/i) != null
+ ) {
+ if(val.match(/a/i) != null) {
+ hasAlpha = true;
+ }
+ else {
+ hasAlpha = false;
+ }
+
+ tmp = val.substring(val.indexOf('(')+1, val.indexOf(','));
+ if( tmp.charAt( tmp.length-1 ) == '%') {
+ if( isNaN( color.h = parseFloat(tmp) / 100 ) ) {
+ return false;
+ }
+ }
+ else {
+ if( isNaN( color.h = parseFloat(tmp) / 360 ) ) {
+ return false;
+ }
+ }
+
+ tmp = val.substring(val.indexOf(',')+1, val.indexOf(',', val.indexOf(',')+1));
+ if( tmp.charAt( tmp.length-1 ) == '%') {
+ if( isNaN( color.s = parseFloat(tmp) / 100 ) ) {
+ return false;
+ }
+ }
+ else {
+ if( isNaN( color.s = parseFloat(tmp) ) ) {
+ return false;
+ }
+ }
+
+ if(hasAlpha) {
+ tmp = val.substring(val.indexOf(',', val.indexOf(',')+1)+1, val.lastIndexOf(','));
+ }
+ else {
+ tmp = val.substring(val.lastIndexOf(',')+1, val.lastIndexOf(')'));
+ }
+ if( tmp.charAt( tmp.length-1 ) == '%') {
+ if( isNaN( color.v = parseFloat(tmp) / 100 ) ) {
+ return false;
+ }
+ }
+ else {
+ if( isNaN( color.v = parseFloat(tmp) ) ) {
+ return false;
+ }
+ }
+
+ if(hasAlpha) {
+ tmp = val.substring(val.lastIndexOf(',')+1, val.lastIndexOf(')'));
+ if( tmp.charAt( tmp.length-1 ) == '%') {
+ if( isNaN( color.a = parseFloat(tmp) / 100 ) ) {
+ return false;
+ }
+ }
+ else {
+ if( isNaN( color.a = parseFloat(tmp) ) ) {
+ return false;
+ }
+ }
+ }
+ }
+
+ else {
+ return false;
+ }
+
+ return color;
+ };
+
+
+ /**
+ * Function: hsvToRgb
+ *
+ * Since 2.0
+ *
+ * Perform HSV to RGB conversion
+ */
+ WCP.hsvToRgb = function( h, s, v ) {
+
+ // Calculate RGB from hue (1st phase)
+ var cr = (h <= (1/6) || h >= (5/6)) ? 1
+ : (h < (1/3) ? 1 - ((h - (1/6)) * 6)
+ : (h > (4/6) ? (h - (4/6)) * 6
+ : 0));
+ var cg = (h >= (1/6) && h <= (3/6)) ? 1
+ : (h < (1/6) ? h * 6
+ : (h < (4/6) ? 1 - ((h - (3/6)) * 6)
+ : 0));
+ var cb = (h >= (3/6) && h <= (5/6)) ? 1
+ : (h > (2/6) && h < (3/6) ? (h - (2/6)) * 6
+ : (h > (5/6) ? 1 - ((h - (5/6)) * 6)
+ : 0));
+
+ //~ console.log(cr + ' ' + cg + ' ' + cb);
+
+ // Calculate RGB with saturation & value applied
+ var r = (cr + (1-cr)*(1-s)) * v;
+ var g = (cg + (1-cg)*(1-s)) * v;
+ var b = (cb + (1-cb)*(1-s)) * v;
+
+ //~ console.log(r + ' ' + g + ' ' + b + ' ' + v);
+
+ return { r: r, g: g, b: b };
+ };
+
+
+ /**
+ * Function: rgbToHsv
+ *
+ * Since 2.0
+ *
+ * Perform RGB to HSV conversion
+ */
+ WCP.rgbToHsv = function( r, g, b ) {
+
+ var h;
+ var s;
+ var v;
+
+ var maxColor = Math.max(r, g, b);
+ var minColor = Math.min(r, g, b);
+ var delta = maxColor - minColor;
+
+ // Calculate saturation
+ if(maxColor != 0) {
+ s = delta / maxColor;
+ }
+ else {
+ s = 0;
+ }
+
+ // Calculate hue
+ // To simplify the formula, we use 0-6 range.
+ if(delta == 0) {
+ h = 0;
+ }
+ else if(r == maxColor) {
+ h = (6 + (g - b) / delta) % 6;
+ }
+ else if(g == maxColor) {
+ h = 2 + (b - r) / delta;
+ }
+ else if(b == maxColor) {
+ h = 4 + (r - g) / delta;
+ }
+ else {
+ h = 0;
+ }
+ // Then adjust the range to be 0-1
+ h = h/6;
+
+ // Calculate value
+ v = maxColor;
+
+ //~ console.log(h + ' ' + s + ' ' + v);
+
+ return { h: h, s: s, v: v };
+ };
+
+
+
+ /******************************************************************/
+
+ ////////////////////////
+ // COLOR PICKER CLASS //
+ ////////////////////////
+
+ /**
+ * Class: ColorPicker
+ *
+ * Since 3.0
+ */
+ WCP.ColorPicker = function ( elm, options ) {
+
+ // Assign reference to input DOM element
+ this.input = elm;
+
+ // Setup selected color in the following priority:
+ // 1. options.color
+ // 2. input.value
+ // 3. default
+ this.color = { h: 0, s: 0, v: 1, r: 1, g: 1, b: 1, a: 1 };
+ this.setValue(this.input.value);
+
+ // Set options
+ this.options = $.extend(true, {}, WCP.defaults);
+ this.setOptions(options);
+
+ // Check sliders option, if not defined, set default sliders
+ if(this.options.sliders == null)
+ this.options.sliders = 'wvp' + (this.options.format.indexOf('a') >= 0 ? 'a' : '');
+
+ this.init();
+ };
+
+
+ ////////////////////
+ // Static members //
+ ////////////////////
+
+
+ /**
+ * Static Property: ColorPicker.widget
+ *
+ * Reference to global color picker widget (popup)
+ */
+ WCP.ColorPicker.widget = null;
+
+
+ /**
+ * Property: ColorPicker.overlay
+ *
+ * Reference to overlay DOM element (overlay for global popup)
+ */
+ WCP.ColorPicker.overlay = null;
+
+
+ /**
+ * Function: init
+ *
+ * Since 3.0
+ * 2.0 was methods.staticInit
+ *
+ * Initialize wheel color picker globally.
+ */
+ WCP.ColorPicker.init = function() {
+ // Only perform initialization once
+ if(WCP.ColorPicker.init.hasInit == true)
+ return;
+ WCP.ColorPicker.init.hasInit = true;
+
+ // Insert overlay element to handle popup closing
+ // when hideKeyboard is true, hence input is always blurred
+ var $overlay = $('<div class="jQWCP-overlay" style="display: none;"></div>');
+ $overlay.on('click', WCP.Handler.overlay_click);
+ WCP.ColorPicker.overlay = $overlay.get(0);
+ $('body').append($overlay);
+
+ // Insert CSS for color wheel
+ var wheelImage = WCP.ColorPicker.getWheelDataUrl(200);
+ $('head').append(
+ '<style type="text/css">' +
+ '.jQWCP-wWheel {' +
+ 'background-image: url(' + wheelImage + ');' +
+ '}' +
+ '</style>'
+ );
+
+ // Attach events
+ $('html').on('mouseup.wheelColorPicker', WCP.Handler.html_mouseup);
+ $('html').on('touchend.wheelColorPicker', WCP.Handler.html_mouseup);
+ $('html').on('mousemove.wheelColorPicker', WCP.Handler.html_mousemove);
+ $('html').on('touchmove.wheelColorPicker', WCP.Handler.html_mousemove);
+ $(window).on('resize.wheelColorPicker', WCP.Handler.window_resize);
+ };
+
+
+ /**
+ * Function: createWidget
+ *
+ * Since 3.0
+ * 2.5 was private.initWidget
+ *
+ * Create color picker widget.
+ */
+ WCP.ColorPicker.createWidget = function() {
+ /// WIDGET ///
+ // Notice: We won't use canvas to draw the color wheel since
+ // it may takes time and cause performance issue.
+ var $widget = $(
+ "<div class='jQWCP-wWidget'>" +
+ "<div class='jQWCP-wWheel'>" +
+ "<div class='jQWCP-wWheelOverlay'></div>" +
+ "<span class='jQWCP-wWheelCursor'></span>" +
+ "</div>" +
+ "<div class='jQWCP-wHue jQWCP-slider-wrapper'>" +
+ "<canvas class='jQWCP-wHueSlider jQWCP-slider' width='1' height='50' title='Hue'></canvas>" +
+ "<span class='jQWCP-wHueCursor jQWCP-scursor'></span>" +
+ "</div>" +
+ "<div class='jQWCP-wSat jQWCP-slider-wrapper'>" +
+ "<canvas class='jQWCP-wSatSlider jQWCP-slider' width='1' height='50' title='Saturation'></canvas>" +
+ "<span class='jQWCP-wSatCursor jQWCP-scursor'></span>" +
+ "</div>" +
+ "<div class='jQWCP-wVal jQWCP-slider-wrapper'>" +
+ "<canvas class='jQWCP-wValSlider jQWCP-slider' width='1' height='50' title='Value'></canvas>" +
+ "<span class='jQWCP-wValCursor jQWCP-scursor'></span>" +
+ "</div>" +
+ "<div class='jQWCP-wRed jQWCP-slider-wrapper'>" +
+ "<canvas class='jQWCP-wRedSlider jQWCP-slider' width='1' height='50' title='Red'></canvas>" +
+ "<span class='jQWCP-wRedCursor jQWCP-scursor'></span>" +
+ "</div>" +
+ "<div class='jQWCP-wGreen jQWCP-slider-wrapper'>" +
+ "<canvas class='jQWCP-wGreenSlider jQWCP-slider' width='1' height='50' title='Green'></canvas>" +
+ "<span class='jQWCP-wGreenCursor jQWCP-scursor'></span>" +
+ "</div>" +
+ "<div class='jQWCP-wBlue jQWCP-slider-wrapper'>" +
+ "<canvas class='jQWCP-wBlueSlider jQWCP-slider' width='1' height='50' title='Blue'></canvas>" +
+ "<span class='jQWCP-wBlueCursor jQWCP-scursor'></span>" +
+ "</div>" +
+ "<div class='jQWCP-wAlpha jQWCP-slider-wrapper'>" +
+ "<canvas class='jQWCP-wAlphaSlider jQWCP-slider' width='1' height='50' title='Alpha'></canvas>" +
+ "<span class='jQWCP-wAlphaCursor jQWCP-scursor'></span>" +
+ "</div>" +
+ "<div class='jQWCP-wPreview'>" +
+ "<canvas class='jQWCP-wPreviewBox' width='1' height='1' title='Selected Color'></canvas>" +
+ "</div>" +
+ "</div>"
+ );
+
+ // Small UI fix to disable highlighting the widget
+ // Also UI fix to disable touch context menu
+ $widget.find('.jQWCP-wWheel, .jQWCP-slider-wrapper, .jQWCP-scursor, .jQWCP-slider')
+ .attr('unselectable', 'on')
+ .css('-moz-user-select', 'none')
+ .css('-webkit-user-select', 'none')
+ .css('user-select', 'none')
+ .css('-webkit-touch-callout', 'none');
+
+ // Disable context menu on sliders
+ // Workaround for touch browsers
+ $widget.on('contextmenu.wheelColorPicker', function() { return false; });
+
+ // Bind widget events
+ $widget.on('mousedown.wheelColorPicker', '.jQWCP-wWheel', WCP.Handler.wheel_mousedown);
+ $widget.on('touchstart.wheelColorPicker', '.jQWCP-wWheel', WCP.Handler.wheel_mousedown);
+ $widget.on('mousedown.wheelColorPicker', '.jQWCP-wWheelCursor', WCP.Handler.wheelCursor_mousedown);
+ $widget.on('touchstart.wheelColorPicker', '.jQWCP-wWheelCursor', WCP.Handler.wheelCursor_mousedown);
+ $widget.on('mousedown.wheelColorPicker', '.jQWCP-slider', WCP.Handler.slider_mousedown);
+ $widget.on('touchstart.wheelColorPicker', '.jQWCP-slider', WCP.Handler.slider_mousedown);
+ $widget.on('mousedown.wheelColorPicker', '.jQWCP-scursor', WCP.Handler.sliderCursor_mousedown);
+ $widget.on('touchstart.wheelColorPicker', '.jQWCP-scursor', WCP.Handler.sliderCursor_mousedown);
+
+ return $widget.get(0);
+ };
+
+
+ /**
+ * Function: getWheelDataUrl
+ *
+ * Create color wheel image and return as base64 encoded data url.
+ */
+ WCP.ColorPicker.getWheelDataUrl = function( size ) {
+ var r = size / 2; // radius
+ var center = r;
+ var canvas = document.createElement('canvas');
+ canvas.width = size;
+ canvas.height = size;
+ var context = canvas.getContext('2d');
+
+ // Fill the wheel with colors
+ for(var y = 0; y < size; y++) {
+ for(var x = 0; x < size; x++) {
+ // Get the offset from central position
+ var offset = Math.sqrt(Math.pow(x - center, 2) + Math.pow(y - center, 2));
+
+ // Skip pixels outside picture area (plus 2 pixels)
+ if(offset > r + 2) {
+ continue;
+ }
+
+ // Get the position in degree (hue)
+ var deg = (
+ (x - center == 0
+ ? (y < center ? 90 : 270)
+ : (Math.atan((center - y) / (x - center)) / Math.PI * 180)
+ )
+ + (x < center ? 180 : 0)
+ + 360
+ ) % 360;
+
+ // Relative offset (sat)
+ var sat = offset / r;
+
+ // Value is always 1
+ var val = 1;
+
+ // Calculate color
+ var cr = (Math.abs(deg + 360) + 60) % 360 < 120 ? 1
+ : (deg > 240 ? (120 - Math.abs(deg - 360)) / 60
+ : (deg < 120 ? (120 - deg) / 60
+ : 0));
+ var cg = Math.abs(deg - 120) < 60 ? 1
+ : (Math.abs(deg - 120) < 120 ? (120 - Math.abs(deg - 120)) / 60
+ : 0);
+
+ var cb = Math.abs(deg - 240) < 60 ? 1
+ : (Math.abs(deg - 240) < 120 ? (120 - Math.abs(deg - 240)) / 60
+ : 0);
+ var pr = Math.round((cr + (1 - cr) * (1 - sat)) * 255);
+ var pg = Math.round((cg + (1 - cg) * (1 - sat)) * 255);
+ var pb = Math.round((cb + (1 - cb) * (1 - sat)) * 255);
+
+ context.fillStyle = 'rgb(' + pr + ',' + pg + ',' + pb + ')';
+ context.fillRect(x, y, 1, 1);
+ }
+ }
+
+ return canvas.toDataURL();
+ };
+
+
+ /////////////
+ // Members //
+ /////////////
+
+
+ /**
+ * Property: ColorPicker.options
+ *
+ * Plugin options for the color picker instance, extended from WCP.defaults.
+ */
+ WCP.ColorPicker.prototype.options = null;
+
+
+ /**
+ * Property: ColorPicker.input
+ *
+ * Reference to input DOM element
+ */
+ WCP.ColorPicker.prototype.input = null;
+
+
+ /**
+ * Property: ColorPicker.widget
+ *
+ * Reference to widget DOM element (global popup or private inline widget)
+ */
+ WCP.ColorPicker.prototype.widget = null;
+
+
+ /**
+ * Property: ColorPicker.color
+ *
+ * Selected color object.
+ */
+ WCP.ColorPicker.prototype.color = null;
+
+
+ /**
+ * Property: ColorPicker.lastValue
+ *
+ * Store last input value
+ */
+ WCP.ColorPicker.prototype.lastValue = null;
+
+
+ /**
+ * Function: ColorPicker.setOptions
+ *
+ * Since 3.0
+ *
+ * Set options to the color picker. If htmlOptions is set to true,
+ * options set via html attributes are also reloaded. If both html
+ * attribute and argument exists, option set via options argument
+ * gets priority.
+ */
+ WCP.ColorPicker.prototype.setOptions = function( options ) {
+
+ // options should be a separate object (passed by value)
+ // Make a copy of options
+ options = $.extend(true, {}, options);
+
+ // Load options from HTML attributes
+ if(this.options.htmlOptions) {
+ for(var key in WCP.defaults) {
+ // Only if option key is valid and not set via function argument
+ if(this.input.hasAttribute('data-wcp-'+key) && options[key] === undefined) {
+ options[key] = this.input.getAttribute('data-wcp-'+key);
+ // Change true/false string to boolean
+ if(options[key] == 'true') {
+ options[key] = true;
+ }
+ else if(options[key] == 'false') {
+ options[key] = false;
+ }
+ }
+ }
+ }
+
+ // Set options
+ for(var key in options) {
+ // Skip undefined option key
+ if(this.options[key] === undefined)
+ continue;
+
+ var keyUc = key.charAt(0).toUpperCase() + key.slice(1);
+
+ // If setter is available, try setting it via setter
+ if(typeof this['set'+keyUc] === "function") {
+ this['set'+keyUc](options[key]);
+ }
+ // Otherwise directly update options
+ else {
+ this.options[key] = options[key];
+ }
+ }
+
+ return this; // Allow chaining
+ };
+
+
+ /**
+ * Function: ColorPicker.init
+ *
+ * Initialize wheel color picker widget
+ */
+ WCP.ColorPicker.prototype.init = function() {
+ WCP.ColorPicker.init();
+
+ // Initialization must only occur once
+ if(this.hasInit == true)
+ return;
+ this.hasInit = true;
+
+ var instance = this;
+ var $input = $(this.input);
+ var $widget = null;
+
+ /// LAYOUT & BINDINGS ///
+ // Setup block mode layout
+ if( this.options.layout == 'block' ) {
+ // Create widget
+ this.widget = WCP.ColorPicker.createWidget();
+ $widget = $(this.widget);
+
+ // Store object instance reference
+ $widget.data('jQWCP.instance', this);
+
+ // Wrap widget around the input elm and put the input
+ // elm inside widget
+ $widget.insertAfter(this.input);
+ // Retain display CSS property
+ if($input.css('display') == "inline") {
+ $widget.css('display', "inline-block");
+ }
+ else {
+ $widget.css('display', $input.css('display'));
+ }
+ $widget.append(this.input);
+ $input.hide();
+
+ // Add tabindex attribute to make the widget focusable
+ if($input.attr('tabindex') != undefined) {
+ $widget.attr('tabindex', $input.attr('tabindex'));
+ }
+ else {
+ $widget.attr('tabindex', 0);
+ }
+
+ // Further widget adjustments based on options
+ this.refreshWidget();
+
+ // Draw shading
+ this.redrawSliders(true);
+ this.updateSliders();
+
+ // Bind widget element events
+ $widget.on('focus.wheelColorPicker', WCP.Handler.widget_focus_block);
+ $widget.on('blur.wheelColorPicker', WCP.Handler.widget_blur_block);
+ }
+
+ // Setup popup mode layout
+ else {
+ // Only need to create one widget, used globally
+ if(WCP.ColorPicker.widget == null) {
+ WCP.ColorPicker.widget = WCP.ColorPicker.createWidget();
+ $widget = $(WCP.ColorPicker.widget);
+
+ // Assign widget to global
+ $widget.hide();
+ $('body').append($widget);
+
+ // Bind popup events
+ $widget.on('mousedown.wheelColorPicker', WCP.Handler.widget_mousedown_popup);
+ //$widget.on('mouseup.wheelColorPicker', WCP.Handler.widget_mouseup_popup);
+
+ }
+ this.widget = WCP.ColorPicker.widget;
+
+ // Bind input element events
+ $input.on('focus.wheelColorPicker', WCP.Handler.input_focus_popup);
+ $input.on('blur.wheelColorPicker', WCP.Handler.input_blur_popup);
+ }
+
+ // Bind input events
+ $input.on('keyup.wheelColorPicker', WCP.Handler.input_keyup);
+ $input.on('change.wheelColorPicker', WCP.Handler.input_change);
+
+ // Set color value
+ // DEPRECATED by 3.0
+ if(typeof this.options.color == "object") {
+ this.setColor(this.options.color);
+ this.options.color = undefined;
+ }
+ else if(typeof this.options.color == "string") {
+ this.setValue(this.options.color);
+ this.options.color = undefined;
+ }
+
+ // Set readonly mode
+ /* DEPRECATED */
+ if(this.options.userinput) {
+ $input.removeAttr('readonly');
+ }
+ else {
+ $input.attr('readonly', true);
+ }
+ };
+
+
+ /**
+ * Function: destroy
+ *
+ * Destroy the color picker and return it to normal element.
+ */
+ WCP.ColorPicker.prototype.destroy = function() {
+ var $widget = $(this.widget);
+ var $input = $(this.input);
+
+ // Reset layout
+ // No need to delete global popup
+ if(this.options.layout == 'block') {
+ // Check if active control is the same widget as destroyed widget, remove the reference if it's true
+ var $control = $( $('body').data('jQWCP.activeControl') ); // Refers to slider wrapper or wheel
+ if ($control.length) {
+ var controlWidget = $control.closest('.jQWCP-wWidget');
+ if ($widget.is(controlWidget)) {
+ $('body').data('jQWCP.activeControl', null);
+ }
+ }
+
+ $widget.before(this.input);
+ $widget.remove();
+ $input.show();
+ }
+
+ // Unbind events
+ $input.off('focus.wheelColorPicker');
+ $input.off('blur.wheelColorPicker');
+ $input.off('keyup.wheelColorPicker');
+ $input.off('change.wheelColorPicker');
+
+ // Remove data
+ $input.data('jQWCP.instance', null);
+
+ // remove self
+ delete this;
+ };
+
+
+ /**
+ * Function: refreshWidget
+ *
+ * Since 3.0
+ * 2.5 was private.adjustWidget
+ *
+ * Update widget to match current option values.
+ */
+ WCP.ColorPicker.prototype.refreshWidget = function() {
+ var $widget = $(this.widget);
+ var options = this.options;
+ var mobileLayout = false;
+
+ // Set CSS classes
+ $widget.attr('class', 'jQWCP-wWidget');
+ if(options.layout == 'block') {
+ $widget.addClass('jQWCP-block');
+ }
+ $widget.addClass(options.cssClass);
+ //$widget.addClass(this.input.getAttribute('class'));
+
+ // Check whether to use mobile layout
+ if(window.innerWidth <= options.mobileWidth && options.layout != 'block' && options.mobile) {
+ mobileLayout = true;
+ $widget.addClass('jQWCP-mobile');
+ }
+
+ // Rearrange sliders
+ $widget.find('.jQWCP-wWheel, .jQWCP-slider-wrapper, .jQWCP-wPreview')
+ .hide()
+ .addClass('hidden');
+
+ for(var i in options.sliders) {
+ var $slider = null;
+ switch(this.options.sliders[i]) {
+ case 'w':
+ $slider = $widget.find('.jQWCP-wWheel'); break;
+ case 'h':
+ $slider = $widget.find('.jQWCP-wHue'); break;
+ case 's':
+ $slider = $widget.find('.jQWCP-wSat'); break;
+ case 'v':
+ $slider = $widget.find('.jQWCP-wVal'); break;
+ case 'r':
+ $slider = $widget.find('.jQWCP-wRed'); break;
+ case 'g':
+ $slider = $widget.find('.jQWCP-wGreen'); break;
+ case 'b':
+ $slider = $widget.find('.jQWCP-wBlue'); break;
+ case 'a':
+ $slider = $widget.find('.jQWCP-wAlpha'); break;
+ case 'p':
+ $slider = $widget.find('.jQWCP-wPreview'); break;
+ }
+
+ if($slider != null) {
+ $slider.appendTo(this.widget);
+ $slider.show().removeClass('hidden');
+ }
+ }
+
+ // If widget is hidden, show it first so we can calculate dimensions correctly
+ //var widgetIsHidden = false;
+ //if($widget.is(':hidden')) {
+ //widgetIsHidden = true;
+ //$widget.css({ opacity: '0' }).show();
+ //}
+
+ // Adjust sliders height based on quality
+ var sliderHeight = options.quality * 50;
+ $widget.find('.jQWCP-slider').attr('height', sliderHeight);
+
+ var $visElms = $widget.find('.jQWCP-wWheel, .jQWCP-slider-wrapper, .jQWCP-wPreview').not('.hidden');
+
+ // Adjust container and sliders width
+ // Only if not on mobile layout (force fixed on mobile)
+ if(options.autoResize && !mobileLayout) {
+ // Auto resize
+ var width = 0
+
+ // Set slider size first, then adjust container
+ $visElms.css({ width: '', height: '' });
+
+ $visElms.each(function(index, item) {
+ var $item = $(item);
+ width += parseFloat($item.css('margin-left').replace('px', '')) + parseFloat($item.css('margin-right').replace('px', '')) + $item.outerWidth();
+ });
+ $widget.css({ width: width + 'px' });
+ }
+ else {
+ // Fixed size
+
+ // Set container size first, then adjust sliders
+ $widget.css({ width: '' });
+
+ var $visWheel = $widget.find('.jQWCP-wWheel').not('.hidden');
+ var $visSliders = $widget.find('.jQWCP-slider-wrapper, .jQWCP-wPreview').not('.hidden');
+ $visWheel.css({ height: $widget.height() + 'px', width: $widget.height() });
+ if($visWheel.length > 0) {
+ var horzSpace = $widget.width() - $visWheel.outerWidth() - parseFloat($visWheel.css('margin-left').replace('px', '')) - parseFloat($visWheel.css('margin-right').replace('px', ''));
+ }
+ else {
+ var horzSpace = $widget.width();
+ }
+ if($visSliders.length > 0) {
+ var sliderMargins = parseFloat($visSliders.css('margin-left').replace('px', '')) + parseFloat($visSliders.css('margin-right').replace('px', ''));
+ $visSliders.css({ height: $widget.height() + 'px', width: (horzSpace - ($visSliders.length - 1) * sliderMargins) / $visSliders.length + 'px' });
+ }
+ }
+
+ // Reset visibility
+ //if(widgetIsHidden) {
+ //$widget.css({ opacity: '' }).hide();
+ //}
+
+ return this; // Allows method chaining
+ };
+
+
+ /**
+ * Function: redrawSliders
+ *
+ * Introduced in 2.0
+ *
+ * Redraw slider gradients. Hidden sliders are not redrawn as to
+ * improve performance. If options.live is FALSE, sliders are not redrawn.
+ *
+ * Parameter:
+ * force - Boolean force redraw all sliders.
+ */
+ WCP.ColorPicker.prototype.redrawSliders = function( force ) {
+
+ // Skip if widget not yet initialized
+ if(this.widget == null)
+ return this;
+
+ var $widget = $(this.widget);
+
+ // DEPRECATED 3.0
+ // In 2.0, parameters are ( sliders, force )
+ if(typeof arguments[0] === "string") {
+ force = arguments[1];
+ }
+
+ // No need to redraw sliders on global popup widget if not
+ // attached to the input elm in current iteration
+ if(this != $widget.data('jQWCP.instance'))
+ return this;
+
+ var options = this.options;
+ var color = this.color;
+
+ var w = 1;
+ var h = options.quality * 50;
+
+ var A = 1;
+ var R = 0;
+ var G = 0;
+ var B = 0;
+ var H = 0;
+ var S = 0;
+ var V = 1;
+
+ // Dynamic colors
+ if(options.live) {
+ A = color.a;
+ R = Math.round(color.r * 255);
+ G = Math.round(color.g * 255);
+ B = Math.round(color.b * 255);
+ H = color.h;
+ S = color.s;
+ V = color.v;
+ }
+
+ /// PREVIEW ///
+ // Preview box must always be redrawn, if not hidden
+ var $previewBox = $widget.find('.jQWCP-wPreviewBox');
+ if(!$previewBox.hasClass('hidden')) {
+ var previewBoxCtx = $previewBox.get(0).getContext('2d');
+ previewBoxCtx.fillStyle = "rgba(" + R + "," + G + "," + B + "," + A + ")";
+ previewBoxCtx.clearRect(0, 0, 1, 1);
+ previewBoxCtx.fillRect(0, 0, 1, 1);
+ }
+
+ /// SLIDERS ///
+ if(!this.options.live && !force)
+ return this;
+
+ /// ALPHA ///
+ // The top color is (R, G, B, 1)
+ // The bottom color is (R, G, B, 0)
+ var $alphaSlider = $widget.find('.jQWCP-wAlphaSlider');
+ if(!$alphaSlider.hasClass('hidden') || force) {
+ var alphaSliderCtx = $alphaSlider.get(0).getContext('2d');
+ var alphaGradient = alphaSliderCtx.createLinearGradient(0, 0, 0, h);
+ alphaGradient.addColorStop(0, "rgba("+R+","+G+","+B+",1)");
+ alphaGradient.addColorStop(1, "rgba("+R+","+G+","+B+",0)");
+ alphaSliderCtx.fillStyle = alphaGradient;
+ alphaSliderCtx.clearRect(0, 0, w, h);
+ alphaSliderCtx.fillRect(0, 0, w, h);
+ }
+
+ /// RED ///
+ // The top color is (255, G, B)
+ // The bottom color is (0, G, B)
+ var $redSlider = $widget.find('.jQWCP-wRedSlider');
+ if(!$redSlider.hasClass('hidden') || force) {
+ var redSliderCtx = $redSlider.get(0).getContext('2d');
+ var redGradient = redSliderCtx.createLinearGradient(0, 0, 0, h);
+ redGradient.addColorStop(0, "rgb(255,"+G+","+B+")");
+ redGradient.addColorStop(1, "rgb(0,"+G+","+B+")");
+ redSliderCtx.fillStyle = redGradient;
+ redSliderCtx.fillRect(0, 0, w, h);
+ }
+
+ /// GREEN ///
+ // The top color is (R, 255, B)
+ // The bottom color is (R, 0, B)
+ var $greenSlider = $widget.find('.jQWCP-wGreenSlider');
+ if(!$greenSlider.hasClass('hidden') || force) {
+ var greenSliderCtx = $greenSlider.get(0).getContext('2d');
+ var greenGradient = greenSliderCtx.createLinearGradient(0, 0, 0, h);
+ greenGradient.addColorStop(0, "rgb("+R+",255,"+B+")");
+ greenGradient.addColorStop(1, "rgb("+R+",0,"+B+")");
+ greenSliderCtx.fillStyle = greenGradient;
+ greenSliderCtx.fillRect(0, 0, w, h);
+ }
+
+ /// BLUE ///
+ // The top color is (R, G, 255)
+ // The bottom color is (R, G, 0)
+ var $blueSlider = $widget.find('.jQWCP-wBlueSlider');
+ if(!$blueSlider.hasClass('hidden') || force) {
+ var blueSliderCtx = $blueSlider.get(0).getContext('2d');
+ var blueGradient = blueSliderCtx.createLinearGradient(0, 0, 0, h);
+ blueGradient.addColorStop(0, "rgb("+R+","+G+",255)");
+ blueGradient.addColorStop(1, "rgb("+R+","+G+",0)");
+ blueSliderCtx.fillStyle = blueGradient;
+ blueSliderCtx.fillRect(0, 0, w, h);
+ }
+
+ /// HUE ///
+ // The hue slider is static.
+ var $hueSlider = $widget.find('.jQWCP-wHueSlider');
+ if(!$hueSlider.hasClass('hidden') || force) {
+ var hueSliderCtx = $hueSlider.get(0).getContext('2d');
+ var hueGradient = hueSliderCtx.createLinearGradient(0, 0, 0, h);
+ hueGradient.addColorStop(0, "#f00");
+ hueGradient.addColorStop(0.166666667, "#ff0");
+ hueGradient.addColorStop(0.333333333, "#0f0");
+ hueGradient.addColorStop(0.5, "#0ff");
+ hueGradient.addColorStop(0.666666667, "#00f");
+ hueGradient.addColorStop(0.833333333, "#f0f");
+ hueGradient.addColorStop(1, "#f00");
+ hueSliderCtx.fillStyle = hueGradient;
+ hueSliderCtx.fillRect(0, 0, w, h);
+ }
+
+ /// SAT ///
+ // The top color is hsv(h, 1, v)
+ // The bottom color is hsv(0, 0, v)
+ var $satSlider = $widget.find('.jQWCP-wSatSlider');
+ if(!$satSlider.hasClass('hidden') || force) {
+ var satTopRgb = $.fn.wheelColorPicker.hsvToRgb(H, 1, V);
+ satTopRgb.r = Math.round(satTopRgb.r * 255);
+ satTopRgb.g = Math.round(satTopRgb.g * 255);
+ satTopRgb.b = Math.round(satTopRgb.b * 255);
+ var satSliderCtx = $satSlider.get(0).getContext('2d');
+ var satGradient = satSliderCtx.createLinearGradient(0, 0, 0, h);
+ satGradient.addColorStop(0, "rgb("+satTopRgb.r+","+satTopRgb.g+","+satTopRgb.b+")");
+ satGradient.addColorStop(1, "rgb("+Math.round(V*255)+","+Math.round(V*255)+","+Math.round(V*255)+")");
+ satSliderCtx.fillStyle = satGradient;
+ satSliderCtx.fillRect(0, 0, w, h);
+ }
+
+ /// VAL ///
+ // The top color is hsv(h, s, 1)
+ // The bottom color is always black.
+ var $valSlider = $widget.find('.jQWCP-wValSlider');
+ if(!$valSlider.hasClass('hidden') || force) {
+ var valTopRgb = $.fn.wheelColorPicker.hsvToRgb(H, S, 1);
+ valTopRgb.r = Math.round(valTopRgb.r * 255);
+ valTopRgb.g = Math.round(valTopRgb.g * 255);
+ valTopRgb.b = Math.round(valTopRgb.b * 255);
+ var valSliderCtx = $valSlider.get(0).getContext('2d');
+ var valGradient = valSliderCtx.createLinearGradient(0, 0, 0, h);
+ valGradient.addColorStop(0, "rgb("+valTopRgb.r+","+valTopRgb.g+","+valTopRgb.b+")");
+ valGradient.addColorStop(1, "#000");
+ valSliderCtx.fillStyle = valGradient;
+ valSliderCtx.fillRect(0, 0, w, h);
+ }
+
+ return this; // Allows method chaining
+ };
+
+
+ /**
+ * Function: updateSliders
+ *
+ * Introduced in 2.0
+ *
+ * Update slider cursor positions based on this.color value.
+ * Only displayed sliders are updated.
+ */
+ WCP.ColorPicker.prototype.updateSliders = function() {
+
+ // Skip if not yet initialized
+ if(this.widget == null)
+ return this;
+
+ var $widget = $(this.widget);
+ var color = this.color;
+
+ // No need to redraw sliders on global popup widget if not
+ // attached to the input elm in current iteration
+ if(this != $widget.data('jQWCP.instance'))
+ return this;
+
+ // Wheel
+ var $wheel = $widget.find('.jQWCP-wWheel');
+ if(!$wheel.hasClass('hidden')) {
+ var $wheelCursor = $widget.find('.jQWCP-wWheelCursor');
+ var $wheelOverlay = $widget.find('.jQWCP-wWheelOverlay');
+ var wheelX = Math.cos(2 * Math.PI * color.h) * color.s;
+ var wheelY = Math.sin(2 * Math.PI * color.h) * color.s;
+ var wheelOffsetX = $wheel.width() / 2;
+ var wheelOffsetY = $wheel.height() / 2;
+ $wheelCursor.css('left', (wheelOffsetX + (wheelX * $wheel.width() / 2)) + 'px');
+ $wheelCursor.css('top', (wheelOffsetY - (wheelY * $wheel.height() / 2)) + 'px');
+ // Keep shading to 1 if preserveWheel is true (DEPRECATED) or live is true
+ if(this.options.preserveWheel == true || (this.options.preserveWheel == null && this.options.live == false)) {
+ $wheelOverlay.css('opacity', 0);
+ }
+ else {
+ $wheelOverlay.css('opacity', 1 - (color.v < 0.2 ? 0.2 : color.v));
+ }
+ }
+
+ // Hue
+ var $hueSlider = $widget.find('.jQWCP-wHueSlider');
+ if(!$hueSlider.hasClass('hidden')) {
+ var $hueCursor = $widget.find('.jQWCP-wHueCursor');
+ $hueCursor.css('top', (color.h * $hueSlider.height()) + 'px');
+ }
+
+ // Saturation
+ var $satSlider = $widget.find('.jQWCP-wSatSlider');
+ if(!$satSlider.hasClass('hidden')) {
+ var $satCursor = $widget.find('.jQWCP-wSatCursor');
+ $satCursor.css('top', ((1 - color.s) * $satSlider.height()) + 'px');
+ }
+
+ // Value
+ var $valSlider = $widget.find('.jQWCP-wValSlider');
+ if(!$valSlider.hasClass('hidden')) {
+ var $valCursor = $widget.find('.jQWCP-wValCursor');
+ $valCursor.css('top', ((1 - color.v) * $valSlider.height()) + 'px');
+ }
+
+ // Red
+ var $redSlider = $widget.find('.jQWCP-wRedSlider');
+ if(!$redSlider.hasClass('hidden')) {
+ var $redCursor = $widget.find('.jQWCP-wRedCursor');
+ $redCursor.css('top', ((1 - color.r) * $redSlider.height()) + 'px');
+ }
+
+ // Green
+ var $greenSlider = $widget.find('.jQWCP-wGreenSlider');
+ if(!$greenSlider.hasClass('hidden')) {
+ var $greenCursor = $widget.find('.jQWCP-wGreenCursor');
+ $greenCursor.css('top', ((1 - color.g) * $greenSlider.height()) + 'px');
+ }
+
+ // Blue
+ var $blueSlider = $widget.find('.jQWCP-wBlueSlider');
+ if(!$blueSlider.hasClass('hidden')) {
+ var $blueCursor = $widget.find('.jQWCP-wBlueCursor');
+ $blueCursor.css('top', ((1 - color.b) * $blueSlider.height()) + 'px');
+ }
+
+ // Alpha
+ var $alphaSlider = $widget.find('.jQWCP-wAlphaSlider');
+ if(!$alphaSlider.hasClass('hidden')) {
+ var $alphaCursor = $widget.find('.jQWCP-wAlphaCursor');
+ $alphaCursor.css('top', ((1 - color.a) * $alphaSlider.height()) + 'px');
+ }
+
+ return this; // Allows method chaining
+ };
+
+
+ /**
+ * Function: updateSelection
+ *
+ * DEPRECATED by 2.0
+ *
+ * Update color dialog selection to match current selectedColor value.
+ */
+ WCP.ColorPicker.prototype.updateSelection = function() {
+ this.redrawSliders();
+ this.updateSliders();
+ return this;
+ };
+
+
+ /**
+ * Function: updateInput
+ *
+ * Since 3.0
+ *
+ * Update input value and background color (if preview is on)
+ */
+ WCP.ColorPicker.prototype.updateInput = function() {
+ // Skip if not yet initialized
+ if(this.widget == null)
+ return this;
+
+ var $input = $(this.input);
+
+ // #13 only update if value is different to avoid cursor repositioned to the end of text on some browsers
+ if(this.input.value != this.getValue()) {
+ this.input.value = this.getValue();
+ }
+
+ if( this.options.preview ) {
+ $input.css('background', WCP.colorToStr( this.color, 'rgba' ));
+ if( this.color.v > .5 ) {
+ $input.css('color', 'black');
+ }
+ else {
+ $input.css('color', 'white');
+ }
+ }
+ };
+
+
+ /**
+ * Function: updateActiveControl
+ *
+ * Move the active control.
+ */
+ WCP.ColorPicker.prototype.updateActiveControl = function( e ) {
+ var $control = $( $('body').data('jQWCP.activeControl') ); // Refers to slider wrapper
+
+ if($control.length == 0)
+ return;
+
+ var $input = $(this.input);
+ var options = this.options;
+ var color = this.color;
+
+ // pageX and pageY wrapper for touches
+ if(e.pageX == undefined && e.originalEvent.touches.length > 0) {
+ e.pageX = e.originalEvent.touches[0].pageX;
+ e.pageY = e.originalEvent.touches[0].pageY;
+ }
+ //$('#log').html(e.pageX + '/' + e.pageY);
+
+ /// WHEEL CONTROL ///
+ if($control.hasClass('jQWCP-wWheel')) {
+ var $cursor = $control.find('.jQWCP-wWheelCursor');
+ var $overlay = $control.find('.jQWCP-wWheelOverlay');
+
+ var relX = (e.pageX - $control.offset().left - ($control.width() / 2)) / ($control.width() / 2);
+ var relY = - (e.pageY - $control.offset().top - ($control.height() / 2)) / ($control.height() / 2);
+
+ // BUG_RELATIVE_PAGE_ORIGIN workaround
+ if(WCP.BUG_RELATIVE_PAGE_ORIGIN) {
+ var relX = (e.pageX - ($control.get(0).getBoundingClientRect().left - WCP.ORIGIN.left) - ($control.width() / 2)) / ($control.width() / 2);
+ var relY = - (e.pageY - ($control.get(0).getBoundingClientRect().top - WCP.ORIGIN.top) - ($control.height() / 2)) / ($control.height() / 2);
+ }
+
+ //console.log(relX + ' ' + relY);
+
+ // Sat value is calculated from the distance of the cursor from the central point
+ var sat = Math.sqrt(Math.pow(relX, 2) + Math.pow(relY, 2));
+ // If distance is out of bound, reset to the upper bound
+ if(sat > 1) {
+ sat = 1;
+ }
+
+ // Snap to 0,0
+ if(options.snap && sat < options.snapTolerance) {
+ sat = 0;
+ }
+
+ // Hue is calculated from the angle of the cursor. 0deg is set to the right, and increase counter-clockwise.
+ var hue = (relX == 0 && relY == 0) ? 0 : Math.atan( relY / relX ) / ( 2 * Math.PI );
+ // If hue is negative, then fix the angle value (meaning angle is in either Q2 or Q4)
+ if( hue < 0 ) {
+ hue += 0.5;
+ }
+ // If y is negative, then fix the angle value (meaning angle is in either Q3 or Q4)
+ if( relY < 0 ) {
+ hue += 0.5;
+ }
+
+ this.setHsv(hue, sat, color.v);
+ }
+
+ /// SLIDER CONTROL ///
+ else if($control.hasClass('jQWCP-slider-wrapper')) {
+ var $cursor = $control.find('.jQWCP-scursor');
+
+ var relY = (e.pageY - $control.offset().top) / $control.height();
+
+ // BUG_RELATIVE_PAGE_ORIGIN workaround
+ if(WCP.BUG_RELATIVE_PAGE_ORIGIN) {
+ var relY = (e.pageY - ($control.get(0).getBoundingClientRect().top - WCP.ORIGIN.top)) / $control.height();
+ }
+
+ var value = relY < 0 ? 0 : relY > 1 ? 1 : relY;
+
+ // Snap to 0.0, 0.5, and 1.0
+ //console.log(value);
+ if(options.snap && value < options.snapTolerance) {
+ value = 0;
+ }
+ else if(options.snap && value > 1-options.snapTolerance) {
+ value = 1;
+ }
+ if(options.snap && value > 0.5-options.snapTolerance && value < 0.5+options.snapTolerance) {
+ value = 0.5;
+ }
+
+ $cursor.css('top', (value * $control.height()) + 'px');
+
+ /// Update color value ///
+ // Red
+ if($control.hasClass('jQWCP-wRed')) {
+ this.setRgb(1-value, color.g, color.b);
+ }
+ // Green
+ if($control.hasClass('jQWCP-wGreen')) {
+ this.setRgb(color.r, 1-value, color.b);
+ }
+ // Blue
+ if($control.hasClass('jQWCP-wBlue')) {
+ this.setRgb(color.r, color.g, 1-value);
+ }
+ // Hue
+ if($control.hasClass('jQWCP-wHue')) {
+ this.setHsv(value, color.s, color.v);
+ }
+ // Saturation
+ if($control.hasClass('jQWCP-wSat')) {
+ this.setHsv(color.h, 1-value, color.v);
+ }
+ // Value
+ if($control.hasClass('jQWCP-wVal')) {
+ this.setHsv(color.h, color.s, 1-value);
+ }
+ // Alpha
+ if($control.hasClass('jQWCP-wAlpha')) {
+ this.setAlpha(1-value);
+ }
+ }
+ };
+
+
+ /**
+ * Function: getColor
+ *
+ * Since 2.0
+ *
+ * Return color components as an object. The object consists of:
+ * {
+ * r: red
+ * g: green
+ * b: blue
+ * h: hue
+ * s: saturation
+ * v: value
+ * a: alpha
+ * }
+ */
+ WCP.ColorPicker.prototype.getColor = function() {
+ return this.color;
+ };
+
+
+ /**
+ * Function: getValue
+ *
+ * Get the color value as string.
+ */
+ WCP.ColorPicker.prototype.getValue = function( format ) {
+ var options = this.options;
+
+ if( format == null ) {
+ format = options.format;
+ }
+
+ // If settings.rounding is TRUE, round alpha value to N decimal digits
+ if(options.rounding >= 0) {
+ this.color.a = Math.round(this.color.a * Math.pow(10, options.rounding)) / Math.pow(10, options.rounding);
+ }
+ return WCP.colorToStr( this.color, format );
+ };
+
+
+ /**
+ * Function: setValue
+ *
+ * Set the color value as string.
+ *
+ * Parameters:
+ * value - <string> String representation of color.
+ * updateInput - <boolean> Whether to update input text. Default is true.
+ */
+ WCP.ColorPicker.prototype.setValue = function( value, updateInput ) {
+ var color = WCP.strToColor(value);
+ if(!color)
+ return this;
+
+ return this.setColor(color, updateInput);
+ }
+
+
+ /**
+ * Function: setColor
+ *
+ * Introduced in 2.0
+ *
+ * Set color by passing an object consisting of:
+ * { r, g, b, a } or
+ * { h, s, v, a }
+ *
+ * For consistency with options.color value, this function also
+ * accepts string value.
+ *
+ * Parameters:
+ * color - <object> Color object or string representation of color.
+ * updateInput - <boolean> Whether to update input text. Default is true.
+ */
+ WCP.ColorPicker.prototype.setColor = function( color, updateInput ) {
+ if(typeof color === "string") {
+ return this.setValue(color, updateInput);
+ }
+ else if(color.r != null) {
+ return this.setRgba(color.r, color.g, color.b, color.a, updateInput);
+ }
+ else if(color.h != null) {
+ return this.setHsva(color.h, color.s, color.v, color.a, updateInput);
+ }
+ else if(color.a != null) {
+ return this.setAlpha(color.a, updateInput);
+ }
+ return this;
+ };
+
+
+ /**
+ * Function: setRgba
+ *
+ * Introduced in 2.0
+ *
+ * Set color using RGBA combination.
+ *
+ * Parameters:
+ * r - <number> Red component [0..1]
+ * g - <number> Green component [0..1]
+ * b - <number> Blue component [0..1]
+ * a - <number> Alpha value [0..1]
+ * updateInput - <boolean> Whether to update input text. Default is true.
+ */
+ WCP.ColorPicker.prototype.setRgba = function( r, g, b, a, updateInput ) {
+ // Default value
+ if(updateInput === undefined) updateInput = true;
+
+ var color = this.color;
+ color.r = r;
+ color.g = g;
+ color.b = b;
+
+ if(a != null) {
+ color.a = a;
+ }
+
+ var hsv = WCP.rgbToHsv(r, g, b);
+ color.h = hsv.h;
+ color.s = hsv.s;
+ color.v = hsv.v;
+
+ this.updateSliders();
+ this.redrawSliders();
+ if(updateInput) {
+ this.updateInput();
+ }
+ return this;
+ };
+
+
+ /**
+ * Function: setRgb
+ *
+ * Introduced in 2.0
+ *
+ * Set color using RGB combination.
+ *
+ * Parameters:
+ * r - <number> Red component [0..1]
+ * g - <number> Green component [0..1]
+ * b - <number> Blue component [0..1]
+ * updateInput - <boolean> Whether to update input text.
+ */
+ WCP.ColorPicker.prototype.setRgb = function( r, g, b, updateInput ) {
+ return this.setRgba(r, g, b, null, updateInput);
+ };
+
+
+ /**
+ * Function: setHsva
+ *
+ * Introduced in 2.0
+ *
+ * Set color using HSVA combination.
+ *
+ * Parameters:
+ * h - <number> Hue component [0..1]
+ * s - <number> Saturation component [0..1]
+ * v - <number> Value component [0..1]
+ * a - <number> Alpha value [0..1]
+ * updateInput - <boolean> Whether to update input text. Default is true.
+ */
+ WCP.ColorPicker.prototype.setHsva = function( h, s, v, a, updateInput ) {
+ // Default value
+ if(updateInput === undefined) updateInput = true;
+
+ var color = this.color;
+ color.h = h;
+ color.s = s;
+ color.v = v;
+
+ if(a != null) {
+ color.a = a;
+ }
+
+ var rgb = WCP.hsvToRgb(h, s, v);
+ color.r = rgb.r;
+ color.g = rgb.g;
+ color.b = rgb.b;
+
+ this.updateSliders();
+ this.redrawSliders();
+ if(updateInput) {
+ this.updateInput();
+ }
+ return this;
+ };
+
+
+ /**
+ * Function: setHsv
+ *
+ * Introduced in 2.0
+ *
+ * Set color using HSV combination.
+ *
+ * Parameters:
+ * h - <number> Hue component [0..1]
+ * s - <number> Saturation component [0..1]
+ * v - <number> Value component [0..1]
+ * updateInput - <boolean> Whether to update input text.
+ */
+ WCP.ColorPicker.prototype.setHsv = function( h, s, v, updateInput ) {
+ return this.setHsva(h, s, v, null, updateInput);
+ };
+
+
+ /**
+ * Function: setAlpha
+ *
+ * Introduced in 2.0
+ *
+ * Set alpha value.
+ *
+ * Parameters:
+ * value - <number> Alpha value [0..1]
+ * updateInput - <boolean> Whether to update input text. Default is true.
+ */
+ WCP.ColorPicker.prototype.setAlpha = function( value, updateInput ) {
+ // Default value
+ if(updateInput === undefined) updateInput = true;
+
+ this.color.a = value;
+
+ this.updateSliders();
+ this.redrawSliders();
+ if(updateInput) {
+ this.updateInput();
+ }
+ return this;
+ };
+
+
+ /**
+ * Function: show
+ *
+ * Show the color picker dialog. This function is only applicable to
+ * popup mode color picker layout.
+ */
+ WCP.ColorPicker.prototype.show = function() {
+ var input = this.input;
+ var $input = $(input); // Refers to input elm
+ var $widget = $(this.widget);
+ var options = this.options;
+
+ // Don't do anything if not using popup layout
+ if( options.layout != "popup" )
+ return;
+
+ // Don't do anything if the popup is already shown and attached
+ // to the correct input elm
+ //if( this == $widget.data('jQWCP.instance') )
+ //return;
+
+ // Attach instance to widget (because popup widget is global)
+ $widget.data('jQWCP.instance', this);
+
+ // Terminate ongoing transitions
+ $widget.stop( true, true );
+
+ // Reposition the popup window
+ $widget.css({
+ top: (input.getBoundingClientRect().top - WCP.ORIGIN.top + $input.outerHeight()) + 'px',
+ left: (input.getBoundingClientRect().left - WCP.ORIGIN.left) + 'px'
+ });
+
+ // Refresh widget with this instance's options
+ this.refreshWidget();
+
+ // Redraw sliders
+ this.redrawSliders();
+ this.updateSliders();
+
+ // Store last textfield value (to determine whether to trigger onchange event later)
+ this.lastValue = input.value;
+
+ $widget.fadeIn( options.animDuration );
+
+ // If hideKeyboard is true, force to hide soft keyboard
+ if(options.hideKeyboard) {
+ $input.blur();
+ $(WCP.ColorPicker.overlay).show();
+ }
+
+ // On mobile layout, autoscroll page to keep input visible
+ if($widget.hasClass('jQWCP-mobile')) {
+ var scrollTop = $('html').scrollTop();
+ var inputTop = input.getBoundingClientRect().top - WCP.ORIGIN.top;
+
+ // If input is way too top
+ if(inputTop < scrollTop) {
+ $('html').animate({ scrollTop: inputTop});
+ }
+
+ // If input is way too bottom
+ else if(inputTop + $input.outerHeight() > scrollTop + window.innerHeight - $widget.outerHeight()) {
+ $('html').animate({ scrollTop: inputTop + $input.outerHeight() - window.innerHeight + $widget.outerHeight()});
+ }
+ }
+ };
+
+
+
+ /**
+ * Function: hide
+ *
+ * Hide the color picker dialog. This function is only applicable to
+ * popup mode color picker layout.
+ */
+ WCP.ColorPicker.prototype.hide = function() {
+ var $widget = $(this.widget);
+
+ // Only hide if popup belongs to this instance
+ if(this != $widget.data('jQWCP.instance'))
+ return;
+
+ $widget.fadeOut( this.options.animDuration );
+ $(WCP.ColorPicker.overlay).hide();
+ };
+
+
+
+ ////////////////////
+ // Event Handlers //
+ ////////////////////
+
+ WCP.Handler = {};
+
+ /**
+ * input.onFocus.popup
+ */
+ WCP.Handler.input_focus_popup = function( e ) {
+ var instance = $(this).data('jQWCP.instance');
+ instance.show();
+
+ // Workaround to prevent on screen keyboard from appearing
+ if($(this).attr('readonly') == null) {
+ $(this).attr('readonly', true);
+ setTimeout(function() {
+ $(instance.input).removeAttr('readonly');
+ });
+
+ // Firefox on Android
+ if(navigator.userAgent.match(/Android .* Firefox/) != null) {
+ setTimeout(function() {
+ $(instance.input).attr('readonly', true);
+ $(instance.input).one('blur', function() {
+ $(instance.input).removeAttr('readonly');
+ });
+ });
+ }
+ }
+ };
+
+
+ /**
+ * input.onBlur.popup
+ *
+ * onBlur event handler for popup layout.
+ */
+ WCP.Handler.input_blur_popup = function( e ) {
+ var instance = $(this).data('jQWCP.instance');
+
+ // If keyboard is hidden, input is always blurred so
+ // no point in hiding
+ if(instance.options.hideKeyboard)
+ return;
+
+ instance.hide();
+
+ // Trigger 'change' event only when it was modified by widget
+ // because user typing on the textfield will automatically
+ // trigger 'change' event on blur.
+ if(instance.lastValue != this.value) {
+ $(this).trigger('change');
+ }
+ };
+
+
+ /**
+ * input.onKeyUp
+ *
+ * Update the color picker while user type in color value.
+ */
+ WCP.Handler.input_keyup = function( e ) {
+ var instance = $(this).data('jQWCP.instance');
+ var color = WCP.strToColor(this.value);
+ if(color) {
+ instance.setColor(color, false);
+ }
+ };
+
+
+ /**
+ * input.onChange
+ *
+ * Reformat the input value based on selected color and configurations.
+ */
+ WCP.Handler.input_change = function( e ) {
+ var instance = $(this).data('jQWCP.instance');
+ var color = WCP.strToColor(this.value);
+
+ // If autoFormat option is enabled, try to reformat the value if it is a valid color
+ if(instance.options.autoFormat && color) {
+ instance.setColor(color, true);
+ }
+
+ // If validate option is enabled, revert the value if it is not a valid color
+ else if(instance.options.validate && !color && this.value != '') {
+ this.value = instance.getValue();
+ }
+ };
+
+
+ /**
+ * widget.onFocus.block
+ *
+ * Prepare runtime widget data
+ */
+ WCP.Handler.widget_focus_block = function( e ) {
+ var instance = $(this).data('jQWCP.instance');
+ var $input = $(instance.input);
+
+ // Store last textfield value
+ instance.lastValue = instance.input.value;
+
+ // Trigger focus event
+ $input.triggerHandler('focus');
+ };
+
+
+ /**
+ * widget.onMouseDown.popup
+ *
+ * Prevent loss focus of the input causing the dialog to be hidden
+ * because of input blur event.
+ */
+ WCP.Handler.widget_mousedown_popup = function( e ) {
+ var instance = $(this).data('jQWCP.instance');
+ var $input = $(instance.input);
+
+ // Temporarily unbind blur and focus event until mouse is released
+ $input.off('focus.wheelColorPicker');
+ $input.off('blur.wheelColorPicker');
+
+ // Temporarily unbind all blur events until mouse is released
+ // data('events') is deprecated since jquery 1.8
+ if($input.data('events') != undefined) {
+ var blurEvents = $input.data('events').blur;
+ }
+ else {
+ var blurEvents = undefined;
+ }
+ var suspendedEvents = { blur: [] };
+ //suspendedEvents.blur = blurEvents;
+ //$input.off('blur');
+ if(blurEvents != undefined) {
+ for(var i = 0; i < blurEvents.length; i++) {
+ suspendedEvents.blur.push(blurEvents[i]);
+ //suspendedEvents.blur['blur' + (blurEvents[i].namespace != '' ? blurEvents[i].namespace : '')] = blurEvents[i].handler;
+ }
+ }
+ $input.data('jQWCP.suspendedEvents', suspendedEvents);
+ //console.log(blurEvents);
+ //console.log($input.data('jQWCP.suspendedEvents'));
+ };
+
+ /**
+ * widget.onMouseUp
+ *
+ * Re-bind events that was unbound by widget_mousedown_popup.
+ */
+ /*WCP.Handler.widget_mouseup_popup = function( e ) {
+ var instance = $(this).data('jQWCP.instance');
+ var $input = $(instance.input);
+
+ //Input elm must always be focused, unless hideKeyboard is set to true
+ if(!instance.options.hideKeyboard) {
+ $input.trigger('focus.jQWCP_DONT_TRIGGER_EVENTS'); // This allow input to be focused without triggering events
+ }
+
+ //Rebind blur & focusevent
+ $input.on('focus.wheelColorPicker', WCP.Handler.input_focus_popup);
+ $input.on('blur.wheelColorPicker', WCP.Handler.input_blur_popup);
+
+ };*/
+
+
+
+ /**
+ * widget.onBlur
+ *
+ * Try to trigger onChange event if value has been changed.
+ */
+ WCP.Handler.widget_blur_block = function( e ) {
+ var instance = $(this).data('jQWCP.instance');
+ var $input = $(instance.input);
+
+ // Trigger 'change' event only when it was modified by widget
+ // because user typing on the textfield will automatically
+ // trigger 'change' event on blur.
+ if(instance.lastValue != instance.input.value) {
+ $input.trigger('change');
+ }
+
+ // Trigger blur event
+ $input.triggerHandler('blur');
+ };
+
+
+ /**
+ * wheelCursor.onMouseDown
+ *
+ * Begin clicking the wheel down. This will allow user to move
+ * the crosshair although the mouse is outside the wheel.
+ */
+ WCP.Handler.wheelCursor_mousedown = function( e ) {
+ var $this = $(this); // Refers to cursor
+ var $widget = $this.closest('.jQWCP-wWidget');
+ var instance = $widget.data('jQWCP.instance');
+ var $input = $(instance.input);
+
+ $('body').data('jQWCP.activeControl', $this.parent().get(0));
+
+ // Trigger sliderdown event
+ $input.trigger('sliderdown');
+ };
+
+
+ /**
+ * wheel.onMouseDown
+ *
+ * Begin clicking the wheel down. This will allow user to move
+ * the crosshair although the mouse is outside the wheel.
+ *
+ * Basically this is the same as wheelCursor_mousedown handler
+ */
+ WCP.Handler.wheel_mousedown = function( e ) {
+ var $this = $(this); // Refers to wheel
+ var $widget = $this.closest('.jQWCP-wWidget');
+ var instance = $widget.data('jQWCP.instance');
+ var $input = $(instance.input);
+
+ $('body').data('jQWCP.activeControl', $this.get(0));
+
+ // Trigger sliderdown event
+ $input.trigger('sliderdown');
+ };
+
+
+ /**
+ * slider.onMouseDown
+ *
+ * Begin clicking the slider down. This will allow user to move
+ * the slider although the mouse is outside the slider.
+ */
+ WCP.Handler.slider_mousedown = function( e ) {
+ var $this = $(this); // Refers to slider
+ var $widget = $this.closest('.jQWCP-wWidget');
+ var instance = $widget.data('jQWCP.instance');
+ var $input = $(instance.input);
+
+ $('body').data('jQWCP.activeControl', $this.parent().get(0));
+
+ // Trigger sliderdown event
+ $input.trigger('sliderdown');
+ };
+
+ /**
+ * sliderCursor.onMouseDown
+ *
+ * Begin clicking the slider down. This will allow user to move
+ * the slider although the mouse is outside the slider.
+ */
+ WCP.Handler.sliderCursor_mousedown = function( e ) {
+ var $this = $(this); // Refers to slider cursor
+ var $widget = $this.closest('.jQWCP-wWidget');
+ var instance = $widget.data('jQWCP.instance');
+ var $input = $(instance.input);
+
+ $('body').data('jQWCP.activeControl', $this.parent().get(0));
+
+ // Trigger sliderdown event
+ $input.trigger('sliderdown');
+ };
+
+
+
+ /**
+ * html.onMouseUp
+ *
+ * Clear active control reference.
+ * Also do cleanups after widget.onMouseDown.popup
+ *
+ * Note: This event handler is also applied to touchend
+ */
+ WCP.Handler.html_mouseup = function( e ) {
+ var $control = $( $('body').data('jQWCP.activeControl') ); // Refers to slider wrapper or wheel
+
+ // Do stuffs when there's active control
+ if($control.length == 0)
+ return;
+
+ var $widget = $control.closest('.jQWCP-wWidget');
+ var instance = $widget.data('jQWCP.instance');
+ var $input = $(instance.input);
+
+
+ // Rebind blur and focus event to input elm which was
+ // temporarily released when popup dialog is shown
+ if(instance.options.layout == 'popup') {
+ // Focus first before binding event so it wont get fired
+ // Input elm must always be focused, unless hideKeyboard is set to true
+ if(!instance.options.hideKeyboard) {
+ $input.trigger('focus.jQWCP_DONT_TRIGGER_EVENTS'); // This allow input to be focused without triggering events
+ }
+
+ // Rebind blur & focusevent
+ $input.on('focus.wheelColorPicker', WCP.Handler.input_focus_popup);
+ $input.on('blur.wheelColorPicker', WCP.Handler.input_blur_popup);
+
+ // Rebind suspended events
+ var suspendedEvents = $input.data('jQWCP.suspendedEvents');
+ if(suspendedEvents != undefined) {
+ var blurEvents = suspendedEvents.blur;
+ for(var i = 0; i < blurEvents.length; i++) {
+ $input.on('blur' + (blurEvents[i].namespace == '' ? '' : '.' + blurEvents[i].namespace), blurEvents[i].handler);
+ }
+ }
+ }
+
+
+ // Update active control
+ if($control.length != 0) {
+ // Last time update active control before clearing
+ // Only call this function if mouse position is known
+ // On touch action, touch point is not available
+ if(e.pageX != undefined) {
+ instance.updateActiveControl( e );
+ }
+
+ // Clear active control reference
+ $('body').data('jQWCP.activeControl', null);
+
+ // Trigger sliderup event
+ $input.trigger('sliderup');
+ }
+ };
+
+
+ /**
+ * html.onMouseMove
+ *
+ * Move the active slider (when mouse click is down).
+ *
+ * Note: This event handler is also applied to touchmove
+ */
+ WCP.Handler.html_mousemove = function( e ) {
+ var $control = $( $('body').data('jQWCP.activeControl') ); // Refers to slider wrapper or wheel
+
+ // Do stuffs when there's active control
+ if($control.length == 0)
+ return;
+
+ // If active, prevent default
+ e.preventDefault();
+
+ var $widget = $control.closest('.jQWCP-wWidget');
+ var instance = $widget.data('jQWCP.instance');
+ var $input = $(instance.input);
+
+ instance.updateActiveControl( e );
+
+ // Trigger slidermove event
+ $input.trigger('slidermove');
+
+ return false;
+ };
+
+
+ /**
+ * window.onResize
+ *
+ * Adjust block widgets
+ */
+ WCP.Handler.window_resize = function( e ) {
+ var $widgets = $('body .jQWCP-wWidget.jQWCP-block');
+
+ $widgets.each(function() {
+ var instance = $(this).data('jQWCP.instance');
+ instance.refreshWidget();
+ instance.redrawSliders();
+ });
+ };
+
+
+ /**
+ * overlay.onClick
+ *
+ * Hide colorpicker popup dialog if overlay is clicked.
+ * This has the same effect as blurring input element if hideKeyboard = false.
+ */
+ WCP.Handler.overlay_click = function( e ) {
+ if(WCP.ColorPicker.widget == null)
+ return;
+
+ var $widget = $(WCP.ColorPicker.widget);
+ var instance = $widget.data('jQWCP.instance');
+
+ // If no instance set, do nothing
+ if(instance != null) {
+ var $input = $(instance.input);
+
+ // Trigger 'change' event only when it was modified by widget
+ // because user typing on the textfield will automatically
+ // trigger 'change' event on blur.
+ if(instance.lastValue != instance.input.value) {
+ $input.trigger('change');
+ }
+
+ instance.hide();
+ }
+ };
+
+ /******************************************************************/
+
+ ////////////////////////////////////////////////////////
+ // Automatically initialize color picker on page load //
+ // for elements with data-wheelcolorpicker attribute. //
+ ////////////////////////////////////////////////////////
+
+ $(document).ready(function() {
+ $('[data-wheelcolorpicker]').wheelColorPicker({ htmlOptions: true });
+ });
+
+
+
+ /******************************************************************/
+
+ //////////////////////////////////
+ // Browser specific workarounds //
+ //////////////////////////////////
+
+ (function() {
+ // MOZILLA //
+
+ // Force low resolution slider canvases to improve performance
+ // Note: Do not rely on $.browser since it's obsolete by jQuery 2.x
+ if($.browser != undefined && $.browser.mozilla) {
+ $.fn.wheelColorPicker.defaults.quality = 0.2;
+ }
+
+ // MOBILE CHROME //
+
+ // BUG_RELATIVE_PAGE_ORIGIN
+ // Calibrate the coordinate of top left point of the page
+ // On mobile chrome, the top left of the page is not always set at (0,0)
+ // making window.scrollX/Y and $.offset() useless
+ $(document).ready(function() {
+ $('body').append(
+ '<div id="jQWCP-PageOrigin" style="position: absolute; top: 0; left: 0; height: 0; width: 0;"></div>'
+ );
+
+ var origin = document.getElementById('jQWCP-PageOrigin').getBoundingClientRect();
+ WCP.ORIGIN = origin;
+
+ $(window).on('scroll.jQWCP_RelativePageOriginBugFix', function() {
+ var origin = document.getElementById('jQWCP-PageOrigin').getBoundingClientRect();
+ WCP.ORIGIN = origin;
+ if(origin.left != 0 || origin.top != 0) {
+ WCP.BUG_RELATIVE_PAGE_ORIGIN = true;
+ }
+ });
+ });
+
+ })();
+
+}) (jQuery);
+<style>
+#glm-event-wrapper .glm-event-cal-new {
+ border: 1px solid {if $settings.agenda_date_background_color}{$settings.agenda_date_background_color}{else}#37426E{/if};
+ font-size: 19px;
+ margin: 0 auto;
+ width: 275px;
+ border-radius: 5px;
+ text-align: center;
+}
+.glm-event-cal-day-container-new {
+ background: {if $settings.agenda_date_background_color}{$settings.agenda_date_background_color}{else}#37426E{/if};
+ color: {if $settings.agenda_date_text_color}{$settings.agenda_date_text_color}{else}white{/if};
+ padding: 10px 20px;
+}
+.glm-event-day-event::before {
+ display: none !important;
+}
+#glm-event-wrapper .glm-event-day-event {
+ border: 1px solid {if $settings.agenda_container_background_color}{$settings.agenda_container_background_color}{else}#37426E{/if} !important;
+}
+#glm-event-wrapper h2 {
+ color: {if $settings.agenda_title_color}{$settings.agenda_title_color}{else}#37426E{/if};
+ font-weight: bold;
+}
+{if $settings.event_add_button_hidden}
+#glm-event-add-event {
+ display: none !important;
+}
+{/if}
+</style>
+
<div id="glm-event-wrapper">
- <div class="row collapse">
- {include file='front/events/searchForm.html'}
- </div>
+ <div class="row">
+ {include file='front/events/searchForm.html'}
+ </div>
+
+ <div id="glm-event-agenda-view" class="row" style="max-width: {if $settings.agenda_view_max_width}{$settings.agenda_view_max_width}{else}1000px{/if}; margin: 0 auto;">
+ <div class="small-12 columns">
+ {foreach $eventsByDate as $date => $key}
+ <div class="row glm-event-day-row-new open">
+ <div class="small-12 medium-12 columns">
+ <div class="glm-event-cal-new">
+ <div class="glm-event-cal-day-container-new">
+ <span>{$date|date_format:"%A %B %e"}</span>
+ </div>
- <div id="glm-event-agenda-view" class="row">
- <div class="small-12 columns">
- {foreach $eventsByDate as $date => $key}
- <div class="row glm-event-day-row">
- <div class="small-12 medium-2 columns">
- <div class="glm-event-cal">
- <div class="glm-event-cal-month">{$date|date_format:"%b"}</div>
- <div class="glm-event-cal-day-container">
- <span class="glm-event-cal-day">{$date|date_format:"%e"}</span>
- <span class="glm-event-cal-dow">{$date|date_format:"%a"}</span>
</div>
</div>
- </div>
- <div class="small-12 medium-10 columns">
- {foreach $key as $events}
- {foreach $events as $event}
- {$showTime = true}
- <div class="row glm-event-day-event">
- <div class="small-12 columns">
- <h2 class="agenda-event-name">{$event.name}</h2>
- {$eventDateTime = $event.starting_date|date_format:"%I:%M %P"}
- {foreach $event.recurrences as $rec}
- {$start_time = $rec.start_time.time}
- {if $start_time == $eventDateTime}
- {if ($rec.from_date.timestamp == $rec.to_date.timestamp && $rec.from_date.timestamp == $date)
- or ($date <= $rec.to_date.timestamp && $date >= $rec.from_date.timestamp )}
- <div class='date-range-container'>
- {if !$event.all_day}
- {$showTime = false}
- {$event_start_time = $event.starting_date|date_format:"%m/%d/%Y"}
- {$event_start_time = $event_start_time|cat:' '}
- {$event_start_time = $event_start_time|cat:$rec.start_time.time}
- {$event_end_time = $event.starting_date|date_format:"%m/%d/%Y"}
- {$event_end_time = $event_end_time|cat:' '}
- {$event_end_time = $event_end_time|cat:$rec.end_time.time}
- {if $event_start_time|date_format:"%l:%M %P" == $event_end_time|date_format:"%l:%M %P" or $rec.start_time_only.value == '1'}
- {$event_start_time|date_format:"%l:%M %P"}
- {else}
- {$event_start_time|date_format:"%l:%M %P"} - {$event_end_time|date_format:"%l:%M %P"}
+ <div class="small-12 medium-12 columns">
+ {foreach $key as $events}
+ {foreach $events as $event}
+ {$showTime = true}
+ <div class="row glm-event-day-event" data-url="{$siteBaseUrl}{$pageSlug}/{if !$customPage}{$event.name_slug}/{else}?eventId={$event.id}{/if}">
+ <div class="small-12 large-8 columns">
+
+ <a class="glm-link" href="{$siteBaseUrl}{$pageSlug}/{if !$customPage}{$event.name_slug}/{else}?eventId={$event.id}{/if}">
+ <h2 class="agenda-event-name">{$event.name}</h2>
+ </a>
+
+ {$eventDateTime = $event.starting_date|date_format:"%I:%M %P"}
+ {foreach $event.recurrences as $rec}
+ {$start_time = $rec.start_time.time}
+ {if $start_time == $eventDateTime}
+ {if ($rec.from_date.timestamp == $rec.to_date.timestamp && $rec.from_date.timestamp == $date)
+ or ($date <= $rec.to_date.timestamp && $date >= $rec.from_date.timestamp )}
+ <div class='date-range-container'>
+ {if !$event.all_day}
+ {$showTime = false}
+ {if $event.starting_date|date_format:"%l:%M %P" == $event.ending_date|date_format:"%l:%M %P"}
+ {$event.starting_date|date_format:"%l:%M %P"}
+ {else}
+ {$event.starting_date|date_format:"%l:%M %P"} - {$event.ending_date|date_format:"%l:%M %P"}
+ {/if}
+
+ {/if}
+ {if $rec.name && $rec.name != 'Imported' && $rec.name != 'Imported Event Schedule' }
+ {$rec.name}
{/if}
+ ( {if $event.times|@count > 1} Occurring {/if}
+ {$rec.from_date.date} <span class="agenda-event-recur-dates">
+ {if $rec.from_date.date != $rec.to_date.date}
+ - {$rec.to_date.date}
+ {else if $rec.specific_dates}
+ - {$rec.specific_dates|@end|date_format:"%m/%d/%Y"}
+ {/if}
+ </span>
+
+ {if $rec.day_of_week.names|@count < 7 && $rec.day_of_week.names|@count > 0 }
+ <span class="agenda-days-of-week">
+ on
+ {foreach $rec.day_of_week.names as $day}
+ {if $day == "Thursday"}
+ <span class="agenda-event-weekday"> {$day|substr:0:4} </span>
+ {else}
+ <span class="agenda-event-weekday"> {$day|substr:0:3} </span>
+ {/if}
+ {/foreach}
+ </span>
{/if}
- {if $rec.name && $rec.name != 'Imported' && $rec.name != 'Imported Event Schedule' }
- {$rec.name}
+ )
+ </div>
+ {if $event.locations.city.name}
+ <div class="glm-agenda-city">City: {$event.locations.city.name}</div>
{/if}
- ( {if $event.times|@count > 1} Occurring {/if}
- {$rec.from_date.date} <span class="agenda-event-recur-dates">
- {if $rec.from_date.date != $rec.to_date.date}
- - {$rec.to_date.date}
- {else if $rec.specific_dates}
- - {$rec.specific_dates|@end|date_format:"%m/%d/%Y"}
- {/if}
- </span>
-
- {if $rec.day_of_week.names|@count < 7 && $rec.day_of_week.names|@count > 0 }
- <span class="agenda-days-of-week">
- on
- {foreach $rec.day_of_week.names as $day}
- {if $day == "Thursday"}
- <span class="agenda-event-weekday"> {$day|substr:0:4} </span>
- {else}
- <span class="agenda-event-weekday"> {$day|substr:0:3} </span>
- {/if}
- {/foreach}
-
- </span>
{/if}
- )
- </div>
+ {/if}
+ {/foreach}
+ <div class="day-times-wrapper">
+ {if !$event.all_day && $showTime}
+ {if $event.starting_date|date_format:"%l:%M %P" == $event.ending_date|date_format:"%l:%M %P"}
+ <div class="agenda-event-times">{$event.starting_date|date_format:"%l:%M %P"}</div>
+ {else}
+ <div class="agenda-event-times"> {$event.starting_date|date_format:"%l:%M %P"} - {$event.ending_date|date_format:"%l:%M %P"}</div>
{/if}
{/if}
- {/foreach}
- <div class="day-times-wrapper">
- {if !$event.all_day && $showTime}
- {if $event.starting_date|date_format:"%l:%M %P" == $event.ending_date|date_format:"%l:%M %P"}
- <div class="agenda-event-times">{$event.starting_date|date_format:"%l:%M %P"}</div>
- {else}
- <div class="agenda-event-times"> {$event.starting_date|date_format:"%l:%M %P"} - {$event.ending_date|date_format:"%l:%M %P"}</div>
+ </div>
+ <div class="event-contents clearfix">
+ {if $event.locations}
+ <div class="glm-agenda-city">Location: {$event.locations.name}</div>
{/if}
- {/if}
- </div>
- <div class="event-content glm-hide clearfix">
- {if $event.image}<img style="float:right;" data-src="{$imgUrl}{$event.image}">{/if}
- {$event.intro}
- <div>
- <a class="glm-read-more" href="{$siteBaseUrl}{$pageSlug}/{if !$customPage}{$event.name_slug}/{else}?eventId={$event.id}{/if}">Read More</a>
+
+ {$event.intro}
+
</div>
</div>
+ <div class="small-12 large-4 columns glm-events-agenda-image">
+ {if $event.image}<img class="" style="float:none;" src="{$imgUrl}{$event.image}">{/if}
+ </div>
</div>
- </div>
+ {/foreach}
{/foreach}
- {/foreach}
+ </div>
</div>
- </div>
- {/foreach}
+ {/foreach}
+ </div>
</div>
- </div>
- {assign var="current_year" value=$smarty.now|date_format:"%Y"}
- {assign var="current_month" value=$smarty.now|date_format:"%m"}
- <div id="event-date-toggle-container">
- <label class="date-toggle-label" for="#event-date-toggle"> Select a Date <label>
- <select id="event-date-toggle">
- <option value="" disabled selected> Select Month</option>
- {foreach $months as $year=>$month}{
- {foreach $month as $m=>$value}
- {if $current_month == $value.date && $current_year == $year}
- <option value="{$year}-{$value.date}-01" selected> {$value.name} - {$year}</option>
- {else}
- <option value="{$year}-{$value.date}-01"> {$value.name} - {$year}</option>
- {/if}
+ {assign var="current_year" value=$smarty.now|date_format:"%Y"}
+ {assign var="current_month" value=$smarty.now|date_format:"%m"}
+ <div id="event-date-toggle-container">
+ <label class="date-toggle-label" for="#event-date-toggle"> Select a Date <label>
+ <select id="event-date-toggle">
+ <option value="" disabled selected> Select Month</option>
+ {foreach $months as $year=>$month}{
+ {foreach $month as $m=>$value}
+ {if $current_month == $value.date && $current_year == $year}
+ <option value="{$year}-{$value.date}-01" selected> {$value.name} - {$year}</option>
+ {else}
+ <option value="{$year}-{$value.date}-01"> {$value.name} - {$year}</option>
+ {/if}
+ {/foreach}
{/foreach}
- {/foreach}
- </select>
- </div>
- <!-- Calendar -->
- <div id="eventCalendar" style='position: relative;'>
- <div class='event-overlay'>
- <div class="loading"></div>
+ </select>
+ </div>
+ <!-- Calendar -->
+ <div id="eventCalendar" style='position: relative;'>
+ <div class='event-overlay'>
+ <div class="loading"></div>
+ </div>
</div>
</div>
-</div>
-
-
-
-<script type="text/javascript">
- jQuery(document).ready(function($) {
-
- var fullCalendarLoaded = false;
- var recurrencesInited = false;
- var locationsInited = false;
- var table = 'glm-table-calendar';
- var post_start, post_end, month_obj;
- var rows = $(".glm-event-day-row");
- var agenda = $("#glm-event-agenda-view");
- var view_select = $("#glm-event-view-select");
- var search = $("#glm-events-search-form");
- var calendar = $("#eventCalendar");
- var event_search = $(".glm-search-icon");
- var main_content = $("#main-content");
- var member_id = '{$memberId}';
- var view = '{$cal_view}';
- var months = '{$json_months}';
- var category = $('#glm-event-category').val();
- var current_month = $('{$current_month}');
- var current_year = $('{$current_year}');
- var custom_page = '{$customPage}';
- var page_slug = '{$pageSlug}';
- var retain_date;
-
- if(!member_id){
- member_id = null;
- }
-
- // add 7 days to ensure we always get the current month and not any other month view that may
- // be visible (last few days of previous month or first few days of next month)
- function get_current_view(){
+
+ <script type="text/javascript">
+ jQuery(document).ready(function($) {
+
+ var fullCalendarLoaded = false;
+ var recurrencesInited = false;
+ var locationsInited = false;
+ var table = 'glm-table-calendar';
+ var post_start, post_end, month_obj;
+ var rows = $(".glm-event-day-row");
+ var agenda = $("#glm-event-agenda-view");
+ var view_select = $("#glm-event-view-select");
+ var search = $("#glm-events-search-form");
+ var calendar = $("#eventCalendar");
+ var event_search = $(".glm-search-icon");
+ var main_content = $("#main-content");
+ var member_id = '{$memberId}';
+ var view = '{$cal_view}';
+ var months = '{$json_months}';
+ var category = $('#glm-event-category').val();
+ var current_month = $('{$current_month}');
+ var current_year = $('{$current_year}');
+ var custom_page = '{$customPage}';
+ var page_slug = '{$pageSlug}';
var retain_date;
- var calCurrDate = $('#eventCalendar').fullCalendar('getView').start;
- var d = moment(calCurrDate).add(7, 'days').format('YYYY-MM-01');
-
- return retain_date = d;
- }
- function in_mobile(){
- if($(window).width() < 641 ){
- return true;
- } else {
- return false;
+
+ if(!member_id){
+ member_id = null;
}
- }
- $('#glm-event-from').on("change", function(){
- var from_date = $(this).val();
- $('#glm-event-to').val(from_date);
+ // add 7 days to ensure we always get the current month and not any other month view that may
+ // be visible (last few days of previous month or first few days of next month)
+ function get_current_view(){
+ var retain_date;
+ var calCurrDate = $('#eventCalendar').fullCalendar('getView').start;
+ var d = moment(calCurrDate).add(7, 'days').format('YYYY-MM-01');
- });
+ return retain_date = d;
+ }
+ function in_mobile(){
+ if($(window).width() < 641 ){
+ return true;
+ } else {
+ return false;
+ }
+ }
- months = JSON.parse(months);
+ $('#glm-event-from').on("change", function(){
+ var from_date = $(this).val();
+ $('#glm-event-to').val(from_date);
- event_search.on('click', function(){
- sessionStorage.override = 'yes';
- });
+ });
- if( sessionStorage.view && sessionStorage.override === 'no' && !in_mobile()){
- view = sessionStorage.view;
- } else if( sessionStorage.override === 'yes' || in_mobile()){
- view = 'agenda';
- }
-
- // AJAX FUNCTION ************************************************
- // Get calendar month via AJAX
- function eventsCalMonthAJAX(month) {
- var dat = {
-
- action: 'glm_members_admin_ajax',
- glm_action: 'eventsCalMonthAJAX',
- month: month,
- category: category,
- member_id: member_id,
- custom_page: custom_page,
- page_slug: page_slug
- };
- $('.fc-event').remove();
-
- jQuery.ajax({
- type: 'POST',
- url: '{$ajaxUrl}',
- data: dat,
- beforeSend: function(){
- $(".event-overlay").show();
- $(".loading").show();
+ months = JSON.parse(months);
+
+ event_search.on('click', function(){
+ sessionStorage.override = 'yes';
+ });
+
+ if( sessionStorage.view && sessionStorage.override === 'no' && !in_mobile()){
+ view = sessionStorage.view;
+ } else if( sessionStorage.override === 'yes' || in_mobile()){
+ view = 'agenda';
+ }
+
+ // AJAX FUNCTION ************************************************
+ // Get calendar month via AJAX
+ function eventsCalMonthAJAX(month) {
+ var dat = {
+
+ action: 'glm_members_admin_ajax',
+ glm_action: 'eventsCalMonthAJAX',
+ month: month,
+ category: category,
+ member_id: member_id,
+ custom_page: custom_page,
+ page_slug: page_slug
+ };
+ $('.fc-event').remove();
+
+ jQuery.ajax({
+ type: 'POST',
+ url: '{$ajaxUrl}',
+ data: dat,
+ beforeSend: function(){
+ $(".event-overlay").show();
+ $(".loading").show();
+ },
+ complete: function(){
+ $(".event-overlay").hide();
+ $(".loading").hide();
+ },
+ cache: false,
+ success: function (response){
+ var buildingEvents = [];
+ //var events_obj = jQuery.parseJSON(response);
+ var events_obj = response;
+ var events = events_obj.events;
+ buildingEvents = $.map(events, function(i, val) {
+ return {
+ title: i.title,
+ start: i.start,
+ end: i.last,
+ allDay: i.all_day,
+ url: i.url,
+ recurs: i.recurs
+ };
+ });
+ $("#eventCalendar").fullCalendar('removeEvents');
+ $("#eventCalendar").fullCalendar('addEventSource', buildingEvents);
+ }
+ });
+ var timestamp = $.now();
+ var url = '{$ajaxUrl}' + '?t=' + timestamp;
+ }
+ var height = 900;
+ // Calendar *****************************************************
+ $('#eventCalendar').fullCalendar({
+ eventOrder: 'allDay',
+ height: height,
+ contentHeight: height,
+ eventRender: function(event, element){
+ element.attr('title', event.title);
},
- complete: function(){
- $(".event-overlay").hide();
- $(".loading").hide();
+ viewRender: function (view, element){
+ post_start = view.start._d;
+ post_end = view.end._d;
+ {literal}month_obj = {start: view.start._d, last: view.end._d};{/literal}
},
- cache: false,
- success: function (response){
- var buildingEvents = [];
- //var events_obj = jQuery.parseJSON(response);
- var events_obj = response;
- var events = events_obj.events;
- buildingEvents = $.map(events, function(i, val) {
- return {
- title: i.title,
- start: i.start,
- end: i.last,
- allDay: i.all_day,
- url: i.url,
- recurs: i.recurs
- };
- });
- $("#eventCalendar").fullCalendar('removeEvents');
- $("#eventCalendar").fullCalendar('addEventSource', buildingEvents);
- }
- });
- var timestamp = $.now();
- var url = '{$ajaxUrl}' + '?t=' + timestamp;
- }
- var height = 900;
- // Calendar *****************************************************
- $('#eventCalendar').fullCalendar({
- eventOrder: 'allDay',
- height: height,
- contentHeight: height,
- eventRender: function(event, element){
- element.attr('title', event.title);
- },
- viewRender: function (view, element){
- post_start = view.start._d;
- post_end = view.end._d;
- {literal}month_obj = {start: view.start._d, last: view.end._d};{/literal}
- },
- header: {
- left: 'prev,next,today',
- center: 'title',
- right: ''
- },
- dayClick: function(date, jsEvent, view) {
- //$('#eventCalendar').fullCalendar('changeView', 'agendaDay');
- //$('#eventCalendar').fullCalendar('gotoDate', date);
- },
- editable: false,
- handleWindowResize: true,
- lazyFetching: true,
- eventClick : function (event){
-
- sessionStorage.current_calendar_view = get_current_view();
-
-
- if(custom_page !== ''){
- location.href = event.url + '&glm_event_from=' + event.start.format();
- } else {
- location.href = event.url + '?glm_event_from=' + event.start.format();
- }
+ header: {
+ left: 'prev,next,today',
+ center: 'title',
+ right: ''
+ },
+ dayClick: function(date, jsEvent, view) {
+ //$('#eventCalendar').fullCalendar('changeView', 'agendaDay');
+ //$('#eventCalendar').fullCalendar('gotoDate', date);
+ },
+ editable: false,
+ handleWindowResize: true,
+ lazyFetching: true,
+ eventClick : function (event){
+
+ sessionStorage.current_calendar_view = get_current_view();
- return false;
- },
- eventLimit: true,
- views: {
- month: {
- eventLimit: 4,
- eventBackgroundColor: 'transparent',
- eventTextColor: '#3A87AD',
- eventBorderColor: 'transparent',
+
+ if(custom_page !== ''){
+ location.href = event.url + '&glm_event_from=' + event.start.format();
+ } else {
+ location.href = event.url + '?glm_event_from=' + event.start.format();
+ }
+
+ return false;
},
- agenda: {
- eventLimit: 4
+ eventLimit: true,
+ views: {
+ month: {
+ eventLimit: 4,
+ eventBackgroundColor: 'transparent',
+ eventTextColor: '#3A87AD',
+ eventBorderColor: 'transparent',
+ },
+ agenda: {
+ eventLimit: 4
+ }
}
- }
- });
+ });
- if(view === "calendar"){
- eventsCalMonthAJAX(month_obj);
- main_content.removeClass("small-8").addClass("small-12");
- calendar.show();
- view_select.val('calendar');
-
- } else if ( view === "agenda"){
- calendar.hide();
- agenda.css("display", "block");
- view_select.val('agenda');
- }
- $("#glm-event-view-select").on("change", function (){
- sessionStorage.override = 'no';
- sessionStorage.setItem("view", $(this).attr("value"));
- if($("#glm-event-view-select option:selected").val() === "calendar"){
+ if(view === "calendar"){
eventsCalMonthAJAX(month_obj);
- agenda.css("display","none");
- calendar.fadeIn('slow', function(){});
- calendar.fullCalendar('render');
+ main_content.removeClass("small-8").addClass("small-12");
+ calendar.show();
+ view_select.val('calendar');
- } else if ( $("#glm-event-view-select option:selected").val() === "agenda"){
+ } else if ( view === "agenda"){
+ calendar.hide();
agenda.css("display", "block");
- calendar.fadeOut('slow', function(){});
+ view_select.val('agenda');
}
- });
- $(window).on("load", function(){
+ $("#glm-event-view-select").on("change", function (){
+ sessionStorage.override = 'no';
+ sessionStorage.setItem("view", $(this).attr("value"));
+ if($("#glm-event-view-select option:selected").val() === "calendar"){
+ eventsCalMonthAJAX(month_obj);
+ agenda.css("display","none");
+ calendar.fadeIn('slow', function(){});
+ calendar.fullCalendar('render');
+
+ } else if ( $("#glm-event-view-select option:selected").val() === "agenda"){
+ agenda.css("display", "block");
+ calendar.fadeOut('slow', function(){});
+ }
+ });
+ $(window).on("load", function(){
- if(sessionStorage.current_calendar_view){
- $('#event-date-toggle option').each(function(){
- if( $(this).val() === sessionStorage.current_calendar_view){
- $(this).prop('selected', true);
- }
- });
- }
+ if(sessionStorage.current_calendar_view){
+ $('#event-date-toggle option').each(function(){
+ if( $(this).val() === sessionStorage.current_calendar_view){
+ $(this).prop('selected', true);
+ }
+ });
+ }
- $('#event-date-toggle-container').insertAfter( $('.fc-left')).fadeTo('slow', 1);
+ $('#event-date-toggle-container').insertAfter( $('.fc-left')).fadeTo('slow', 1);
- $('#event-date-toggle').on("change", function(){
- var selected_date = $(this).val();
+ $('#event-date-toggle').on("change", function(){
+ var selected_date = $(this).val();
- $('#eventCalendar').fullCalendar('gotoDate', selected_date);
+ $('#eventCalendar').fullCalendar('gotoDate', selected_date);
+ eventsCalMonthAJAX(month_obj);
+ if(sessionStorage.current_calendar_view){
+ sessionStorage.current_calendar_view = '';
+ }
+ });
+ });
+ if(sessionStorage.current_calendar_view){
+ $('#eventCalendar').fullCalendar('gotoDate', sessionStorage.current_calendar_view);
eventsCalMonthAJAX(month_obj);
- if(sessionStorage.current_calendar_view){
+ }
+ // initialize calendar with AJAX calls *************************************
+ $(document).on("click", "button.fc-button", function () {
+ if(sessionStorage.current_calendar_view){
sessionStorage.current_calendar_view = '';
}
+
+ eventsCalMonthAJAX(month_obj);
});
- });
- if(sessionStorage.current_calendar_view){
- $('#eventCalendar').fullCalendar('gotoDate', sessionStorage.current_calendar_view);
- eventsCalMonthAJAX(month_obj);
- }
- // initialize calendar with AJAX calls *************************************
- $(document).on("click", "button.fc-button", function () {
- if(sessionStorage.current_calendar_view){
- sessionStorage.current_calendar_view = '';
- }
- eventsCalMonthAJAX(month_obj);
- });
+ $('#eventCalendar').find('.fc-today-button').on("click", function(){
+ eventsCalMonthAJAX(month_obj);
+ var current_view = get_current_view();
+ $('#event-date-toggle option').each(function(){
+ if( $(this).val() === current_view){
+ $(this).prop('selected', true);
+ }
+ });
+ });
- $('#eventCalendar').find('.fc-today-button').on("click", function(){
- eventsCalMonthAJAX(month_obj);
- var current_view = get_current_view();
- $('#event-date-toggle option').each(function(){
- if( $(this).val() === current_view){
- $(this).prop('selected', true);
- }
+ var dates = $(".agenda-event-recur-dates");
+ dates.each( function (){
+ if( $(this).text().indexOf('-') < 0 ){
+ $(this).remove();
+ }
});
- });
- var dates = $(".agenda-event-recur-dates");
- dates.each( function (){
- if( $(this).text().indexOf('-') < 0 ){
- $(this).remove();
- }
+ // Event agenda view container click, go to event url
+ $('.glm-event-day-event').on("click", function(){
+ window.location = $(this).data('url');
+ });
+
+
});
+ </script>
- });
-</script>