caboose-cms 0.5.35 → 0.5.36

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YThkN2U0ZjAxNTAzNzQxNjliZmYzNTc1OTEyZTdhNDE4ZTg1M2EzNA==
4
+ YmUzYTcwYWM5NDdiMTRiOTQ1ZjBlNTIwNzMyYzM3NjZiMjBjNGIwNQ==
5
5
  data.tar.gz: !binary |-
6
- NmZiNDU3NTNhYjk0MGFjOTUwZjJkZjQyMGY2OTdkZDRlOGM3NTU0OQ==
6
+ YzlkNGEzZmI3YzBhOWVhYmQyYzcxYjcyNTk3NWI4ZmY2NTcxZjRkMw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MzcxZTVlMWNkZjNkYjUxODU0MTExZmY2NzVmYTJlZmNlNzVhMThhZjdlNmM5
10
- MDFkMzE2YzhiMjI3YTAyNjA2YzhkMWIxMjk5MTM5ZTZkYzc2Y2Q3Yjk3MTMy
11
- YzNmNmJiNzI0NGYwNmVmYzc0YTI5MmU4ZThkNzdhMjJmOWNlNjQ=
9
+ NTg1MTBlYTc4NTlhNGQxZjZjNDBiNzg4NTFhMzhiYTIyNjVlNjRlZjJjZjcz
10
+ YWQzOTE5ZjQyMGI2NzIxMjhlZWYwOTBmY2ZhMzdiYWI0Y2UwOGFhZjExZjM3
11
+ ODQ3ODIzOWYwZTgyYTBiNzJlMjU3ODBjMDRkMjQ0MDM2ZTE2Y2Y=
12
12
  data.tar.gz: !binary |-
13
- ODlhY2U4Yjc4Y2JkN2YyYWQ4OGJlYTg4ODc1NWNhNjc1NGQ0YzBjOWMyYWFj
14
- OTBjNzQxOWE1YjBjNzEyNjUzZmEwNzRiN2EzYzk0NmU5OTQ1MmM2ODYyMGE3
15
- NzBkNTFhNTA0MTg3YWQxYjNjMTRmZjQyM2I5YzY1NGE4NThlN2E=
13
+ ODUyMzM4NmEwODk2OWQ1ODNiOGU2YmJkNTQ0NDVmZTYyNjU2YzRhMzg4ZDY5
14
+ ZmY2YzRhYjA3YjI5MzYzYjQ2OWY3ZWI0ZjAzYjIxNGJkZDZkY2QzZGJlNjEy
15
+ NmExZWM3ZWU4MDZmNGE4ZTAwYWVkZmZiOTY5Y2VlMDI0MDIwOTE=
@@ -1,3 +1,4 @@
1
+ //= require caboose/spectrum
1
2
  //= require caboose/model/class
2
3
  //= require caboose/model/model
3
4
  //= require caboose/model/s3
@@ -5,6 +6,7 @@
5
6
  //= require caboose/model/index_table
6
7
  //= require caboose/model/model_binder
7
8
  //= require caboose/model/bound_control
9
+ //= require caboose/model/bound_color
8
10
  //= require caboose/model/bound_checkbox
9
11
  //= require caboose/model/bound_checkbox_multiple
10
12
  //= require caboose/model/bound_date
