Вход Регистрация
Файл: jcolor.js
Строк: 742
<?php
(function ($) {
  
'use strict';

  function 
clamp(val, min, max) { return Math.max(Math.min(val, max), min); }
  function 
identity(val) { return val.toFixed(2); }
  function 
uchar(val) { return ((val * 255) | 0) + ''; }
  function 
degree(val) { return ((val * 360) | 0) + ''; }
  function 
percent(val) { return (val * 100).toFixed(2) + '%'; }
  var 
base64encode = window.btoa || function (str) {
    var 
result = [],
        
position = -1,
        
len = str.length,
        
nan0, nan1, nan2, enc = [ ,,, ];

    while (++
position < len) {
      
nan0 = str.charCodeAt(position);
      
nan1 = str.charCodeAt(++position);
      
enc[0] = nan0 >> 2;
      
enc[1] = ((nan0 & 3) << 4) | (nan1 >> 4);
      if (
isNaN(nan1)) {
        
enc[2] = enc[3] = 64;
      } else {
        
nan2 = str.charCodeAt(++position);
        
enc[2] = ((nan1 & 15) << 2) | (nan2 >> 6);
        
enc[3] = (isNaN(nan2)) ? 64 : nan2 & 63;
      }
      
result.push(
          
alphabet.charAt(enc[0]),
          
alphabet.charAt(enc[1]),
          
alphabet.charAt(enc[2]),
          
alphabet.charAt(enc[3]));
    }
    return 
result.join('');
  };

  var 
componentMatchers = { r: /R/g, g: /G/g, b: /B/g, h: /H/g, s: /S/g, l: /L/g, a: /A/g, };
  var 
componentMap = { r: uchar, g: uchar, b: uchar, h: degree, s: percent, l: percent, a: identity, };
  var 
isSafari = /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
  var 
isUnsupportedBrowser = /MSIE [1-8]/.test(navigator.userAgent);
  var 
supportsGradients = !(/MSIE 9.0/.test(navigator.userAgent));
  var 
supportsTransitions = supportsGradients;
  var 
isTouchDevice = 'ontouchstart' in document.documentElement || 'ontouchstart' in window;
  var 
alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
  var 
staticComponentValues = { r: 0, g: 0, b: 0, h: 0, s: 1, l: 0.5, a: 1 };
  var 
componentStops = { r: 2, g: 2, b: 2, h: 7, s: 2, l: 3, a: 2 };

  var 
LEFT_BUTTON = 0;
  var 
TRANSITION_END = isSafari ? 'webkitTransitionEnd' : 'transitionend';
  var 
POINTER_DOWN_EVENT = isTouchDevice ? 'touchstart' : 'mousedown';
  var 
POINTER_MOVE_EVENT = isTouchDevice ? 'touchmove' : 'mousemove';
  var 
POINTER_UP_EVENT = isTouchDevice ? 'touchend touchcancel' : 'mouseup';
  var 
NEW_COLOR_EVENT = 'newcolor';
  var 
EXPANDED_Z_INDEX = 999999;

  function 
getGradientTemplate(component, space, staticComponents) {
    var 
colorComponents = staticComponents ? space.split('').map(function (component) {
      return 
componentMap[component](staticComponentValues[component]);
    }) : 
space.split('');
    var 
componentIndex = space.indexOf(component);
    var 
colors = [];
    var 
n = componentStops[component];
    var 
i;

    
// Generate the color stops, e.g. "rgba(R, G, 0, A),rgba(R, G, 255, A)"
    
for (i = 0; i < n; ++i) {
      var 
frac = i / (n - 1);
      
colorComponents[componentIndex] = componentMap[component](frac);
      var 
color = supportsGradients ?
        
space + '(' + colorComponents.join().toUpperCase() + ')' :
        
'<stop stop-color="' + space + '(' + colorComponents.join().toUpperCase() + ')" offset="' + frac + '"/>';
      
colors.push(color);
    }
    
colors = colors.join(supportsGradients ? ',' : '');

    
// The template function substitutes the color placeholders, e.g. R, G, A for the
    // color values specified in the color argument
    
return function (color) {
      var 
ret = colors;
      for (var 
c in color) {
        
c === component || (ret = ret.replace(componentMatchers[c], componentMap[c](color[c])));
      }
      if (
supportsGradients) {
        return 
'linear-gradient(to right, ' + ret + ')';
      } else {
        var 
svg =
          
'<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" ' +
              
'viewBox="0 0 1 1" preserveAspectRatio="none">' +
          
'<linearGradient id="the-gradient" gradientUnits="userSpaceOnUse" x1="0%" y1="0%" x2="100%" y2="0%">' +
          
ret +
          
'</linearGradient>' +
          
'<rect x="0" y="0" width="1" height="1" fill="url(#the-gradient)" />' +
          
'</svg>';
        return 
'url(data:image/svg+xml;base64,' + base64encode(svg) + ')';
      }
    };
  }

  function 
getRgb(c) {
    if (
'r' in c) { return c; }

    var 
r, g, b;
    var 
h = c.h, s = c.s, l = c.l;

    function 
hue2rgb(p, q, t) {
      if (
t < 0) { t += 1; }
      if (
t > 1) { t -= 1; }
      if (
t < 1 / 6) { return p + (q - p) * 6 * t; }
      if (
t < 1 / 2) { return q; }
      if (
t < 2 / 3) { return p + (q - p) * (2 / 3 - t) * 6; }
      return 
p;
    }

    if (
s === 0) {
      
r = g = b = l; // achromatic
    
} else {
      var 
q = l < 0.5 ? l * (1 + s) : l + s - l * s;
      var 
p = 2 * l - q;
      
r = hue2rgb(p, q, h + 1 / 3);
      
g = hue2rgb(p, q, h);
      
b = hue2rgb(p, q, h - 1 / 3);
    }

    var 
ret = { r: r, g: g, b: b };
    
'a' in c && (ret.a = c.a);
    return 
ret;
  }

  function 
getHsl(c) {
    if (
'h' in c) { return c; }

    var 
r = c.r, g = c.g, b = c.b;
    var 
max = Math.max(r, g, b), min = Math.min(r, g, b);
    var 
h, s, l = (max + min) / 2;

    if (
max === min) {
      
h = s = 0; // achromatic
    
} else {
      var 
d = max - min;
      
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
      switch (
max) {
      case 
r: h = (g - b) / d + (g < b ? 6 : 0); break;
      case 
g: h = (b - r) / d + 2; break;
      case 
b: h = (r - g) / d + 4; break;
      }
      
h /= 6;
    }

    var 
ret = { h: h, s: s, l: l };
    
'a' in c && (ret.a = c.a);
    return 
ret;
  }

  
// COLOR CLASS

  
function Color(space, color) {
    var 
i, components = {};

    
// Validate color space argument
    
space = space.toLowerCase();
    if (!(/^(
rgb|hsl)a?$/i).test(space)) {
      throw 
'Color spaces must be any of the following: "rgb", "rgba", "hsl" or "hsla"';
    }

    
// Validate color argument
    
if (typeof color === 'string') {
      
color = color.toLowerCase();
      if (/^
#[0-9a-f]{6}([0-9a-f]{2})?$/.test(color)) {
        
space.length === 4 && color.length !== 9 && (color += 'ff');  // Default alpha to fully opaque
        
for (i = 1; i < color.length; i += 2) {
          
components[space[(i - 1) / 2]] = parseInt(color.substr(i, 2), 16) / 255;
        }
      } else if (/^(
rgb|hsl)a?([ds,.%]+)$/.test(color)) {
        var 
parsedSpace = color.match(/(rgb|hsl)a?/)[0];
        var 
componentsArray = color.match(/[d.]+/g);
        if (/
rgb/.test(parsedSpace)) {
          
components.r = componentsArray[0] / 255;
          
components.g = componentsArray[1] / 255;
          
components.b = componentsArray[2] / 255;
        } else {
          
components.h = componentsArray[0] / 360;
          
components.s = componentsArray[1] / 100;
          
components.l = componentsArray[2] / 100;
        }
        
components.a = +componentsArray[3];
      } else {
        throw 
'Color strings must be hexadecimal (e.g. "#00ff00", or "#00ff00ff") or CSS style (e.g. rgba(0,255,0,1))';
      }
    } else if ($.
isPlainObject(color)) {
      var 
sortedColorComponentKeys = Object.keys(color).sort().join('');
      if (!(/^
a?(bgr|hls)$/i).test(sortedColorComponentKeys)) {
        throw 
'Color objects must contain either r, g and b keys, or h, s and l keys. The a key is optional.';
      }
      if (
space.split('').sort().join('') !== sortedColorComponentKeys) {
        
color = /rgb/.test('space') ? getRgb(color) : getHsl(color);
      }
      
components = color;
    } else {
      throw 
'Unrecognized color format';
    }

    
// Make sure the color matches the color space. No-op if they are already the same
    
components = /rgb/.test(space) ? getRgb(components) : getHsl(components);
    
// Add an alpha channel if missing
    
isFinite(components.a) || (components.a = 1);

    for (var 
key in components) {
      if (
components[key] < 0 || 1 < components[key]) { throw 'Color component out of range: ' + key; }
    }

    
this.getComponents = function () { return components; };
    
this.getComponent = function (componentKey) { return components[componentKey]; };
    
this.setComponent = function (componentKey, value) { components[componentKey] = value; };
    
this.getSpace = function () { return space; };
  }

  
Color.prototype.convertComponents = function (newSpace) {
    
newSpace = newSpace || this.getSpace();
    var 
components = $.extend({}, this.getComponents());

    
// See if the components are already in the right space
    
if (new RegExp(newSpace).test(this.getSpace())) {
      
newSpace.length === 3 && (delete components.a);
      return 
components;
    }

    
components = /rgb/.test(newSpace) ? getRgb(components) : getHsl(components);
    if (/
a/.test(newSpace)) {
      var 
a = this.getComponent('a');
      
components.a = typeof a === 'undefined' ? 1 : a;
    }

    return 
components;
  };

  
Color.prototype.componentsToString = function (components, space) {
    function 
pad(str) {
      return (
str.length === 1 ? '0' : '') + str;
    }
    var 
str = '#';
    for (var 
i = 0; i < space.length; ++i) {
      
str += pad(Math.floor(255 * components[space[i]]).toString(16));
    }
    return 
str;
  };

  
Color.prototype.toString = function (space) {
    
space = space || this.getSpace();
    return 
this.componentsToString(this.convertComponents(space), space);
  };

  
Color.prototype.componentsToCssValuesString = function (components, space) {
    var 
componentArray = [];
    for (var 
i = 0; i < space.length; ++i) {
      var 
componentKey = space[i];
      
componentArray.push(componentMap[componentKey](components[componentKey]));
    }
    return 
componentArray.join(', ');
  };

  
Color.prototype.toCssString = function (space) {
    
space = space || this.getSpace();
    return 
space + '(' + this.componentsToCssValuesString(this.convertComponents(space), space) + ')';
  };

  
// COLORPICKER CLASS

  
function Colorpicker($el, userOptions) {
    var 
self = this;
    var 
originalClasses = $el.attr('class');
    var 
$originalChildren = $el.children().detach();
    var 
originalText = $el.text();
    
$el.addClass('colorpicker').empty();
    var 
$body = $('body');

    var 
options = $.extend({
      
color: $el.css('color'),
      
colorSpace: 'hsla',
      
expandEvent: 'mousedown touchstart',
      
collapseEvent: '',
      
staticComponents: false,
      
boundingElement: $body,
      
modal: false,
    }, 
userOptions);

    var 
color = new Color(options.colorSpace, options.color);

    
$el.addClass('componentcount-' + color.getSpace().length).toggleClass('show-labels', !!options.labels);

    function 
addChild(className, $parent) { return $('<div>').addClass(className).appendTo($parent); }
    var 
$maximizeWrapper = addChild('maximize-wrapper', $el);
    var 
$innerMaximizeWrapper = addChild('inner-maximize-wrapper', $maximizeWrapper);
    var 
$uiWrapper = addChild('ui-wrapper', $innerMaximizeWrapper);
    var 
$displayWrapper = addChild('display-wrapper', $uiWrapper);
    var 
$display = addChild('display', $displayWrapper);
    var 
$sliderContainer = addChild('slider-container', $uiWrapper);
    var 
sliders = $.map(color.getSpace().split(''), function (componentKey) {
      var 
$slider = addChild('slider ' + componentKey, $sliderContainer);
      
addChild('handle', $slider).attr('data-component', componentKey);
      
$slider.data({
        
componentKey: componentKey,
        
template: getGradientTemplate(componentKey, color.getSpace(), options.staticComponents),
      });
      return 
$slider;
    });

    var 
$outputWrapper, colorOutputFunction;
    if (
options.displayColor) {
      if (!(/^(
hex|css)$/.test(options.displayColor))) { throw 'Invalid displayColor value, should be "hex" or "css"'; }
      
$outputWrapper = addChild('output-wrapper', $innerMaximizeWrapper);
      
colorOutputFunction = {
        
hex: color.toString,
        
css: color.toCssString,
      }[
options.displayColor].bind(color, options.displayColorSpace || options.colorSpace);
    }

    
// Listen to new colors, and update the UI accordingly
    
function onNewColor(ev, self, componentKey, value) {
      
componentKey && color.setComponent(componentKey, value);
      for (var 
i = 0; i < sliders.length; ++i) {
        var 
$slider = sliders[i];
        
$slider
            
.css({
              
backgroundImage: $slider.data('template')(color.getComponents()),
            })
            .
find('.handle').css({
              
left: (color.getComponent($slider.data('componentKey')) * 100) + '%',
            });
        
$display.css({ backgroundColor: color.toCssString() });
        
options.displayColor && $outputWrapper.text(colorOutputFunction());
      }
    }
    
$el.on(NEW_COLOR_EVENT, onNewColor);
    
setTimeout(onNewColor.bind(null, undefined, this), 0);

    
// Expanding the colorpicker
    
var onClickOutside = function (ev) {
      $(
ev.target).closest($el).length || collapse();
    };
    var 
expand, collapse;
    
expand = function () {
      
$el.addClass('expanded').css({ zIndex: EXPANDED_Z_INDEX });
      
options.modal && $body.addClass('colorpicker-modal');

      var 
height = 0;
      
$innerMaximizeWrapper.children().each(function () { height += $(this).outerHeight(true); });
      
$innerMaximizeWrapper.css({ width: $uiWrapper.width(), height: height });
      $(
window).on(POINTER_DOWN_EVENT, onClickOutside);
      
options.collapseEvent && $el.on(options.collapseEvent, collapse);
      
$el.off(options.expandEvent, expand);

      var 
boundingRect = options.boundingElement[0].getBoundingClientRect();
      var 
uiWrapperRect = $uiWrapper[0].getBoundingClientRect();
      var 
dX = Math.min(0, boundingRect.right - uiWrapperRect.right - 10);
      var 
dY = Math.min(0, boundingRect.bottom - uiWrapperRect.bottom - 10);
      
$el.css('transform', 'translate(' + dX + 'px, ' + dY + 'px)');
    };
    
collapse = function () {
      
supportsTransitions ?
        
$el.off(TRANSITION_END).one(TRANSITION_END, function () { $el.css({ zIndex: '' }); }) :
        
$el.css({ zIndex: '' });
      
$el.css({ zIndex: EXPANDED_Z_INDEX - 1 });
      
$innerMaximizeWrapper.css({ width: '', height: '' });
      
$el.removeClass('expanded');
      
options.modal && $body.removeClass('colorpicker-modal');

      $(
window).off(POINTER_DOWN_EVENT, onClickOutside);
      
options.expandEvent && $el.on(options.expandEvent, expand);
      
$el.css('transform', '');
    };

    
options.expandEvent && $el.on(options.expandEvent, expand);

    var 
triggerNewColor = function (ev) {
      var 
$target = $(ev.target);
      if (!
$target.hasClass('slider')) { return; }
      var 
offsetX = isTouchDevice ?
          
ev.originalEvent.touches[0].clientX - $(ev.target).offset().left :
          $.
isNumeric(ev.offsetX) ? ev.offsetX : ev.clientX - $(ev.target).offset().left;
      
$target.trigger(NEW_COLOR_EVENT, [
        
self, $target.data('componentKey'), clamp(offsetX / $target.outerWidth(), 0, 1)
      ]);
      
ev.preventDefault();
      
ev.stopPropagation();
    };
    var 
onPointerUp = function () {
      $(
window).off(POINTER_MOVE_EVENT, triggerNewColor);
    };
    
$el.on(POINTER_DOWN_EVENT, function (ev) {
      var 
$target = $(ev.target);
      if (
ev.type === 'mousedown' && ev.button !== LEFT_BUTTON || !$target.hasClass('slider')) { return; }

      
triggerNewColor(ev);

      $(
window).on(POINTER_MOVE_EVENT, triggerNewColor);
      $(
window).one(POINTER_UP_EVENT, onPointerUp);
    });

    
// Public functions
    
this.destroy = function () {
      $(
window).off(POINTER_UP_EVENT, onPointerUp);
      $(
window).off(POINTER_MOVE_EVENT, triggerNewColor);
      $(
window).off(POINTER_DOWN_EVENT, onClickOutside);
      
$el.off().empty().removeData('colorpicker')
          .
attr('class', originalClasses).html($originalChildren).text(originalText);
    };
    
this.toString = function () { return color.toString.apply(color, arguments); };
    
this.toCssString = function () { return color.toCssString.apply(color, arguments); };
    
this.toObject = function () { return color.convertComponents.apply(color, arguments); };
    
this.getColorSpace = function () { return color.getSpace(); };
    
this.on = $el.on.bind($el);
    
this.off = $el.off.bind($el);

    
$el.data('colorpicker', this);
    return 
this;
  }

  
// REGISTER PLUGIN

  
$.fn.colorpicker = function (options) {
    if (
isUnsupportedBrowser) { throw 'Colorpicker does not work with your browser'; }
    var 
$el = this.eq(0);
    if (!
$el.length) { throw 'No element matched'; }
    return 
$el.data('colorpicker') || new Colorpicker($el, options);
  };

}(
window.$));
?>
Онлайн: 1
Реклама