--- /dev/null
+/*!
+* Colorpicker for Bootstrap
+*
+* Copyright 2012 Stefan Petre
+* Licensed under the Apache License v2.0
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+*/
+.colorpicker-saturation {
+width: 100px;
+height: 100px;
+background-image: url(../img/saturation.png);
+cursor: crosshair;
+float: left;
+}
+.colorpicker-saturation i {
+display: block;
+height: 5px;
+width: 5px;
+border: 1px solid #000;
+-webkit-border-radius: 5px;
+-moz-border-radius: 5px;
+border-radius: 5px;
+position: absolute;
+top: 0;
+left: 0;
+margin: -4px 0 0 -4px;
+}
+.colorpicker-saturation i b {
+display: block;
+height: 5px;
+width: 5px;
+border: 1px solid #fff;
+-webkit-border-radius: 5px;
+-moz-border-radius: 5px;
+border-radius: 5px;
+}
+.colorpicker-hue, .colorpicker-alpha {
+width: 15px;
+height: 100px;
+float: left;
+cursor: row-resize;
+margin-left: 4px;
+margin-bottom: 4px;
+}
+.colorpicker-hue i, .colorpicker-alpha i {
+display: block;
+height: 1px;
+background: #000;
+border-top: 1px solid #fff;
+position: absolute;
+top: 0;
+left: 0;
+width: 100%;
+margin-top: -1px;
+}
+.colorpicker-hue {
+background-image: url(../img/hue.png);
+}
+.colorpicker-alpha {
+background-image: url(../img/alpha.png);
+display: none;
+}
+.colorpicker {
+*zoom: 1;
+top: 0;
+left: 0;
+padding: 4px;
+min-width: 120px;
+margin-top: 1px;
+-webkit-border-radius: 4px;
+-moz-border-radius: 4px;
+border-radius: 4px;
+}
+.colorpicker:before, .colorpicker:after {
+display: table;
+content: "";
+}
+.colorpicker:after {
+clear: both;
+}
+.colorpicker:before {
+content: '';
+display: inline-block;
+border-left: 7px solid transparent;
+border-right: 7px solid transparent;
+border-bottom: 7px solid #ccc;
+border-bottom-color: rgba(0, 0, 0, 0.2);
+position: absolute;
+top: -7px;
+left: 6px;
+}
+.colorpicker:after {
+content: '';
+display: inline-block;
+border-left: 6px solid transparent;
+border-right: 6px solid transparent;
+border-bottom: 6px solid #ffffff;
+position: absolute;
+top: -6px;
+left: 7px;
+}
+.colorpicker div {
+position: relative;
+}
+.colorpicker.alpha {
+min-width: 140px;
+}
+.colorpicker.alpha .colorpicker-alpha {
+display: block;
+}
+.colorpicker-color {
+height: 10px;
+margin-top: 5px;
+clear: both;
+background-image: url(../img/alpha.png);
+background-position: 0 100%;
+}
+.colorpicker-color div {
+height: 10px;
+}
+.input-append.color .add-on i, .input-prepend.color .add-on i {
+display: block;
+cursor: pointer;
+width: 16px;
+height: 16px;
+}
\ No newline at end of file
--- /dev/null
+/* =========================================================
+ * bootstrap-colorpicker.js
+ * http://www.eyecon.ro/bootstrap-colorpicker
+ * =========================================================
+ * Copyright 2012 Stefan Petre
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================= */
+
+!function( $ ) {
+
+ // Color object
+
+ var Color = function(val) {
+ this.value = {
+ h: 1,
+ s: 1,
+ b: 1,
+ a: 1
+ };
+ this.setColor(val);
+ };
+
+ Color.prototype = {
+ constructor: Color,
+
+ //parse a string to HSB
+ setColor: function(val){
+ val = val.toLowerCase();
+ var that = this;
+ $.each( CPGlobal.stringParsers, function( i, parser ) {
+ var match = parser.re.exec( val ),
+ values = match && parser.parse( match ),
+ space = parser.space||'rgba';
+ if ( values ) {
+ if (space == 'hsla') {
+ that.value = CPGlobal.RGBtoHSB.apply(null, CPGlobal.HSLtoRGB.apply(null, values));
+ } else {
+ that.value = CPGlobal.RGBtoHSB.apply(null, values);
+ }
+ return false;
+ }
+ });
+ },
+
+ setHue: function(h) {
+ this.value.h = 1- h;
+ },
+
+ setSaturation: function(s) {
+ this.value.s = s;
+ },
+
+ setLightness: function(b) {
+ this.value.b = 1- b;
+ },
+
+ setAlpha: function(a) {
+ this.value.a = parseInt((1 - a)*100, 10)/100;
+ },
+
+ // HSBtoRGB from RaphaelJS
+ // https://github.com/DmitryBaranovskiy/raphael/
+ toRGB: function(h, s, b, a) {
+ if (!h) {
+ h = this.value.h;
+ s = this.value.s;
+ b = this.value.b;
+ }
+ h *= 360;
+ var R, G, B, X, C;
+ h = (h % 360) / 60;
+ C = b * s;
+ X = C * (1 - Math.abs(h % 2 - 1));
+ R = G = B = b - C;
+
+ h = ~~h;
+ R += [C, X, 0, 0, X, C][h];
+ G += [X, C, C, X, 0, 0][h];
+ B += [0, 0, X, C, C, X][h];
+ return {
+ r: Math.round(R*255),
+ g: Math.round(G*255),
+ b: Math.round(B*255),
+ a: a||this.value.a
+ };
+ },
+
+ toHex: function(h, s, b, a){
+ var rgb = this.toRGB(h, s, b, a);
+ return '#'+((1 << 24) | (parseInt(rgb.r) << 16) | (parseInt(rgb.g) << 8) | parseInt(rgb.b)).toString(16).substr(1);
+ },
+
+ toHSL: function(h, s, b, a){
+ if (!h) {
+ h = this.value.h;
+ s = this.value.s;
+ b = this.value.b;
+ }
+ var H = h,
+ L = (2 - s) * b,
+ S = s * b;
+ if (L > 0 && L <= 1) {
+ S /= L;
+ } else {
+ S /= 2 - L;
+ }
+ L /= 2;
+ if (S > 1) {
+ S = 1;
+ }
+ return {
+ h: H,
+ s: S,
+ l: L,
+ a: a||this.value.a
+ };
+ }
+ };
+
+ // Picker object
+
+ var Colorpicker = function(element, options){
+ this.element = $(element);
+ var format = options.format||this.element.data('color-format')||'hex';
+ this.format = CPGlobal.translateFormats[format];
+ this.isInput = this.element.is('input');
+ this.component = this.element.is('.color') ? this.element.find('.add-on') : false;
+
+ this.picker = $(CPGlobal.template)
+ .appendTo('body')
+ .on('mousedown', $.proxy(this.mousedown, this));
+
+ if (this.isInput) {
+ this.element.on({
+ 'focus': $.proxy(this.show, this),
+ 'keyup': $.proxy(this.update, this)
+ });
+ } else if (this.component){
+ this.component.on({
+ 'click': $.proxy(this.show, this)
+ });
+ } else {
+ this.element.on({
+ 'click': $.proxy(this.show, this)
+ });
+ }
+ if (format == 'rgba' || format == 'hsla') {
+ this.picker.addClass('alpha');
+ this.alpha = this.picker.find('.colorpicker-alpha')[0].style;
+ }
+
+ if (this.component){
+ this.picker.find('.colorpicker-color').hide();
+ this.preview = this.element.find('i')[0].style;
+ } else {
+ this.preview = this.picker.find('div:last')[0].style;
+ }
+
+ this.base = this.picker.find('div:first')[0].style;
+ this.update();
+ };
+
+ Colorpicker.prototype = {
+ constructor: Colorpicker,
+
+ show: function(e) {
+ this.picker.show();
+ this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
+ this.place();
+ $(window).on('resize', $.proxy(this.place, this));
+ if (!this.isInput) {
+ if (e) {
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ }
+ $(document).on({
+ 'mousedown': $.proxy(this.hide, this)
+ });
+ this.element.trigger({
+ type: 'show',
+ color: this.color
+ });
+ },
+
+ update: function(){
+ this.color = new Color(this.isInput ? this.element.prop('value') : this.element.data('color'));
+ this.picker.find('i')
+ .eq(0).css({left: this.color.value.s*100, top: 100 - this.color.value.b*100}).end()
+ .eq(1).css('top', 100 * (1 - this.color.value.h)).end()
+ .eq(2).css('top', 100 * (1 - this.color.value.a));
+ this.previewColor();
+ },
+
+ hide: function(){
+ this.picker.hide();
+ $(window).off('resize', this.place);
+ if (!this.isInput) {
+ $(document).off({
+ 'mousedown': this.hide
+ });
+ if (this.component){
+ this.element.find('input').prop('value', this.format.call(this));
+ }
+ this.element.data('color', this.format.call(this));
+ } else {
+ this.element.prop('value', this.format.call(this));
+ }
+ this.element.trigger({
+ type: 'hide',
+ color: this.color
+ });
+ },
+
+ place: function(){
+ var offset = this.component ? this.component.offset() : this.element.offset();
+ this.picker.css({
+ top: offset.top + this.height,
+ left: offset.left
+ });
+ },
+
+ //preview color change
+ previewColor: function(){
+ this.preview.backgroundColor = this.format.call(this);
+ //set the color for brightness/saturation slider
+ this.base.backgroundColor = this.color.toHex(this.color.value.h, 1, 1, 1);
+ //set te color for alpha slider
+ if (this.alpha) {
+ this.alpha.backgroundColor = this.color.toHex();
+ }
+ },
+
+ pointer: null,
+
+ slider: null,
+
+ mousedown: function(e){
+ e.stopPropagation();
+ e.preventDefault();
+
+ var target = $(e.target);
+
+ //detect the slider and set the limits and callbacks
+ var zone = target.closest('div');
+ if (!zone.is('.colorpicker')) {
+ if (zone.is('.colorpicker-saturation')) {
+ this.slider = $.extend({}, CPGlobal.sliders['saturation']);
+ }
+ else if (zone.is('.colorpicker-hue')) {
+ this.slider = $.extend({}, CPGlobal.sliders['hue']);
+ }
+ else if (zone.is('.colorpicker-alpha')) {
+ this.slider = $.extend({}, CPGlobal.sliders['alpha']);
+ }
+ var offset = zone.offset();
+ //reference to knob's style
+ this.slider.knob = zone.find('i')[0].style;
+ this.slider.left = e.pageX - offset.left;
+ this.slider.top = e.pageY - offset.top;
+ this.pointer = {
+ left: e.pageX,
+ top: e.pageY
+ };
+ //trigger mousemove to move the knob to the current position
+ $(document).on({
+ mousemove: $.proxy(this.mousemove, this),
+ mouseup: $.proxy(this.mouseup, this)
+ }).trigger('mousemove');
+ }
+ return false;
+ },
+
+ mousemove: function(e){
+ e.stopPropagation();
+ e.preventDefault();
+ var left = Math.max(
+ 0,
+ Math.min(
+ this.slider.maxLeft,
+ this.slider.left + ((e.pageX||this.pointer.left) - this.pointer.left)
+ )
+ );
+ var top = Math.max(
+ 0,
+ Math.min(
+ this.slider.maxTop,
+ this.slider.top + ((e.pageY||this.pointer.top) - this.pointer.top)
+ )
+ );
+ this.slider.knob.left = left + 'px';
+ this.slider.knob.top = top + 'px';
+ if (this.slider.callLeft) {
+ this.color[this.slider.callLeft].call(this.color, left/100);
+ }
+ if (this.slider.callTop) {
+ this.color[this.slider.callTop].call(this.color, top/100);
+ }
+ this.previewColor();
+ this.element.trigger({
+ type: 'changeColor',
+ color: this.color
+ });
+ return false;
+ },
+
+ mouseup: function(e){
+ e.stopPropagation();
+ e.preventDefault();
+ $(document).off({
+ mousemove: this.mousemove,
+ mouseup: this.mouseup
+ });
+ return false;
+ }
+ }
+
+ $.fn.colorpicker = function ( option ) {
+ return this.each(function () {
+ var $this = $(this),
+ data = $this.data('colorpicker'),
+ options = typeof option == 'object' && option;
+ if (!data) {
+ $this.data('colorpicker', (data = new Colorpicker(this, $.extend({}, $.fn.colorpicker.defaults, options))));
+ }
+ if (typeof option == 'string') data[option]();
+ });
+ };
+
+ $.fn.colorpicker.defaults = {
+ };
+
+ $.fn.colorpicker.Constructor = Colorpicker;
+
+ var CPGlobal = {
+
+ // translate a format from Color object to a string
+ translateFormats: {
+ 'rgb': function(){
+ var rgb = this.color.toRGB();
+ return 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')';
+ },
+
+ 'rgba': function(){
+ var rgb = this.color.toRGB();
+ return 'rgba('+rgb.r+','+rgb.g+','+rgb.b+','+rgb.a+')';
+ },
+
+ 'hsl': function(){
+ var hsl = this.color.toHSL();
+ return 'hsl('+Math.round(hsl.h*360)+','+Math.round(hsl.s*100)+'%,'+Math.round(hsl.l*100)+'%)';
+ },
+
+ 'hsla': function(){
+ var hsl = this.color.toHSL();
+ return 'hsla('+Math.round(hsl.h*360)+','+Math.round(hsl.s*100)+'%,'+Math.round(hsl.l*100)+'%,'+hsl.a+')';
+ },
+
+ 'hex': function(){
+ return this.color.toHex();
+ }
+ },
+
+ sliders: {
+ saturation: {
+ maxLeft: 100,
+ maxTop: 100,
+ callLeft: 'setSaturation',
+ callTop: 'setLightness'
+ },
+
+ hue: {
+ maxLeft: 0,
+ maxTop: 100,
+&n