@@ -0,0 +1,138 @@
1
+
2
+ BoundColor = BoundControl.extend({
3
+
4
+ //el: false,
5
+ //model: false,
6
+ //attribute: false,
7
+ //binder: false,
8
+
9
+ width: false,
10
+ save_attempts: 0,
11
+
12
+ init: function(params) {
13
+ for (var thing in params)
14
+ this[thing] = params[thing];
15
+
16
+ this.el = this.el ? this.el : this.model.name.toLowerCase() + '_' + this.model.id + '_' + this.attribute.name;
17
+ $('#'+this.el).wrap($('<div/>')
18
+ .attr('id', this.el + '_container')
19
+ .addClass('mb_container')
20
+ .css('position', 'relative')
21
+ );
22
+ $('#'+this.el+'_container').empty().append(
23
+ $('<input/>')
24
+ .attr('id', this.el)
25
+ .attr('type', 'text')
26
+ .attr('placeholder', this.attribute.fixed_placeholder ? 'empty' : this.attribute.nice_name)
27
+ .val(this.attribute.value)
28
+ );
29
+ $('#'+this.el+'_container').css('text-align', 'right');
30
+
31
+ if (this.attribute.fixed_placeholder)
32
+ $('#'+this.el+'_container').append($('<div/>').attr('id', this.el + '_placeholder').addClass('mb_placeholder').append($('<span/>').html(this.attribute.nice_name + ': ')));
33
+ if (this.attribute.width)
34
+ $('#'+this.el+'_container').css('width' , this.attribute.width);
35
+ if (this.attribute.fixed_placeholder && this.attribute.align != 'left')
36
+ {
37
+ var w = $('#'+this.el+'_placeholder').outerWidth(true);
38
+ $('#'+this.el).attr('placeholder', 'empty').css('padding-left', '+=' + w).css('width', '-=' + w);
39
+ }
40
+
41
+ var this2 = this;
42
+ $('#'+this.el).on('keyup', function(e) {
43
+ if (e.keyCode == 27) this2.cancel(); // Escape
44
+ if (e.keyCode == 13) this2.save(); // Enter
45
+
46
+ if ($('#'+this2.el).val() != this2.attribute.value_clean)
47
+ $('#'+this2.el).addClass('mb_dirty');
48
+ else
49
+ $('#'+this2.el).removeClass('mb_dirty');
50
+ });
51
+ $('#'+this.el).on('blur', function() {
52
+ if (this2.save_attempts < 1)
53
+ {
54
+ this2.save_attempts++;
55
+ this2.save();
56
+ }
57
+ });
58
+ $('#'+this.el).css('z-index', 21);
59
+ $('#'+this.el).css('position', 'relative');
60
+ $('#'+this.el).css('background', 'transparent');
61
+ $('#'+this.el).spectrum({
62
+ color: this2.attribute.value,
63
+ showPalette: true,
64
+ showInput: true,
65
+ preferredFormat: 'hex',
66
+ replacerClassName: this2.el + '_bound_color',
67
+ change: function(color) {
68
+ this2.attribute.value = color.toHexString();
69
+ this2.save();
70
+ }
71
+ });
72
+
73
+ $('.' + this.el + '_bound_color').css('text-align', this.attribute.align);
74
+ //if (this.attribute.width) $('.' + this.el + '_bound_color').css('width', this.attribute.width);
75
+ if (this.attribute.fixed_placeholder && this.attribute.align != 'right')
76
+ {
77
+ var w = $('#'+this.el+'_placeholder').outerWidth(true);
78
+ $('.' + this2.el + '_bound_color').css('padding-left', '+=' + w).css('width', '-=' + w);
79
+ }
80
+ if (this.attribute.align == 'right')
81
+ $('.' + this.el + '_bound_color').css('margin', '0 0 0 auto');
82
+ },
83
+
84
+ save: function() {
85
+ //this.attribute.value = $('#'+this.el).val();
86
+ if (this.attribute.value == this.attribute.value_clean)
87
+ return;
88
+
89
+ //this.show_loader();
90
+ var this2 = this;
91
+
92
+ this.model.save(this.attribute, function(resp) {
93
+ this2.save_attempts = 0;
94
+ if (resp.error)
95
+ {
96
+ //this2.hide_loader();
97
+ this2.error(resp.error);
98
+ }
99
+ else
100
+ {
101
+ //this2.show_check(500);
102
+ $('#'+this2.el).val(this2.attribute.value);
103
+ $('#'+this2.el).removeClass('mb_dirty');
104
+
105
+ if (this2.binder.success)
106
+ this2.binder.success(this2);
107
+ }
108
+ });
109
+ },
110
+
111
+ cancel: function() {
112
+ if (this.attribute.before_cancel) this.attribute.before_cancel();
113
+ this.attribute.value = this.attribute.value_clean;
114
+ $('#'+this.el).val(this.attribute.value);
115
+ $('#'+this.el).removeClass('mb_dirty');
116
+
117
+ //if ($('#'+this.el+'_check').length)
118
+ // this.hide_check();
119
+
120
+ if (this.attribute.after_cancel) this.attribute.after_cancel();
121
+ },
122
+
123
+ error: function(str) {
124
+ if (!$('#'+this.el+'_message').length)
125
+ {
126
+ $('#'+this.el+'_container').append($('<div/>')
127
+ .attr('id', this.el + '_message')
128
+ .css('width', $('#'+this.el).outerWidth())
129
+ );
130
+ }
131
+ $('#'+this.el+'_message').hide();
132
+ $('#'+this.el+'_message').html("<p class='note error'>" + str + "</p>");
133
+ $('#'+this.el+'_message').slideDown();
134
+ var this2 = this;
135
+ setTimeout(function() { $('#'+this2.el+'_message').slideUp(function() { $(this).empty(); }); }, 3000);
136
+ }
137
+
138
+ });
@@ -27,16 +27,19 @@ BoundText = BoundControl.extend({
27
27
  .css('text-align', this.attribute.align)
28
28
  .val(this.attribute.value)
29
29
  );
30
-
31
- if (this.attribute.fixed_placeholder)
32
- $('#'+this.el+'_container').append($('<div/>').attr('id', this.el + '_placeholder').addClass('mb_placeholder').append($('<span/>').html(this.attribute.nice_name + ': ')));
33
- if (this.attribute.width) $('#'+this.el).css('width' , this.attribute.width);
30
+
34
31
  if (this.attribute.fixed_placeholder)
32
+ {
33
+ $('#'+this.el+'_container').append($('<div/>').attr('id', this.el + '_placeholder').addClass('mb_placeholder').append($('<span/>').html(this.attribute.nice_name + ': ')));
34
+ $('#'+this.el).css('background', 'transparent');
35
+ }
36
+ if (this.attribute.width) $('#'+this.el).css('width' , this.attribute.width);
37
+ if (this.attribute.fixed_placeholder && this.attribute.align != 'right')
35
38
  {
36
39
  var w = $('#'+this.el+'_placeholder').outerWidth();
37
- $('#'+this.el).attr('placeholder', 'empty').css('padding-left', '+=' + w).css('width', '-=' + w);
40
+ $('#'+this.el).attr('placeholder', 'empty').css('padding-left', '+=' + w).css('width', '-=' + w);
38
41
  }
39
-
42
+
40
43
  var this2 = this;
41
44
  $('#'+this.el).on('keyup', function(e) {
42
45
  if (e.keyCode == 27) this2.cancel(); // Escape
@@ -102,6 +102,7 @@ ModelBinder.prototype = {
102
102
  var control = false;
103
103
 
104
104
  if (attrib.type == 'text') control = new BoundText(opts);
105
+ else if (attrib.type == 'color') control = new BoundColor(opts);
105
106
  else if (attrib.type == 'select') control = new BoundSelect(opts);
106
107
  else if (attrib.type == 'checkbox') control = new BoundCheckbox(opts);
107
108
  else if (attrib.type == 'checkbox-multiple') control = new BoundCheckboxMultiple(opts);
@@ -0,0 +1,2255 @@
1
+ // Spectrum Colorpicker v1.5.1
2
+ // https://github.com/bgrins/spectrum
3
+ // Author: Brian Grinstead
4
+ // License: MIT
5
+
6
+ (function (window, $, undefined) {
7
+ "use strict";
8
+
9
+ var defaultOpts = {
10
+
11
+ // Callbacks
12
+ beforeShow: noop,
13
+ move: noop,
14
+ change: noop,
15
+ show: noop,
16
+ hide: noop,
17
+
18
+ // Options
19
+ color: false,
20
+ flat: false,
21
+ showInput: false,
22
+ allowEmpty: false,
23
+ showButtons: true,
24
+ clickoutFiresChange: false,
25
+ showInitial: false,
26
+ showPalette: false,
27
+ showPaletteOnly: false,
28
+ hideAfterPaletteSelect: false,
29
+ togglePaletteOnly: false,
30
+ showSelectionPalette: true,
31
+ localStorageKey: false,
32
+ appendTo: "body",
33
+ maxSelectionSize: 7,
34
+ cancelText: "cancel",
35
+ chooseText: "choose",
36
+ togglePaletteMoreText: "more",
37
+ togglePaletteLessText: "less",
38
+ clearText: "Clear Color Selection",
39
+ noColorSelectedText: "No Color Selected",
40
+ preferredFormat: false,
41
+ className: "", // Deprecated - use containerClassName and replacerClassName instead.
42
+ containerClassName: "",
43
+ replacerClassName: "",
44
+ showAlpha: false,
45
+ theme: "sp-light",
46
+ palette: [["#ffffff", "#000000", "#ff0000", "#ff8000", "#ffff00", "#008000", "#0000ff", "#4b0082", "#9400d3"]],
47
+ selectionPalette: [],
48
+ disabled: false
49
+ },
50
+ spectrums = [],
51
+ IE = !!/msie/i.exec( window.navigator.userAgent ),
52
+ rgbaSupport = (function() {
53
+ function contains( str, substr ) {
54
+ return !!~('' + str).indexOf(substr);
55
+ }
56
+
57
+ var elem = document.createElement('div');
58
+ var style = elem.style;
59
+ style.cssText = 'background-color:rgba(0,0,0,.5)';
60
+ return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla');
61
+ })(),
62
+ inputTypeColorSupport = (function() {
63
+ var colorInput = $("<input type='color' value='!' />")[0];
64
+ return colorInput.type === "color" && colorInput.value !== "!";
65
+ })(),
66
+ replaceInput = [
67
+ "<div class='sp-replacer'>",
68
+ "<div class='sp-preview'><div class='sp-preview-inner'></div></div>",
69
+ "<div class='sp-dd'>&#9660;</div>",
70
+ "</div>"
71
+ ].join(''),
72
+ markup = (function () {
73
+
74
+ // IE does not support gradients with multiple stops, so we need to simulate
75
+ // that for the rainbow slider with 8 divs that each have a single gradient
76
+ var gradientFix = "";
77
+ if (IE) {
78
+ for (var i = 1; i <= 6; i++) {
79
+ gradientFix += "<div class='sp-" + i + "'></div>";
80
+ }
81
+ }
82
+
83
+ return [
84
+ "<div class='sp-container sp-hidden'>",
85
+ "<div class='sp-palette-container'>",
86
+ "<div class='sp-palette sp-thumb sp-cf'></div>",
87
+ "<div class='sp-palette-button-container sp-cf'>",
88
+ "<button type='button' class='sp-palette-toggle'></button>",
89
+ "</div>",
90
+ "</div>",
91
+ "<div class='sp-picker-container'>",
92
+ "<div class='sp-top sp-cf'>",
93
+ "<div class='sp-fill'></div>",
94
+ "<div class='sp-top-inner'>",
95
+ "<div class='sp-color'>",
96
+ "<div class='sp-sat'>",
97
+ "<div class='sp-val'>",
98
+ "<div class='sp-dragger'></div>",
99
+ "</div>",
100
+ "</div>",
101
+ "</div>",
102
+ "<div class='sp-clear sp-clear-display'>",
103
+ "</div>",
104
+ "<div class='sp-hue'>",
105
+ "<div class='sp-slider'></div>",
106
+ gradientFix,
107
+ "</div>",
108
+ "</div>",
109
+ "<div class='sp-alpha'><div class='sp-alpha-inner'><div class='sp-alpha-handle'></div></div></div>",
110
+ "</div>",
111
+ "<div class='sp-input-container sp-cf'>",
112
+ "<input class='sp-input' type='text' spellcheck='false' />",
113
+ "</div>",
114
+ "<div class='sp-initial sp-thumb sp-cf'></div>",
115
+ "<div class='sp-button-container sp-cf'>",
116
+ "<a class='sp-cancel' href='#'></a>",
117
+ "<button type='button' class='sp-choose'></button>",
118
+ "</div>",
119
+ "</div>",
120
+ "</div>"
121
+ ].join("");
122
+ })();
123
+
124
+ function paletteTemplate (p, color, className, opts) {
125
+ var html = [];
126
+ for (var i = 0; i < p.length; i++) {
127
+ var current = p[i];
128
+ if(current) {
129
+ var tiny = tinycolor(current);
130
+ var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light";
131
+ c += (tinycolor.equals(color, current)) ? " sp-thumb-active" : "";
132
+ var formattedString = tiny.toString(opts.preferredFormat || "rgb");
133
+ var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter();
134
+ html.push('<span title="' + formattedString + '" data-color="' + tiny.toRgbString() + '" class="' + c + '"><span class="sp-thumb-inner" style="' + swatchStyle + ';" /></span>');
135
+ } else {
136
+ var cls = 'sp-clear-display';
137
+ html.push($('<div />')
138
+ .append($('<span data-color="" style="background-color:transparent;" class="' + cls + '"></span>')
139
+ .attr('title', opts.noColorSelectedText)
140
+ )
141
+ .html()
142
+ );
143
+ }
144
+ }
145
+ return "<div class='sp-cf " + className + "'>" + html.join('') + "</div>";
146
+ }
147
+
148
+ function hideAll() {
149
+ for (var i = 0; i < spectrums.length; i++) {
150
+ if (spectrums[i]) {
151
+ spectrums[i].hide();
152
+ }
153
+ }
154
+ }
155
+
156
+ function instanceOptions(o, callbackContext) {
157
+ var opts = $.extend({}, defaultOpts, o);
158
+ opts.callbacks = {
159
+ 'move': bind(opts.move, callbackContext),
160
+ 'change': bind(opts.change, callbackContext),
161
+ 'show': bind(opts.show, callbackContext),
162
+ 'hide': bind(opts.hide, callbackContext),
163
+ 'beforeShow': bind(opts.beforeShow, callbackContext)
164
+ };
165
+
166
+ return opts;
167
+ }
168
+
169
+ function spectrum(element, o) {
170
+
171
+ var opts = instanceOptions(o, element),
172
+ flat = opts.flat,
173
+ showSelectionPalette = opts.showSelectionPalette,
174
+ localStorageKey = opts.localStorageKey,
175
+ theme = opts.theme,
176
+ callbacks = opts.callbacks,
177
+ resize = throttle(reflow, 10),
178
+ visible = false,
179
+ dragWidth = 0,
180
+ dragHeight = 0,
181
+ dragHelperHeight = 0,
182
+ slideHeight = 0,
183
+ slideWidth = 0,
184
+ alphaWidth = 0,
185
+ alphaSlideHelperWidth = 0,
186
+ slideHelperHeight = 0,
187
+ currentHue = 0,
188
+ currentSaturation = 0,
189
+ currentValue = 0,
190
+ currentAlpha = 1,
191
+ palette = [],
192
+ paletteArray = [],
193
+ paletteLookup = {},
194
+ selectionPalette = opts.selectionPalette.slice(0),
195
+ maxSelectionSize = opts.maxSelectionSize,
196
+ draggingClass = "sp-dragging",
197
+ shiftMovementDirection = null;
198
+
199
+ var doc = element.ownerDocument,
200
+ body = doc.body,
201
+ boundElement = $(element),
202
+ disabled = false,
203
+ container = $(markup, doc).addClass(theme),
204
+ pickerContainer = container.find(".sp-picker-container"),
205
+ dragger = container.find(".sp-color"),
206
+ dragHelper = container.find(".sp-dragger"),
207
+ slider = container.find(".sp-hue"),
208
+ slideHelper = container.find(".sp-slider"),
209
+ alphaSliderInner = container.find(".sp-alpha-inner"),
210
+ alphaSlider = container.find(".sp-alpha"),
211
+ alphaSlideHelper = container.find(".sp-alpha-handle"),
212
+ textInput = container.find(".sp-input"),
213
+ paletteContainer = container.find(".sp-palette"),
214
+ initialColorContainer = container.find(".sp-initial"),
215
+ cancelButton = container.find(".sp-cancel"),
216
+ clearButton = container.find(".sp-clear"),
217
+ chooseButton = container.find(".sp-choose"),
218
+ toggleButton = container.find(".sp-palette-toggle"),
219
+ isInput = boundElement.is("input"),
220
+ isInputTypeColor = isInput && inputTypeColorSupport && boundElement.attr("type") === "color",
221
+ shouldReplace = isInput && !flat,
222
+ replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className).addClass(opts.replacerClassName) : $([]),
223
+ offsetElement = (shouldReplace) ? replacer : boundElement,
224
+ previewElement = replacer.find(".sp-preview-inner"),
225
+ initialColor = opts.color || (isInput && boundElement.val()),
226
+ colorOnShow = false,
227
+ preferredFormat = opts.preferredFormat,
228
+ currentPreferredFormat = preferredFormat,
229
+ clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange,
230
+ isEmpty = !initialColor,
231
+ allowEmpty = opts.allowEmpty && !isInputTypeColor;
232
+
233
+ function applyOptions() {
234
+
235
+ if (opts.showPaletteOnly) {
236
+ opts.showPalette = true;
237
+ }
238
+
239
+ toggleButton.text(opts.showPaletteOnly ? opts.togglePaletteMoreText : opts.togglePaletteLessText);
240
+
241
+ if (opts.palette) {
242
+ palette = opts.palette.slice(0);
243
+ paletteArray = $.isArray(palette[0]) ? palette : [palette];
244
+ paletteLookup = {};
245
+ for (var i = 0; i < paletteArray.length; i++) {
246
+ for (var j = 0; j < paletteArray[i].length; j++) {
247
+ var rgb = tinycolor(paletteArray[i][j]).toRgbString();
248
+ paletteLookup[rgb] = true;
249
+ }
250
+ }
251
+ }
252
+
253
+ container.toggleClass("sp-flat", flat);
254
+ container.toggleClass("sp-input-disabled", !opts.showInput);
255
+ container.toggleClass("sp-alpha-enabled", opts.showAlpha);
256
+ container.toggleClass("sp-clear-enabled", allowEmpty);
257
+ container.toggleClass("sp-buttons-disabled", !opts.showButtons);
258
+ container.toggleClass("sp-palette-buttons-disabled", !opts.togglePaletteOnly);
259
+ container.toggleClass("sp-palette-disabled", !opts.showPalette);
260
+ container.toggleClass("sp-palette-only", opts.showPaletteOnly);
261
+ container.toggleClass("sp-initial-disabled", !opts.showInitial);
262
+ container.addClass(opts.className).addClass(opts.containerClassName);
263
+
264
+ reflow();
265
+ }
266
+
267
+ function initialize() {
268
+
269
+ if (IE) {
270
+ container.find("*:not(input)").attr("unselectable", "on");
271
+ }
272
+
273
+ applyOptions();
274
+
275
+ if (shouldReplace) {
276
+ boundElement.after(replacer).hide();
277
+ }
278
+
279
+ if (!allowEmpty) {
280
+ clearButton.hide();
281
+ }
282
+
283
+ if (flat) {
284
+ boundElement.after(container).hide();
285
+ }
286
+ else {
287
+
288
+ var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo);
289
+ if (appendTo.length !== 1) {
290
+ appendTo = $("body");
291
+ }
292
+
293
+ appendTo.append(container);
294
+ }
295
+
296
+ updateSelectionPaletteFromStorage();
297
+
298
+ offsetElement.bind("click.spectrum touchstart.spectrum", function (e) {
299
+ if (!disabled) {
300
+ toggle();
301
+ }
302
+
303
+ e.stopPropagation();
304
+
305
+ if (!$(e.target).is("input")) {
306
+ e.preventDefault();
307
+ }
308
+ });
309
+
310
+ if(boundElement.is(":disabled") || (opts.disabled === true)) {
311
+ disable();
312
+ }
313
+
314
+ // Prevent clicks from bubbling up to document. This would cause it to be hidden.
315
+ container.click(stopPropagation);
316
+
317
+ // Handle user typed input
318
+ textInput.change(setFromTextInput);
319
+ textInput.bind("paste", function () {
320
+ setTimeout(setFromTextInput, 1);
321
+ });
322
+ textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } });
323
+
324
+ cancelButton.text(opts.cancelText);
325
+ cancelButton.bind("click.spectrum", function (e) {
326
+ e.stopPropagation();
327
+ e.preventDefault();
328
+ revert();
329
+ hide();
330
+ });
331
+
332
+ clearButton.attr("title", opts.clearText);
333
+ clearButton.bind("click.spectrum", function (e) {
334
+ e.stopPropagation();
335
+ e.preventDefault();
336
+ isEmpty = true;
337
+ move();
338
+
339
+ if(flat) {
340
+ //for the flat style, this is a change event
341
+ updateOriginalInput(true);
342
+ }
343
+ });
344
+
345
+ chooseButton.text(opts.chooseText);
346
+ chooseButton.bind("click.spectrum", function (e) {
347
+ e.stopPropagation();
348
+ e.preventDefault();
349
+
350
+ if (isValid()) {
351
+ updateOriginalInput(true);
352
+ hide();
353
+ }
354
+ });
355
+
356
+ toggleButton.text(opts.showPaletteOnly ? opts.togglePaletteMoreText : opts.togglePaletteLessText);
357
+ toggleButton.bind("click.spectrum", function (e) {
358
+ e.stopPropagation();
359
+ e.preventDefault();
360
+
361
+ opts.showPaletteOnly = !opts.showPaletteOnly;
362
+
363
+ // To make sure the Picker area is drawn on the right, next to the
364
+ // Palette area (and not below the palette), first move the Palette
365
+ // to the left to make space for the picker, plus 5px extra.
366
+ // The 'applyOptions' function puts the whole container back into place
367
+ // and takes care of the button-text and the sp-palette-only CSS class.
368
+ if (!opts.showPaletteOnly && !flat) {
369
+ container.css('left', '-=' + (pickerContainer.outerWidth(true) + 5));
370
+ }
371
+ applyOptions();
372
+ });
373
+
374
+ draggable(alphaSlider, function (dragX, dragY, e) {
375
+ currentAlpha = (dragX / alphaWidth);
376
+ isEmpty = false;
377
+ if (e.shiftKey) {
378
+ currentAlpha = Math.round(currentAlpha * 10) / 10;
379
+ }
380
+
381
+ move();
382
+ }, dragStart, dragStop);
383
+
384
+ draggable(slider, function (dragX, dragY) {
385
+ currentHue = parseFloat(dragY / slideHeight);
386
+ isEmpty = false;
387
+ if (!opts.showAlpha) {
388
+ currentAlpha = 1;
389
+ }
390
+ move();
391
+ }, dragStart, dragStop);
392
+
393
+ draggable(dragger, function (dragX, dragY, e) {
394
+
395
+ // shift+drag should snap the movement to either the x or y axis.
396
+ if (!e.shiftKey) {
397
+ shiftMovementDirection = null;
398
+ }
399
+ else if (!shiftMovementDirection) {
400
+ var oldDragX = currentSaturation * dragWidth;
401
+ var oldDragY = dragHeight - (currentValue * dragHeight);
402
+ var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY);
403
+
404
+ shiftMovementDirection = furtherFromX ? "x" : "y";
405
+ }
406
+
407
+ var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x";
408
+ var setValue = !shiftMovementDirection || shiftMovementDirection === "y";
409
+
410
+ if (setSaturation) {
411
+ currentSaturation = parseFloat(dragX / dragWidth);
412
+ }
413
+ if (setValue) {
414
+ currentValue = parseFloat((dragHeight - dragY) / dragHeight);
415
+ }
416
+
417
+ isEmpty = false;
418
+ if (!opts.showAlpha) {
419
+ currentAlpha = 1;
420
+ }
421
+
422
+ move();
423
+
424
+ }, dragStart, dragStop);
425
+
426
+ if (!!initialColor) {
427
+ set(initialColor);
428
+
429
+ // In case color was black - update the preview UI and set the format
430
+ // since the set function will not run (default color is black).
431
+ updateUI();
432
+ currentPreferredFormat = preferredFormat || tinycolor(initialColor).format;
433
+
434
+ addColorToSelectionPalette(initialColor);
435
+ }
436
+ else {
437
+ updateUI();
438
+ }
439
+
440
+ if (flat) {
441
+ show();
442
+ }
443
+
444
+ function paletteElementClick(e) {
445
+ if (e.data && e.data.ignore) {
446
+ set($(e.target).closest(".sp-thumb-el").data("color"));
447
+ move();
448
+ }
449
+ else {
450
+ set($(e.target).closest(".sp-thumb-el").data("color"));
451
+ move();
452
+ updateOriginalInput(true);
453
+ if (opts.hideAfterPaletteSelect) {
454
+ hide();
455
+ }
456
+ }
457
+
458
+ return false;
459
+ }
460
+
461
+ var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum";
462
+ paletteContainer.delegate(".sp-thumb-el", paletteEvent, paletteElementClick);
463
+ initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, paletteElementClick);
464
+ }
465
+
466
+ function updateSelectionPaletteFromStorage() {
467
+
468
+ if (localStorageKey && window.localStorage) {
469
+
470
+ // Migrate old palettes over to new format. May want to remove this eventually.
471
+ try {
472
+ var oldPalette = window.localStorage[localStorageKey].split(",#");
473
+ if (oldPalette.length > 1) {
474
+ delete window.localStorage[localStorageKey];
475
+ $.each(oldPalette, function(i, c) {
476
+ addColorToSelectionPalette(c);
477
+ });
478
+ }
479
+ }
480
+ catch(e) { }
481
+
482
+ try {
483
+ selectionPalette = window.localStorage[localStorageKey].split(";");
484
+ }
485
+ catch (e) { }
486
+ }
487
+ }
488
+
489
+ function addColorToSelectionPalette(color) {
490
+ if (showSelectionPalette) {
491
+ var rgb = tinycolor(color).toRgbString();
492
+ if (!paletteLookup[rgb] && $.inArray(rgb, selectionPalette) === -1) {
493
+ selectionPalette.push(rgb);
494
+ while(selectionPalette.length > maxSelectionSize) {
495
+ selectionPalette.shift();
496
+ }
497
+ }
498
+
499
+ if (localStorageKey && window.localStorage) {
500
+ try {
501
+ window.localStorage[localStorageKey] = selectionPalette.join(";");
502
+ }
503
+ catch(e) { }
504
+ }
505
+ }
506
+ }
507
+
508
+ function getUniqueSelectionPalette() {
509
+ var unique = [];
510
+ if (opts.showPalette) {
511
+ for (var i = 0; i < selectionPalette.length; i++) {
512
+ var rgb = tinycolor(selectionPalette[i]).toRgbString();
513
+
514
+ if (!paletteLookup[rgb]) {
515
+ unique.push(selectionPalette[i]);
516
+ }
517
+ }
518
+ }
519
+
520
+ return unique.reverse().slice(0, opts.maxSelectionSize);
521
+ }
522
+
523
+ function drawPalette() {
524
+
525
+ var currentColor = get();
526
+
527
+ var html = $.map(paletteArray, function (palette, i) {
528
+ return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i, opts);
529
+ });
530
+
531
+ updateSelectionPaletteFromStorage();
532
+
533
+ if (selectionPalette) {
534
+ html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection", opts));
535
+ }
536
+
537
+ paletteContainer.html(html.join(""));
538
+ }
539
+
540
+ function drawInitial() {
541
+ if (opts.showInitial) {
542
+ var initial = colorOnShow;
543
+ var current = get();
544
+ initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial", opts));
545
+ }
546
+ }
547
+
548
+ function dragStart() {
549
+ if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) {
550
+ reflow();
551
+ }
552
+ container.addClass(draggingClass);
553
+ shiftMovementDirection = null;
554
+ boundElement.trigger('dragstart.spectrum', [ get() ]);
555
+ }
556
+
557
+ function dragStop() {
558
+ container.removeClass(draggingClass);
559
+ boundElement.trigger('dragstop.spectrum', [ get() ]);
560
+ }
561
+
562
+ function setFromTextInput() {
563
+
564
+ var value = textInput.val();
565
+
566
+ if ((value === null || value === "") && allowEmpty) {
567
+ set(null);
568
+ updateOriginalInput(true);
569
+ }
570
+ else {
571
+ var tiny = tinycolor(value);
572
+ if (tiny.isValid()) {
573
+ set(tiny);
574
+ updateOriginalInput(true);
575
+ }
576
+ else {
577
+ textInput.addClass("sp-validation-error");
578
+ }
579
+ }
580
+ }
581
+
582
+ function toggle() {
583
+ if (visible) {
584
+ hide();
585
+ }
586
+ else {
587
+ show();
588
+ }
589
+ }
590
+
591
+ function show() {
592
+ var event = $.Event('beforeShow.spectrum');
593
+
594
+ if (visible) {
595
+ reflow();
596
+ return;
597
+ }
598
+
599
+ boundElement.trigger(event, [ get() ]);
600
+
601
+ if (callbacks.beforeShow(get()) === false || event.isDefaultPrevented()) {
602
+ return;
603
+ }
604
+
605
+ hideAll();
606
+ visible = true;
607
+
608
+ $(doc).bind("click.spectrum", clickout);
609
+ $(window).bind("resize.spectrum", resize);
610
+ replacer.addClass("sp-active");
611
+ container.removeClass("sp-hidden");
612
+
613
+ reflow();
614
+ updateUI();
615
+
616
+ colorOnShow = get();
617
+
618
+ drawInitial();
619
+ callbacks.show(colorOnShow);
620
+ boundElement.trigger('show.spectrum', [ colorOnShow ]);
621
+ }
622
+
623
+ function clickout(e) {
624
+ // Return on right click.
625
+ if (e && e.type == "click" && e.button == 2) { return; }
626
+
627
+ if (clickoutFiresChange) {
628
+ updateOriginalInput(true);
629
+ }
630
+ else {
631
+ revert();
632
+ }
633
+ hide();
634
+ }
635
+
636
+ function hide() {
637
+ // Return if hiding is unnecessary
638
+ if (!visible || flat) { return; }
639
+ visible = false;
640
+
641
+ $(doc).unbind("click.spectrum", clickout);
642
+ $(window).unbind("resize.spectrum", resize);
643
+
644
+ replacer.removeClass("sp-active");
645
+ container.addClass("sp-hidden");
646
+
647
+ callbacks.hide(get());
648
+ boundElement.trigger('hide.spectrum', [ get() ]);
649
+ }
650
+
651
+ function revert() {
652
+ set(colorOnShow, true);
653
+ }
654
+
655
+ function set(color, ignoreFormatChange) {
656
+ if (tinycolor.equals(color, get())) {
657
+ // Update UI just in case a validation error needs
658
+ // to be cleared.
659
+ updateUI();
660
+ return;
661
+ }
662
+
663
+ var newColor, newHsv;
664
+ if (!color && allowEmpty) {
665
+ isEmpty = true;
666
+ } else {
667
+ isEmpty = false;
668
+ newColor = tinycolor(color);
669
+ newHsv = newColor.toHsv();
670
+
671
+ currentHue = (newHsv.h % 360) / 360;
672
+ currentSaturation = newHsv.s;
673
+ currentValue = newHsv.v;
674
+ currentAlpha = newHsv.a;
675
+ }
676
+ updateUI();
677
+
678
+ if (newColor && newColor.isValid() && !ignoreFormatChange) {
679
+ currentPreferredFormat = preferredFormat || newColor.getFormat();
680
+ }
681
+ }
682
+
683
+ function get(opts) {
684
+ opts = opts || { };
685
+
686
+ if (allowEmpty && isEmpty) {
687
+ return null;
688
+ }
689
+
690
+ return tinycolor.fromRatio({
691
+ h: currentHue,
692
+ s: currentSaturation,
693
+ v: currentValue,
694
+ a: Math.round(currentAlpha * 100) / 100
695
+ }, { format: opts.format || currentPreferredFormat });
696
+ }
697
+
698
+ function isValid() {
699
+ return !textInput.hasClass("sp-validation-error");
700
+ }
701
+
702
+ function move() {
703
+ updateUI();
704
+
705
+ callbacks.move(get());
706
+ boundElement.trigger('move.spectrum', [ get() ]);
707
+ }
708
+
709
+ function updateUI() {
710
+
711
+ textInput.removeClass("sp-validation-error");
712
+
713
+ updateHelperLocations();
714
+
715
+ // Update dragger background color (gradients take care of saturation and value).
716
+ var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 });
717
+ dragger.css("background-color", flatColor.toHexString());
718
+
719
+ // Get a format that alpha will be included in (hex and names ignore alpha)
720
+ var format = currentPreferredFormat;
721
+ if (currentAlpha < 1 && !(currentAlpha === 0 && format === "name")) {
722
+ if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") {
723
+ format = "rgb";
724
+ }
725
+ }
726
+
727
+ var realColor = get({ format: format }),
728
+ displayColor = '';
729
+
730
+ //reset background info for preview element
731
+ previewElement.removeClass("sp-clear-display");
732
+ previewElement.css('background-color', 'transparent');
733
+
734
+ if (!realColor && allowEmpty) {
735
+ // Update the replaced elements background with icon indicating no color selection
736
+ previewElement.addClass("sp-clear-display");
737
+ }
738
+ else {
739
+ var realHex = realColor.toHexString(),
740
+ realRgb = realColor.toRgbString();
741
+
742
+ // Update the replaced elements background color (with actual selected color)
743
+ if (rgbaSupport || realColor.alpha === 1) {
744
+ previewElement.css("background-color", realRgb);
745
+ }
746
+ else {
747
+ previewElement.css("background-color", "transparent");
748
+ previewElement.css("filter", realColor.toFilter());
749
+ }
750
+
751
+ if (opts.showAlpha) {
752
+ var rgb = realColor.toRgb();
753
+ rgb.a = 0;
754
+ var realAlpha = tinycolor(rgb).toRgbString();
755
+ var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")";
756
+
757
+ if (IE) {
758
+ alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex));
759
+ }
760
+ else {
761
+ alphaSliderInner.css("background", "-webkit-" + gradient);
762
+ alphaSliderInner.css("background", "-moz-" + gradient);
763
+ alphaSliderInner.css("background", "-ms-" + gradient);
764
+ // Use current syntax gradient on unprefixed property.
765
+ alphaSliderInner.css("background",
766
+ "linear-gradient(to right, " + realAlpha + ", " + realHex + ")");
767
+ }
768
+ }
769
+
770
+ displayColor = realColor.toString(format);
771
+ }
772
+
773
+ // Update the text entry input as it changes happen
774
+ if (opts.showInput) {
775
+ textInput.val(displayColor);
776
+ }
777
+
778
+ if (opts.showPalette) {
779
+ drawPalette();
780
+ }
781
+
782
+ drawInitial();
783
+ }
784
+
785
+ function updateHelperLocations() {
786
+ var s = currentSaturation;
787
+ var v = currentValue;
788
+
789
+ if(allowEmpty && isEmpty) {
790
+ //if selected color is empty, hide the helpers
791
+ alphaSlideHelper.hide();
792
+ slideHelper.hide();
793
+ dragHelper.hide();
794
+ }
795
+ else {
796
+ //make sure helpers are visible
797
+ alphaSlideHelper.show();
798
+ slideHelper.show();
799
+ dragHelper.show();
800
+
801
+ // Where to show the little circle in that displays your current selected color
802
+ var dragX = s * dragWidth;
803
+ var dragY = dragHeight - (v * dragHeight);
804
+ dragX = Math.max(
805
+ -dragHelperHeight,
806
+ Math.min(dragWidth - dragHelperHeight, dragX - dragHelperHeight)
807
+ );
808
+ dragY = Math.max(
809
+ -dragHelperHeight,
810
+ Math.min(dragHeight - dragHelperHeight, dragY - dragHelperHeight)
811
+ );
812
+ dragHelper.css({
813
+ "top": dragY + "px",
814
+ "left": dragX + "px"
815
+ });
816
+
817
+ var alphaX = currentAlpha * alphaWidth;
818
+ alphaSlideHelper.css({
819
+ "left": (alphaX - (alphaSlideHelperWidth / 2)) + "px"
820
+ });
821
+
822
+ // Where to show the bar that displays your current selected hue
823
+ var slideY = (currentHue) * slideHeight;
824
+ slideHelper.css({
825
+ "top": (slideY - slideHelperHeight) + "px"
826
+ });
827
+ }
828
+ }
829
+
830
+ function updateOriginalInput(fireCallback) {
831
+ var color = get(),
832
+ displayColor = '',
833
+ hasChanged = !tinycolor.equals(color, colorOnShow);
834
+
835
+ if (color) {
836
+ displayColor = color.toString(currentPreferredFormat);
837
+ // Update the selection palette with the current color
838
+ addColorToSelectionPalette(color);
839
+ }
840
+
841
+ if (isInput) {
842
+ boundElement.val(displayColor);
843
+ }
844
+
845
+ if (fireCallback && hasChanged) {
846
+ callbacks.change(color);
847
+ boundElement.trigger('change', [ color ]);
848
+ }
849
+ }
850
+
851
+ function reflow() {
852
+ dragWidth = dragger.width();
853
+ dragHeight = dragger.height();
854
+ dragHelperHeight = dragHelper.height();
855
+ slideWidth = slider.width();
856
+ slideHeight = slider.height();
857
+ slideHelperHeight = slideHelper.height();
858
+ alphaWidth = alphaSlider.width();
859
+ alphaSlideHelperWidth = alphaSlideHelper.width();
860
+
861
+ if (!flat) {
862
+ container.css("position", "absolute");
863
+ container.offset(getOffset(container, offsetElement));
864
+ }
865
+
866
+ updateHelperLocations();
867
+
868
+ if (opts.showPalette) {
869
+ drawPalette();
870
+ }
871
+
872
+ boundElement.trigger('reflow.spectrum');
873
+ }
874
+
875
+ function destroy() {
876
+ boundElement.show();
877
+ offsetElement.unbind("click.spectrum touchstart.spectrum");
878
+ container.remove();
879
+ replacer.remove();
880
+ spectrums[spect.id] = null;
881
+ }
882
+
883
+ function option(optionName, optionValue) {
884
+ if (optionName === undefined) {
885
+ return $.extend({}, opts);
886
+ }
887
+ if (optionValue === undefined) {
888
+ return opts[optionName];
889
+ }
890
+
891
+ opts[optionName] = optionValue;
892
+ applyOptions();
893
+ }
894
+
895
+ function enable() {
896
+ disabled = false;
897
+ boundElement.attr("disabled", false);
898
+ offsetElement.removeClass("sp-disabled");
899
+ }
900
+
901
+ function disable() {
902
+ hide();
903
+ disabled = true;
904
+ boundElement.attr("disabled", true);
905
+ offsetElement.addClass("sp-disabled");
906
+ }
907
+
908
+ initialize();
909
+
910
+ var spect = {
911
+ show: show,
912
+ hide: hide,
913
+ toggle: toggle,
914
+ reflow: reflow,
915
+ option: option,
916
+ enable: enable,
917
+ disable: disable,
918
+ set: function (c) {
919
+ set(c);
920
+ updateOriginalInput();
921
+ },
922
+ get: get,
923
+ destroy: destroy,
924
+ container: container
925
+ };
926
+
927
+ spect.id = spectrums.push(spect) - 1;
928
+
929
+ return spect;
930
+ }
931
+
932
+ /**
933
+ * checkOffset - get the offset below/above and left/right element depending on screen position
934
+ * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js
935
+ */
936
+ function getOffset(picker, input) {
937
+ var extraY = 0;
938
+ var dpWidth = picker.outerWidth();
939
+ var dpHeight = picker.outerHeight();
940
+ var inputHeight = input.outerHeight();
941
+ var doc = picker[0].ownerDocument;
942
+ var docElem = doc.documentElement;
943
+ var viewWidth = docElem.clientWidth + $(doc).scrollLeft();
944
+ var viewHeight = docElem.clientHeight + $(doc).scrollTop();
945
+ var offset = input.offset();
946
+ offset.top += inputHeight;
947
+
948
+ offset.left -=
949
+ Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
950
+ Math.abs(offset.left + dpWidth - viewWidth) : 0);
951
+
952
+ offset.top -=
953
+ Math.min(offset.top, ((offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
954
+ Math.abs(dpHeight + inputHeight - extraY) : extraY));
955
+
956
+ return offset;
957
+ }
958
+
959
+ /**
960
+ * noop - do nothing
961
+ */
962
+ function noop() {
963
+
964
+ }
965
+
966
+ /**
967
+ * stopPropagation - makes the code only doing this a little easier to read in line
968
+ */
969
+ function stopPropagation(e) {
970
+ e.stopPropagation();
971
+ }
972
+
973
+ /**
974
+ * Create a function bound to a given object
975
+ * Thanks to underscore.js
976
+ */
977
+ function bind(func, obj) {
978
+ var slice = Array.prototype.slice;
979
+ var args = slice.call(arguments, 2);
980
+ return function () {
981
+ return func.apply(obj, args.concat(slice.call(arguments)));
982
+ };
983
+ }
984
+
985
+ /**
986
+ * Lightweight drag helper. Handles containment within the element, so that
987
+ * when dragging, the x is within [0,element.width] and y is within [0,element.height]
988
+ */
989
+ function draggable(element, onmove, onstart, onstop) {
990
+ onmove = onmove || function () { };
991
+ onstart = onstart || function () { };
992
+ onstop = onstop || function () { };
993
+ var doc = document;
994
+ var dragging = false;
995
+ var offset = {};
996
+ var maxHeight = 0;
997
+ var maxWidth = 0;
998
+ var hasTouch = ('ontouchstart' in window);
999
+
1000
+ var duringDragEvents = {};
1001
+ duringDragEvents["selectstart"] = prevent;
1002
+ duringDragEvents["dragstart"] = prevent;
1003
+ duringDragEvents["touchmove mousemove"] = move;
1004
+ duringDragEvents["touchend mouseup"] = stop;
1005
+
1006
+ function prevent(e) {
1007
+ if (e.stopPropagation) {
1008
+ e.stopPropagation();
1009
+ }
1010
+ if (e.preventDefault) {
1011
+ e.preventDefault();
1012
+ }
1013
+ e.returnValue = false;
1014
+ }
1015
+
1016
+ function move(e) {
1017
+ if (dragging) {
1018
+ // Mouseup happened outside of window
1019
+ if (IE && doc.documentMode < 9 && !e.button) {
1020
+ return stop();
1021
+ }
1022
+
1023
+ var touches = e.originalEvent.touches;
1024
+ var pageX = touches ? touches[0].pageX : e.pageX;
1025
+ var pageY = touches ? touches[0].pageY : e.pageY;
1026
+
1027
+ var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth));
1028
+ var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight));
1029
+
1030
+ if (hasTouch) {
1031
+ // Stop scrolling in iOS
1032
+ prevent(e);
1033
+ }
1034
+
1035
+ onmove.apply(element, [dragX, dragY, e]);
1036
+ }
1037
+ }
1038
+
1039
+ function start(e) {
1040
+ var rightclick = (e.which) ? (e.which == 3) : (e.button == 2);
1041
+
1042
+ if (!rightclick && !dragging) {
1043
+ if (onstart.apply(element, arguments) !== false) {
1044
+ dragging = true;
1045
+ maxHeight = $(element).height();
1046
+ maxWidth = $(element).width();
1047
+ offset = $(element).offset();
1048
+
1049
+ $(doc).bind(duringDragEvents);
1050
+ $(doc.body).addClass("sp-dragging");
1051
+
1052
+ if (!hasTouch) {
1053
+ move(e);
1054
+ }
1055
+
1056
+ prevent(e);
1057
+ }
1058
+ }
1059
+ }
1060
+
1061
+ function stop() {
1062
+ if (dragging) {
1063
+ $(doc).unbind(duringDragEvents);
1064
+ $(doc.body).removeClass("sp-dragging");
1065
+ onstop.apply(element, arguments);
1066
+ }
1067
+ dragging = false;
1068
+ }
1069
+
1070
+ $(element).bind("touchstart mousedown", start);
1071
+ }
1072
+
1073
+ function throttle(func, wait, debounce) {
1074
+ var timeout;
1075
+ return function () {
1076
+ var context = this, args = arguments;
1077
+ var throttler = function () {
1078
+ timeout = null;
1079
+ func.apply(context, args);
1080
+ };
1081
+ if (debounce) clearTimeout(timeout);
1082
+ if (debounce || !timeout) timeout = setTimeout(throttler, wait);
1083
+ };
1084
+ }
1085
+
1086
+ /**
1087
+ * Define a jQuery plugin
1088
+ */
1089
+ var dataID = "spectrum.id";
1090
+ $.fn.spectrum = function (opts, extra) {
1091
+
1092
+ if (typeof opts == "string") {
1093
+
1094
+ var returnValue = this;
1095
+ var args = Array.prototype.slice.call( arguments, 1 );
1096
+
1097
+ this.each(function () {
1098
+ var spect = spectrums[$(this).data(dataID)];
1099
+ if (spect) {
1100
+ var method = spect[opts];
1101
+ if (!method) {
1102
+ throw new Error( "Spectrum: no such method: '" + opts + "'" );
1103
+ }
1104
+
1105
+ if (opts == "get") {
1106
+ returnValue = spect.get();
1107
+ }
1108
+ else if (opts == "container") {
1109
+ returnValue = spect.container;
1110
+ }
1111
+ else if (opts == "option") {
1112
+ returnValue = spect.option.apply(spect, args);
1113
+ }
1114
+ else if (opts == "destroy") {
1115
+ spect.destroy();
1116
+ $(this).removeData(dataID);
1117
+ }
1118
+ else {
1119
+ method.apply(spect, args);
1120
+ }
1121
+ }
1122
+ });
1123
+
1124
+ return returnValue;
1125
+ }
1126
+
1127
+ // Initializing a new instance of spectrum
1128
+ return this.spectrum("destroy").each(function () {
1129
+ var options = $.extend({}, opts, $(this).data());
1130
+ var spect = spectrum(this, options);
1131
+ $(this).data(dataID, spect.id);
1132
+ });
1133
+ };
1134
+
1135
+ $.fn.spectrum.load = true;
1136
+ $.fn.spectrum.loadOpts = {};
1137
+ $.fn.spectrum.draggable = draggable;
1138
+ $.fn.spectrum.defaults = defaultOpts;
1139
+
1140
+ $.spectrum = { };
1141
+ $.spectrum.localization = { };
1142
+ $.spectrum.palettes = { };
1143
+
1144
+ $.fn.spectrum.processNativeColorInputs = function () {
1145
+ if (!inputTypeColorSupport) {
1146
+ $("input[type=color]").spectrum({
1147
+ preferredFormat: "hex6"
1148
+ });
1149
+ }
1150
+ };
1151
+
1152
+ // TinyColor v1.0.0
1153
+ // https://github.com/bgrins/TinyColor
1154
+ // Brian Grinstead, MIT License
1155
+
1156
+ (function() {
1157
+
1158
+ var trimLeft = /^[\s,#]+/,
1159
+ trimRight = /\s+$/,
1160
+ tinyCounter = 0,
1161
+ math = Math,
1162
+ mathRound = math.round,
1163
+ mathMin = math.min,
1164
+ mathMax = math.max,
1165
+ mathRandom = math.random;
1166
+
1167
+ var tinycolor = function tinycolor (color, opts) {
1168
+
1169
+ color = (color) ? color : '';
1170
+ opts = opts || { };
1171
+
1172
+ // If input is already a tinycolor, return itself
1173
+ if (color instanceof tinycolor) {
1174
+ return color;
1175
+ }
1176
+ // If we are called as a function, call using new instead
1177
+ if (!(this instanceof tinycolor)) {
1178
+ return new tinycolor(color, opts);
1179
+ }
1180
+
1181
+ var rgb = inputToRGB(color);
1182
+ this._r = rgb.r,
1183
+ this._g = rgb.g,
1184
+ this._b = rgb.b,
1185
+ this._a = rgb.a,
1186
+ this._roundA = mathRound(100*this._a) / 100,
1187
+ this._format = opts.format || rgb.format;
1188
+ this._gradientType = opts.gradientType;
1189
+
1190
+ // Don't let the range of [0,255] come back in [0,1].
1191
+ // Potentially lose a little bit of precision here, but will fix issues where
1192
+ // .5 gets interpreted as half of the total, instead of half of 1
1193
+ // If it was supposed to be 128, this was already taken care of by `inputToRgb`
1194
+ if (this._r < 1) { this._r = mathRound(this._r); }
1195
+ if (this._g < 1) { this._g = mathRound(this._g); }
1196
+ if (this._b < 1) { this._b = mathRound(this._b); }
1197
+
1198
+ this._ok = rgb.ok;
1199
+ this._tc_id = tinyCounter++;
1200
+ };
1201
+
1202
+ tinycolor.prototype = {
1203
+ isDark: function() {
1204
+ return this.getBrightness() < 128;
1205
+ },
1206
+ isLight: function() {
1207
+ return !this.isDark();
1208
+ },
1209
+ isValid: function() {
1210
+ return this._ok;
1211
+ },
1212
+ getFormat: function() {
1213
+ return this._format;
1214
+ },
1215
+ getAlpha: function() {
1216
+ return this._a;
1217
+ },
1218
+ getBrightness: function() {
1219
+ var rgb = this.toRgb();
1220
+ return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
1221
+ },
1222
+ setAlpha: function(value) {
1223
+ this._a = boundAlpha(value);
1224
+ this._roundA = mathRound(100*this._a) / 100;
1225
+ return this;
1226
+ },
1227
+ toHsv: function() {
1228
+ var hsv = rgbToHsv(this._r, this._g, this._b);
1229
+ return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a };
1230
+ },
1231
+ toHsvString: function() {
1232
+ var hsv = rgbToHsv(this._r, this._g, this._b);
1233
+ var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100);
1234
+ return (this._a == 1) ?
1235
+ "hsv(" + h + ", " + s + "%, " + v + "%)" :
1236
+ "hsva(" + h + ", " + s + "%, " + v + "%, "+ this._roundA + ")";
1237
+ },
1238
+ toHsl: function() {
1239
+ var hsl = rgbToHsl(this._r, this._g, this._b);
1240
+ return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a };
1241
+ },
1242
+ toHslString: function() {
1243
+ var hsl = rgbToHsl(this._r, this._g, this._b);
1244
+ var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100);
1245
+ return (this._a == 1) ?
1246
+ "hsl(" + h + ", " + s + "%, " + l + "%)" :
1247
+ "hsla(" + h + ", " + s + "%, " + l + "%, "+ this._roundA + ")";
1248
+ },
1249
+ toHex: function(allow3Char) {
1250
+ return rgbToHex(this._r, this._g, this._b, allow3Char);
1251
+ },
1252
+ toHexString: function(allow3Char) {
1253
+ return '#' + this.toHex(allow3Char);
1254
+ },
1255
+ toHex8: function() {
1256
+ return rgbaToHex(this._r, this._g, this._b, this._a);
1257
+ },
1258
+ toHex8String: function() {
1259
+ return '#' + this.toHex8();
1260
+ },
1261
+ toRgb: function() {
1262
+ return { r: mathRound(this._r), g: mathRound(this._g), b: mathRound(this._b), a: this._a };
1263
+ },
1264
+ toRgbString: function() {
1265
+ return (this._a == 1) ?
1266
+ "rgb(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ")" :
1267
+ "rgba(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ", " + this._roundA + ")";
1268
+ },
1269
+ toPercentageRgb: function() {
1270
+ return { r: mathRound(bound01(this._r, 255) * 100) + "%", g: mathRound(bound01(this._g, 255) * 100) + "%", b: mathRound(bound01(this._b, 255) * 100) + "%", a: this._a };
1271
+ },
1272
+ toPercentageRgbString: function() {
1273
+ return (this._a == 1) ?
1274
+ "rgb(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%)" :
1275
+ "rgba(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%, " + this._roundA + ")";
1276
+ },
1277
+ toName: function() {
1278
+ if (this._a === 0) {
1279
+ return "transparent";
1280
+ }
1281
+
1282
+ if (this._a < 1) {
1283
+ return false;
1284
+ }
1285
+
1286
+ return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false;
1287
+ },
1288
+ toFilter: function(secondColor) {
1289
+ var hex8String = '#' + rgbaToHex(this._r, this._g, this._b, this._a);
1290
+ var secondHex8String = hex8String;
1291
+ var gradientType = this._gradientType ? "GradientType = 1, " : "";
1292
+
1293
+ if (secondColor) {
1294
+ var s = tinycolor(secondColor);
1295
+ secondHex8String = s.toHex8String();
1296
+ }
1297
+
1298
+ return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")";
1299
+ },
1300
+ toString: function(format) {
1301
+ var formatSet = !!format;
1302
+ format = format || this._format;
1303
+
1304
+ var formattedString = false;
1305
+ var hasAlpha = this._a < 1 && this._a >= 0;
1306
+ var needsAlphaFormat = !formatSet && hasAlpha && (format === "hex" || format === "hex6" || format === "hex3" || format === "name");
1307
+
1308
+ if (needsAlphaFormat) {
1309
+ // Special case for "transparent", all other non-alpha formats
1310
+ // will return rgba when there is transparency.
1311
+ if (format === "name" && this._a === 0) {
1312
+ return this.toName();
1313
+ }
1314
+ return this.toRgbString();
1315
+ }
1316
+ if (format === "rgb") {
1317
+ formattedString = this.toRgbString();
1318
+ }
1319
+ if (format === "prgb") {
1320
+ formattedString = this.toPercentageRgbString();
1321
+ }
1322
+ if (format === "hex" || format === "hex6") {
1323
+ formattedString = this.toHexString();
1324
+ }
1325
+ if (format === "hex3") {
1326
+ formattedString = this.toHexString(true);
1327
+ }
1328
+ if (format === "hex8") {
1329
+ formattedString = this.toHex8String();
1330
+ }
1331
+ if (format === "name") {
1332
+ formattedString = this.toName();
1333
+ }
1334
+ if (format === "hsl") {
1335
+ formattedString = this.toHslString();
1336
+ }
1337
+ if (format === "hsv") {
1338
+ formattedString = this.toHsvString();
1339
+ }
1340
+
1341
+ return formattedString || this.toHexString();
1342
+ },
1343
+
1344
+ _applyModification: function(fn, args) {
1345
+ var color = fn.apply(null, [this].concat([].slice.call(args)));
1346
+ this._r = color._r;
1347
+ this._g = color._g;
1348
+ this._b = color._b;
1349
+ this.setAlpha(color._a);
1350
+ return this;
1351
+ },
1352
+ lighten: function() {
1353
+ return this._applyModification(lighten, arguments);
1354
+ },
1355
+ brighten: function() {
1356
+ return this._applyModification(brighten, arguments);
1357
+ },
1358
+ darken: function() {
1359
+ return this._applyModification(darken, arguments);
1360
+ },
1361
+ desaturate: function() {
1362
+ return this._applyModification(desaturate, arguments);
1363
+ },
1364
+ saturate: function() {
1365
+ return this._applyModification(saturate, arguments);
1366
+ },
1367
+ greyscale: function() {
1368
+ return this._applyModification(greyscale, arguments);
1369
+ },
1370
+ spin: function() {
1371
+ return this._applyModification(spin, arguments);
1372
+ },
1373
+
1374
+ _applyCombination: function(fn, args) {
1375
+ return fn.apply(null, [this].concat([].slice.call(args)));
1376
+ },
1377
+ analogous: function() {
1378
+ return this._applyCombination(analogous, arguments);
1379
+ },
1380
+ complement: function() {
1381
+ return this._applyCombination(complement, arguments);
1382
+ },
1383
+ monochromatic: function() {
1384
+ return this._applyCombination(monochromatic, arguments);
1385
+ },
1386
+ splitcomplement: function() {
1387
+ return this._applyCombination(splitcomplement, arguments);
1388
+ },
1389
+ triad: function() {
1390
+ return this._applyCombination(triad, arguments);
1391
+ },
1392
+ tetrad: function() {
1393
+ return this._applyCombination(tetrad, arguments);
1394
+ }
1395
+ };
1396
+
1397
+ // If input is an object, force 1 into "1.0" to handle ratios properly
1398
+ // String input requires "1.0" as input, so 1 will be treated as 1
1399
+ tinycolor.fromRatio = function(color, opts) {
1400
+ if (typeof color == "object") {
1401
+ var newColor = {};
1402
+ for (var i in color) {
1403
+ if (color.hasOwnProperty(i)) {
1404
+ if (i === "a") {
1405
+ newColor[i] = color[i];
1406
+ }
1407
+ else {
1408
+ newColor[i] = convertToPercentage(color[i]);
1409
+ }
1410
+ }
1411
+ }
1412
+ color = newColor;
1413
+ }
1414
+
1415
+ return tinycolor(color, opts);
1416
+ };
1417
+
1418
+ // Given a string or object, convert that input to RGB
1419
+ // Possible string inputs:
1420
+ //
1421
+ // "red"
1422
+ // "#f00" or "f00"
1423
+ // "#ff0000" or "ff0000"
1424
+ // "#ff000000" or "ff000000"
1425
+ // "rgb 255 0 0" or "rgb (255, 0, 0)"
1426
+ // "rgb 1.0 0 0" or "rgb (1, 0, 0)"
1427
+ // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1"
1428
+ // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1"
1429
+ // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%"
1430
+ // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1"
1431
+ // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%"
1432
+ //
1433
+ function inputToRGB(color) {
1434
+
1435
+ var rgb = { r: 0, g: 0, b: 0 };
1436
+ var a = 1;
1437
+ var ok = false;
1438
+ var format = false;
1439
+
1440
+ if (typeof color == "string") {
1441
+ color = stringInputToObject(color);
1442
+ }
1443
+
1444
+ if (typeof color == "object") {
1445
+ if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) {
1446
+ rgb = rgbToRgb(color.r, color.g, color.b);
1447
+ ok = true;
1448
+ format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb";
1449
+ }
1450
+ else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) {
1451
+ color.s = convertToPercentage(color.s);
1452
+ color.v = convertToPercentage(color.v);
1453
+ rgb = hsvToRgb(color.h, color.s, color.v);
1454
+ ok = true;
1455
+ format = "hsv";
1456
+ }
1457
+ else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) {
1458
+ color.s = convertToPercentage(color.s);
1459
+ color.l = convertToPercentage(color.l);
1460
+ rgb = hslToRgb(color.h, color.s, color.l);
1461
+ ok = true;
1462
+ format = "hsl";
1463
+ }
1464
+
1465
+ if (color.hasOwnProperty("a")) {
1466
+ a = color.a;
1467
+ }
1468
+ }
1469
+
1470
+ a = boundAlpha(a);
1471
+
1472
+ return {
1473
+ ok: ok,
1474
+ format: color.format || format,
1475
+ r: mathMin(255, mathMax(rgb.r, 0)),
1476
+ g: mathMin(255, mathMax(rgb.g, 0)),
1477
+ b: mathMin(255, mathMax(rgb.b, 0)),
1478
+ a: a
1479
+ };
1480
+ }
1481
+
1482
+
1483
+ // Conversion Functions
1484
+ // --------------------
1485
+
1486
+ // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from:
1487
+ // <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript>
1488
+
1489
+ // `rgbToRgb`
1490
+ // Handle bounds / percentage checking to conform to CSS color spec
1491
+ // <http://www.w3.org/TR/css3-color/>
1492
+ // *Assumes:* r, g, b in [0, 255] or [0, 1]
1493
+ // *Returns:* { r, g, b } in [0, 255]
1494
+ function rgbToRgb(r, g, b){
1495
+ return {
1496
+ r: bound01(r, 255) * 255,
1497
+ g: bound01(g, 255) * 255,
1498
+ b: bound01(b, 255) * 255
1499
+ };
1500
+ }
1501
+
1502
+ // `rgbToHsl`
1503
+ // Converts an RGB color value to HSL.
1504
+ // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]
1505
+ // *Returns:* { h, s, l } in [0,1]
1506
+ function rgbToHsl(r, g, b) {
1507
+
1508
+ r = bound01(r, 255);
1509
+ g = bound01(g, 255);
1510
+ b = bound01(b, 255);
1511
+
1512
+ var max = mathMax(r, g, b), min = mathMin(r, g, b);
1513
+ var h, s, l = (max + min) / 2;
1514
+
1515
+ if(max == min) {
1516
+ h = s = 0; // achromatic
1517
+ }
1518
+ else {
1519
+ var d = max - min;
1520
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
1521
+ switch(max) {
1522
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
1523
+ case g: h = (b - r) / d + 2; break;
1524
+ case b: h = (r - g) / d + 4; break;
1525
+ }
1526
+
1527
+ h /= 6;
1528
+ }
1529
+
1530
+ return { h: h, s: s, l: l };
1531
+ }
1532
+
1533
+ // `hslToRgb`
1534
+ // Converts an HSL color value to RGB.
1535
+ // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]
1536
+ // *Returns:* { r, g, b } in the set [0, 255]
1537
+ function hslToRgb(h, s, l) {
1538
+ var r, g, b;
1539
+
1540
+ h = bound01(h, 360);
1541
+ s = bound01(s, 100);
1542
+ l = bound01(l, 100);
1543
+
1544
+ function hue2rgb(p, q, t) {
1545
+ if(t < 0) t += 1;
1546
+ if(t > 1) t -= 1;
1547
+ if(t < 1/6) return p + (q - p) * 6 * t;
1548
+ if(t < 1/2) return q;
1549
+ if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
1550
+ return p;
1551
+ }
1552
+
1553
+ if(s === 0) {
1554
+ r = g = b = l; // achromatic
1555
+ }
1556
+ else {
1557
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
1558
+ var p = 2 * l - q;
1559
+ r = hue2rgb(p, q, h + 1/3);
1560
+ g = hue2rgb(p, q, h);
1561
+ b = hue2rgb(p, q, h - 1/3);
1562
+ }
1563
+
1564
+ return { r: r * 255, g: g * 255, b: b * 255 };
1565
+ }
1566
+
1567
+ // `rgbToHsv`
1568
+ // Converts an RGB color value to HSV
1569
+ // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
1570
+ // *Returns:* { h, s, v } in [0,1]
1571
+ function rgbToHsv(r, g, b) {
1572
+
1573
+ r = bound01(r, 255);
1574
+ g = bound01(g, 255);
1575
+ b = bound01(b, 255);
1576
+
1577
+ var max = mathMax(r, g, b), min = mathMin(r, g, b);
1578
+ var h, s, v = max;
1579
+
1580
+ var d = max - min;
1581
+ s = max === 0 ? 0 : d / max;
1582
+
1583
+ if(max == min) {
1584
+ h = 0; // achromatic
1585
+ }
1586
+ else {
1587
+ switch(max) {
1588
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
1589
+ case g: h = (b - r) / d + 2; break;
1590
+ case b: h = (r - g) / d + 4; break;
1591
+ }
1592
+ h /= 6;
1593
+ }
1594
+ return { h: h, s: s, v: v };
1595
+ }
1596
+
1597
+ // `hsvToRgb`
1598
+ // Converts an HSV color value to RGB.
1599
+ // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
1600
+ // *Returns:* { r, g, b } in the set [0, 255]
1601
+ function hsvToRgb(h, s, v) {
1602
+
1603
+ h = bound01(h, 360) * 6;
1604
+ s = bound01(s, 100);
1605
+ v = bound01(v, 100);
1606
+
1607
+ var i = math.floor(h),
1608
+ f = h - i,
1609
+ p = v * (1 - s),
1610
+ q = v * (1 - f * s),
1611
+ t = v * (1 - (1 - f) * s),
1612
+ mod = i % 6,
1613
+ r = [v, q, p, p, t, v][mod],
1614
+ g = [t, v, v, q, p, p][mod],
1615
+ b = [p, p, t, v, v, q][mod];
1616
+
1617
+ return { r: r * 255, g: g * 255, b: b * 255 };
1618
+ }
1619
+
1620
+ // `rgbToHex`
1621
+ // Converts an RGB color to hex
1622
+ // Assumes r, g, and b are contained in the set [0, 255]
1623
+ // Returns a 3 or 6 character hex
1624
+ function rgbToHex(r, g, b, allow3Char) {
1625
+
1626
+ var hex = [
1627
+ pad2(mathRound(r).toString(16)),
1628
+ pad2(mathRound(g).toString(16)),
1629
+ pad2(mathRound(b).toString(16))
1630
+ ];
1631
+
1632
+ // Return a 3 character hex if possible
1633
+ if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) {
1634
+ return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
1635
+ }
1636
+
1637
+ return hex.join("");
1638
+ }
1639
+ // `rgbaToHex`
1640
+ // Converts an RGBA color plus alpha transparency to hex
1641
+ // Assumes r, g, b and a are contained in the set [0, 255]
1642
+ // Returns an 8 character hex
1643
+ function rgbaToHex(r, g, b, a) {
1644
+
1645
+ var hex = [
1646
+ pad2(convertDecimalToHex(a)),
1647
+ pad2(mathRound(r).toString(16)),
1648
+ pad2(mathRound(g).toString(16)),
1649
+ pad2(mathRound(b).toString(16))
1650
+ ];
1651
+
1652
+ return hex.join("");
1653
+ }
1654
+
1655
+ // `equals`
1656
+ // Can be called with any tinycolor input
1657
+ tinycolor.equals = function (color1, color2) {
1658
+ if (!color1 || !color2) { return false; }
1659
+ return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString();
1660
+ };
1661
+ tinycolor.random = function() {
1662
+ return tinycolor.fromRatio({
1663
+ r: mathRandom(),
1664
+ g: mathRandom(),
1665
+ b: mathRandom()
1666
+ });
1667
+ };
1668
+
1669
+
1670
+ // Modification Functions
1671
+ // ----------------------
1672
+ // Thanks to less.js for some of the basics here
1673
+ // <https://github.com/cloudhead/less.js/blob/master/lib/less/functions.js>
1674
+
1675
+ function desaturate(color, amount) {
1676
+ amount = (amount === 0) ? 0 : (amount || 10);
1677
+ var hsl = tinycolor(color).toHsl();
1678
+ hsl.s -= amount / 100;
1679
+ hsl.s = clamp01(hsl.s);
1680
+ return tinycolor(hsl);
1681
+ }
1682
+
1683
+ function saturate(color, amount) {
1684
+ amount = (amount === 0) ? 0 : (amount || 10);
1685
+ var hsl = tinycolor(color).toHsl();
1686
+ hsl.s += amount / 100;
1687
+ hsl.s = clamp01(hsl.s);
1688
+ return tinycolor(hsl);
1689
+ }
1690
+
1691
+ function greyscale(color) {
1692
+ return tinycolor(color).desaturate(100);
1693
+ }
1694
+
1695
+ function lighten (color, amount) {
1696
+ amount = (amount === 0) ? 0 : (amount || 10);
1697
+ var hsl = tinycolor(color).toHsl();
1698
+ hsl.l += amount / 100;
1699
+ hsl.l = clamp01(hsl.l);
1700
+ return tinycolor(hsl);
1701
+ }
1702
+
1703
+ function brighten(color, amount) {
1704
+ amount = (amount === 0) ? 0 : (amount || 10);
1705
+ var rgb = tinycolor(color).toRgb();
1706
+ rgb.r = mathMax(0, mathMin(255, rgb.r - mathRound(255 * - (amount / 100))));
1707
+ rgb.g = mathMax(0, mathMin(255, rgb.g - mathRound(255 * - (amount / 100))));
1708
+ rgb.b = mathMax(0, mathMin(255, rgb.b - mathRound(255 * - (amount / 100))));
1709
+ return tinycolor(rgb);
1710
+ }
1711
+
1712
+ function darken (color, amount) {
1713
+ amount = (amount === 0) ? 0 : (amount || 10);
1714
+ var hsl = tinycolor(color).toHsl();
1715
+ hsl.l -= amount / 100;
1716
+ hsl.l = clamp01(hsl.l);
1717
+ return tinycolor(hsl);
1718
+ }
1719
+
1720
+ // Spin takes a positive or negative amount within [-360, 360] indicating the change of hue.
1721
+ // Values outside of this range will be wrapped into this range.
1722
+ function spin(color, amount) {
1723
+ var hsl = tinycolor(color).toHsl();
1724
+ var hue = (mathRound(hsl.h) + amount) % 360;
1725
+ hsl.h = hue < 0 ? 360 + hue : hue;
1726
+ return tinycolor(hsl);
1727
+ }
1728
+
1729
+ // Combination Functions
1730
+ // ---------------------
1731
+ // Thanks to jQuery xColor for some of the ideas behind these
1732
+ // <https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js>
1733
+
1734
+ function complement(color) {
1735
+ var hsl = tinycolor(color).toHsl();
1736
+ hsl.h = (hsl.h + 180) % 360;
1737
+ return tinycolor(hsl);
1738
+ }
1739
+
1740
+ function triad(color) {
1741
+ var hsl = tinycolor(color).toHsl();
1742
+ var h = hsl.h;
1743
+ return [
1744
+ tinycolor(color),
1745
+ tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }),
1746
+ tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l })
1747
+ ];
1748
+ }
1749
+
1750
+ function tetrad(color) {
1751
+ var hsl = tinycolor(color).toHsl();
1752
+ var h = hsl.h;
1753
+ return [
1754
+ tinycolor(color),
1755
+ tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }),
1756
+ tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }),
1757
+ tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l })
1758
+ ];
1759
+ }
1760
+
1761
+ function splitcomplement(color) {
1762
+ var hsl = tinycolor(color).toHsl();
1763
+ var h = hsl.h;
1764
+ return [
1765
+ tinycolor(color),
1766
+ tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}),
1767
+ tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l})
1768
+ ];
1769
+ }
1770
+
1771
+ function analogous(color, results, slices) {
1772
+ results = results || 6;
1773
+ slices = slices || 30;
1774
+
1775
+ var hsl = tinycolor(color).toHsl();
1776
+ var part = 360 / slices;
1777
+ var ret = [tinycolor(color)];
1778
+
1779
+ for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) {
1780
+ hsl.h = (hsl.h + part) % 360;
1781
+ ret.push(tinycolor(hsl));
1782
+ }
1783
+ return ret;
1784
+ }
1785
+
1786
+ function monochromatic(color, results) {
1787
+ results = results || 6;
1788
+ var hsv = tinycolor(color).toHsv();
1789
+ var h = hsv.h, s = hsv.s, v = hsv.v;
1790
+ var ret = [];
1791
+ var modification = 1 / results;
1792
+
1793
+ while (results--) {
1794
+ ret.push(tinycolor({ h: h, s: s, v: v}));
1795
+ v = (v + modification) % 1;
1796
+ }
1797
+
1798
+ return ret;
1799
+ }
1800
+
1801
+ // Utility Functions
1802
+ // ---------------------
1803
+
1804
+ tinycolor.mix = function(color1, color2, amount) {
1805
+ amount = (amount === 0) ? 0 : (amount || 50);
1806
+
1807
+ var rgb1 = tinycolor(color1).toRgb();
1808
+ var rgb2 = tinycolor(color2).toRgb();
1809
+
1810
+ var p = amount / 100;
1811
+ var w = p * 2 - 1;
1812
+ var a = rgb2.a - rgb1.a;
1813
+
1814
+ var w1;
1815
+
1816
+ if (w * a == -1) {
1817
+ w1 = w;
1818
+ } else {
1819
+ w1 = (w + a) / (1 + w * a);
1820
+ }
1821
+
1822
+ w1 = (w1 + 1) / 2;
1823
+
1824
+ var w2 = 1 - w1;
1825
+
1826
+ var rgba = {
1827
+ r: rgb2.r * w1 + rgb1.r * w2,
1828
+ g: rgb2.g * w1 + rgb1.g * w2,
1829
+ b: rgb2.b * w1 + rgb1.b * w2,
1830
+ a: rgb2.a * p + rgb1.a * (1 - p)
1831
+ };
1832
+
1833
+ return tinycolor(rgba);
1834
+ };
1835
+
1836
+
1837
+ // Readability Functions
1838
+ // ---------------------
1839
+ // <http://www.w3.org/TR/AERT#color-contrast>
1840
+
1841
+ // `readability`
1842
+ // Analyze the 2 colors and returns an object with the following properties:
1843
+ // `brightness`: difference in brightness between the two colors
1844
+ // `color`: difference in color/hue between the two colors
1845
+ tinycolor.readability = function(color1, color2) {
1846
+ var c1 = tinycolor(color1);
1847
+ var c2 = tinycolor(color2);
1848
+ var rgb1 = c1.toRgb();
1849
+ var rgb2 = c2.toRgb();
1850
+ var brightnessA = c1.getBrightness();
1851
+ var brightnessB = c2.getBrightness();
1852
+ var colorDiff = (
1853
+ Math.max(rgb1.r, rgb2.r) - Math.min(rgb1.r, rgb2.r) +
1854
+ Math.max(rgb1.g, rgb2.g) - Math.min(rgb1.g, rgb2.g) +
1855
+ Math.max(rgb1.b, rgb2.b) - Math.min(rgb1.b, rgb2.b)
1856
+ );
1857
+
1858
+ return {
1859
+ brightness: Math.abs(brightnessA - brightnessB),
1860
+ color: colorDiff
1861
+ };
1862
+ };
1863
+
1864
+ // `readable`
1865
+ // http://www.w3.org/TR/AERT#color-contrast
1866
+ // Ensure that foreground and background color combinations provide sufficient contrast.
1867
+ // *Example*
1868
+ // tinycolor.isReadable("#000", "#111") => false
1869
+ tinycolor.isReadable = function(color1, color2) {
1870
+ var readability = tinycolor.readability(color1, color2);
1871
+ return readability.brightness > 125 && readability.color > 500;
1872
+ };
1873
+
1874
+ // `mostReadable`
1875
+ // Given a base color and a list of possible foreground or background
1876
+ // colors for that base, returns the most readable color.
1877
+ // *Example*
1878
+ // tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000"
1879
+ tinycolor.mostReadable = function(baseColor, colorList) {
1880
+ var bestColor = null;
1881
+ var bestScore = 0;
1882
+ var bestIsReadable = false;
1883
+ for (var i=0; i < colorList.length; i++) {
1884
+
1885
+ // We normalize both around the "acceptable" breaking point,
1886
+ // but rank brightness constrast higher than hue.
1887
+
1888
+ var readability = tinycolor.readability(baseColor, colorList[i]);
1889
+ var readable = readability.brightness > 125 && readability.color > 500;
1890
+ var score = 3 * (readability.brightness / 125) + (readability.color / 500);
1891
+
1892
+ if ((readable && ! bestIsReadable) ||
1893
+ (readable && bestIsReadable && score > bestScore) ||
1894
+ ((! readable) && (! bestIsReadable) && score > bestScore)) {
1895
+ bestIsReadable = readable;
1896
+ bestScore = score;
1897
+ bestColor = tinycolor(colorList[i]);
1898
+ }
1899
+ }
1900
+ return bestColor;
1901
+ };
1902
+
1903
+
1904
+ // Big List of Colors
1905
+ // ------------------
1906
+ // <http://www.w3.org/TR/css3-color/#svg-color>
1907
+ var names = tinycolor.names = {
1908
+ aliceblue: "f0f8ff",
1909
+ antiquewhite: "faebd7",
1910
+ aqua: "0ff",
1911
+ aquamarine: "7fffd4",
1912
+ azure: "f0ffff",
1913
+ beige: "f5f5dc",
1914
+ bisque: "ffe4c4",
1915
+ black: "000",
1916
+ blanchedalmond: "ffebcd",
1917
+ blue: "00f",
1918
+ blueviolet: "8a2be2",
1919
+ brown: "a52a2a",
1920
+ burlywood: "deb887",
1921
+ burntsienna: "ea7e5d",
1922
+ cadetblue: "5f9ea0",
1923
+ chartreuse: "7fff00",
1924
+ chocolate: "d2691e",
1925
+ coral: "ff7f50",
1926
+ cornflowerblue: "6495ed",
1927
+ cornsilk: "fff8dc",
1928
+ crimson: "dc143c",
1929
+ cyan: "0ff",
1930
+ darkblue: "00008b",
1931
+ darkcyan: "008b8b",
1932
+ darkgoldenrod: "b8860b",
1933
+ darkgray: "a9a9a9",
1934
+ darkgreen: "006400",
1935
+ darkgrey: "a9a9a9",
1936
+ darkkhaki: "bdb76b",
1937
+ darkmagenta: "8b008b",
1938
+ darkolivegreen: "556b2f",
1939
+ darkorange: "ff8c00",
1940
+ darkorchid: "9932cc",
1941
+ darkred: "8b0000",
1942
+ darksalmon: "e9967a",
1943
+ darkseagreen: "8fbc8f",
1944
+ darkslateblue: "483d8b",
1945
+ darkslategray: "2f4f4f",
1946
+ darkslategrey: "2f4f4f",
1947
+ darkturquoise: "00ced1",
1948
+ darkviolet: "9400d3",
1949
+ deeppink: "ff1493",
1950
+ deepskyblue: "00bfff",
1951
+ dimgray: "696969",
1952
+ dimgrey: "696969",
1953
+ dodgerblue: "1e90ff",
1954
+ firebrick: "b22222",
1955
+ floralwhite: "fffaf0",
1956
+ forestgreen: "228b22",
1957
+ fuchsia: "f0f",
1958
+ gainsboro: "dcdcdc",
1959
+ ghostwhite: "f8f8ff",
1960
+ gold: "ffd700",
1961
+ goldenrod: "daa520",
1962
+ gray: "808080",
1963
+ green: "008000",
1964
+ greenyellow: "adff2f",
1965
+ grey: "808080",
1966
+ honeydew: "f0fff0",
1967
+ hotpink: "ff69b4",
1968
+ indianred: "cd5c5c",
1969
+ indigo: "4b0082",
1970
+ ivory: "fffff0",
1971
+ khaki: "f0e68c",
1972
+ lavender: "e6e6fa",
1973
+ lavenderblush: "fff0f5",
1974
+ lawngreen: "7cfc00",
1975
+ lemonchiffon: "fffacd",
1976
+ lightblue: "add8e6",
1977
+ lightcoral: "f08080",
1978
+ lightcyan: "e0ffff",
1979
+ lightgoldenrodyellow: "fafad2",
1980
+ lightgray: "d3d3d3",
1981
+ lightgreen: "90ee90",
1982
+ lightgrey: "d3d3d3",
1983
+ lightpink: "ffb6c1",
1984
+ lightsalmon: "ffa07a",
1985
+ lightseagreen: "20b2aa",
1986
+ lightskyblue: "87cefa",
1987
+ lightslategray: "789",
1988
+ lightslategrey: "789",
1989
+ lightsteelblue: "b0c4de",
1990
+ lightyellow: "ffffe0",
1991
+ lime: "0f0",
1992
+ limegreen: "32cd32",
1993
+ linen: "faf0e6",
1994
+ magenta: "f0f",
1995
+ maroon: "800000",
1996
+ mediumaquamarine: "66cdaa",
1997
+ mediumblue: "0000cd",
1998
+ mediumorchid: "ba55d3",
1999
+ mediumpurple: "9370db",
2000
+ mediumseagreen: "3cb371",
2001
+ mediumslateblue: "7b68ee",
2002
+ mediumspringgreen: "00fa9a",
2003
+ mediumturquoise: "48d1cc",
2004
+ mediumvioletred: "c71585",
2005
+ midnightblue: "191970",
2006
+ mintcream: "f5fffa",
2007
+ mistyrose: "ffe4e1",
2008
+ moccasin: "ffe4b5",
2009
+ navajowhite: "ffdead",
2010
+ navy: "000080",
2011
+ oldlace: "fdf5e6",
2012
+ olive: "808000",
2013
+ olivedrab: "6b8e23",
2014
+ orange: "ffa500",
2015
+ orangered: "ff4500",
2016
+ orchid: "da70d6",
2017
+ palegoldenrod: "eee8aa",
2018
+ palegreen: "98fb98",
2019
+ paleturquoise: "afeeee",
2020
+ palevioletred: "db7093",
2021
+ papayawhip: "ffefd5",
2022
+ peachpuff: "ffdab9",
2023
+ peru: "cd853f",
2024
+ pink: "ffc0cb",
2025
+ plum: "dda0dd",
2026
+ powderblue: "b0e0e6",
2027
+ purple: "800080",
2028
+ red: "f00",
2029
+ rosybrown: "bc8f8f",
2030
+ royalblue: "4169e1",
2031
+ saddlebrown: "8b4513",
2032
+ salmon: "fa8072",
2033
+ sandybrown: "f4a460",
2034
+ seagreen: "2e8b57",
2035
+ seashell: "fff5ee",
2036
+ sienna: "a0522d",
2037
+ silver: "c0c0c0",
2038
+ skyblue: "87ceeb",
2039
+ slateblue: "6a5acd",
2040
+ slategray: "708090",
2041
+ slategrey: "708090",
2042
+ snow: "fffafa",
2043
+ springgreen: "00ff7f",
2044
+ steelblue: "4682b4",
2045
+ tan: "d2b48c",
2046
+ teal: "008080",
2047
+ thistle: "d8bfd8",
2048
+ tomato: "ff6347",
2049
+ turquoise: "40e0d0",
2050
+ violet: "ee82ee",
2051
+ wheat: "f5deb3",
2052
+ white: "fff",
2053
+ whitesmoke: "f5f5f5",
2054
+ yellow: "ff0",
2055
+ yellowgreen: "9acd32"
2056
+ };
2057
+
2058
+ // Make it easy to access colors via `hexNames[hex]`
2059
+ var hexNames = tinycolor.hexNames = flip(names);
2060
+
2061
+
2062
+ // Utilities
2063
+ // ---------
2064
+
2065
+ // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }`
2066
+ function flip(o) {
2067
+ var flipped = { };
2068
+ for (var i in o) {
2069
+ if (o.hasOwnProperty(i)) {
2070
+ flipped[o[i]] = i;
2071
+ }
2072
+ }
2073
+ return flipped;
2074
+ }
2075
+
2076
+ // Return a valid alpha value [0,1] with all invalid values being set to 1
2077
+ function boundAlpha(a) {
2078
+ a = parseFloat(a);
2079
+
2080
+ if (isNaN(a) || a < 0 || a > 1) {
2081
+ a = 1;
2082
+ }
2083
+
2084
+ return a;
2085
+ }
2086
+
2087
+ // Take input from [0, n] and return it as [0, 1]
2088
+ function bound01(n, max) {
2089
+ if (isOnePointZero(n)) { n = "100%"; }
2090
+
2091
+ var processPercent = isPercentage(n);
2092
+ n = mathMin(max, mathMax(0, parseFloat(n)));
2093
+
2094
+ // Automatically convert percentage into number
2095
+ if (processPercent) {
2096
+ n = parseInt(n * max, 10) / 100;
2097
+ }
2098
+
2099
+ // Handle floating point rounding errors
2100
+ if ((math.abs(n - max) < 0.000001)) {
2101
+ return 1;
2102
+ }
2103
+
2104
+ // Convert into [0, 1] range if it isn't already
2105
+ return (n % max) / parseFloat(max);
2106
+ }
2107
+
2108
+ // Force a number between 0 and 1
2109
+ function clamp01(val) {
2110
+ return mathMin(1, mathMax(0, val));
2111
+ }
2112
+
2113
+ // Parse a base-16 hex value into a base-10 integer
2114
+ function parseIntFromHex(val) {
2115
+ return parseInt(val, 16);
2116
+ }
2117
+
2118
+ // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
2119
+ // <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
2120
+ function isOnePointZero(n) {
2121
+ return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1;
2122
+ }
2123
+
2124
+ // Check to see if string passed in is a percentage
2125
+ function isPercentage(n) {
2126
+ return typeof n === "string" && n.indexOf('%') != -1;
2127
+ }
2128
+
2129
+ // Force a hex value to have 2 characters
2130
+ function pad2(c) {
2131
+ return c.length == 1 ? '0' + c : '' + c;
2132
+ }
2133
+
2134
+ // Replace a decimal with it's percentage value
2135
+ function convertToPercentage(n) {
2136
+ if (n <= 1) {
2137
+ n = (n * 100) + "%";
2138
+ }
2139
+
2140
+ return n;
2141
+ }
2142
+
2143
+ // Converts a decimal to a hex value
2144
+ function convertDecimalToHex(d) {
2145
+ return Math.round(parseFloat(d) * 255).toString(16);
2146
+ }
2147
+ // Converts a hex value to a decimal
2148
+ function convertHexToDecimal(h) {
2149
+ return (parseIntFromHex(h) / 255);
2150
+ }
2151
+
2152
+ var matchers = (function() {
2153
+
2154
+ // <http://www.w3.org/TR/css3-values/#integers>
2155
+ var CSS_INTEGER = "[-\\+]?\\d+%?";
2156
+
2157
+ // <http://www.w3.org/TR/css3-values/#number-value>
2158
+ var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?";
2159
+
2160
+ // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome.
2161
+ var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")";
2162
+
2163
+ // Actual matching.
2164
+ // Parentheses and commas are optional, but not required.
2165
+ // Whitespace can take the place of commas or opening paren
2166
+ var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
2167
+ var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
2168
+
2169
+ return {
2170
+ rgb: new RegExp("rgb" + PERMISSIVE_MATCH3),
2171
+ rgba: new RegExp("rgba" + PERMISSIVE_MATCH4),
2172
+ hsl: new RegExp("hsl" + PERMISSIVE_MATCH3),
2173
+ hsla: new RegExp("hsla" + PERMISSIVE_MATCH4),
2174
+ hsv: new RegExp("hsv" + PERMISSIVE_MATCH3),
2175
+ hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
2176
+ hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
2177
+ hex8: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/
2178
+ };
2179
+ })();
2180
+
2181
+ // `stringInputToObject`
2182
+ // Permissive string parsing. Take in a number of formats, and output an object
2183
+ // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}`
2184
+ function stringInputToObject(color) {
2185
+
2186
+ color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase();
2187
+ var named = false;
2188
+ if (names[color]) {
2189
+ color = names[color];
2190
+ named = true;
2191
+ }
2192
+ else if (color == 'transparent') {
2193
+ return { r: 0, g: 0, b: 0, a: 0, format: "name" };
2194
+ }
2195
+
2196
+ // Try to match string input using regular expressions.
2197
+ // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360]
2198
+ // Just return an object and let the conversion functions handle that.
2199
+ // This way the result will be the same whether the tinycolor is initialized with string or object.
2200
+ var match;
2201
+ if ((match = matchers.rgb.exec(color))) {
2202
+ return { r: match[1], g: match[2], b: match[3] };
2203
+ }
2204
+ if ((match = matchers.rgba.exec(color))) {
2205
+ return { r: match[1], g: match[2], b: match[3], a: match[4] };
2206
+ }
2207
+ if ((match = matchers.hsl.exec(color))) {
2208
+ return { h: match[1], s: match[2], l: match[3] };
2209
+ }
2210
+ if ((match = matchers.hsla.exec(color))) {
2211
+ return { h: match[1], s: match[2], l: match[3], a: match[4] };
2212
+ }
2213
+ if ((match = matchers.hsv.exec(color))) {
2214
+ return { h: match[1], s: match[2], v: match[3] };
2215
+ }
2216
+ if ((match = matchers.hex8.exec(color))) {
2217
+ return {
2218
+ a: convertHexToDecimal(match[1]),
2219
+ r: parseIntFromHex(match[2]),
2220
+ g: parseIntFromHex(match[3]),
2221
+ b: parseIntFromHex(match[4]),
2222
+ format: named ? "name" : "hex8"
2223
+ };
2224
+ }
2225
+ if ((match = matchers.hex6.exec(color))) {
2226
+ return {
2227
+ r: parseIntFromHex(match[1]),
2228
+ g: parseIntFromHex(match[2]),
2229
+ b: parseIntFromHex(match[3]),
2230
+ format: named ? "name" : "hex"
2231
+ };
2232
+ }
2233
+ if ((match = matchers.hex3.exec(color))) {
2234
+ return {
2235
+ r: parseIntFromHex(match[1] + '' + match[1]),
2236
+ g: parseIntFromHex(match[2] + '' + match[2]),
2237
+ b: parseIntFromHex(match[3] + '' + match[3]),
2238
+ format: named ? "name" : "hex"
2239
+ };
2240
+ }
2241
+
2242
+ return false;
2243
+ }
2244
+
2245
+ window.tinycolor = tinycolor;
2246
+ })();
2247
+
2248
+
2249
+ $(function () {
2250
+ if ($.fn.spectrum.load) {
2251
+ $.fn.spectrum.processNativeColorInputs();
2252
+ }
2253
+ });
2254
+
2255
+ })(window, jQuery);