2 * Copyright (C) 2011 Brian Grinstead All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * @extends {WebInspector.VBox}
33 WebInspector
.Spectrum = function()
36 * @param {!Element} parentElement
38 function appendSwitcherIcon(parentElement
)
40 var icon
= parentElement
.createSVGChild("svg");
41 icon
.setAttribute("height", 16);
42 icon
.setAttribute("width", 16);
43 var path
= icon
.createSVGChild("path");
44 path
.setAttribute("d", "M5,6 L11,6 L8,2 Z M5,10 L11,10 L8,14 Z");
48 WebInspector
.VBox
.call(this, true);
49 this.registerRequiredCSS("elements/spectrum.css");
50 this.contentElement
.tabIndex
= 0;
52 this._colorElement
= this.contentElement
.createChild("div", "spectrum-color");
53 this._colorDragElement
= this._colorElement
.createChild("div", "spectrum-sat fill").createChild("div", "spectrum-val fill").createChild("div", "spectrum-dragger");
54 var contrastRatioSVG
= this._colorElement
.createSVGChild("svg", "spectrum-contrast-container fill");
55 this._contrastRatioLine
= contrastRatioSVG
.createSVGChild("path", "spectrum-contrast-line");
57 var toolbar
= new WebInspector
.Toolbar(this.contentElement
);
58 toolbar
.element
.classList
.add("spectrum-eye-dropper");
59 this._colorPickerButton
= new WebInspector
.ToolbarButton(WebInspector
.UIString("Toggle color picker"), "eyedropper-toolbar-item");
60 this._colorPickerButton
.setToggled(true);
61 this._colorPickerButton
.addEventListener("click", this._toggleColorPicker
.bind(this, undefined));
62 toolbar
.appendToolbarItem(this._colorPickerButton
);
64 var swatchElement
= this.contentElement
.createChild("span", "swatch");
65 this._swatchInnerElement
= swatchElement
.createChild("span", "swatch-inner");
67 this._hueElement
= this.contentElement
.createChild("div", "spectrum-hue");
68 this._hueSlider
= this._hueElement
.createChild("div", "spectrum-slider");
69 this._alphaElement
= this.contentElement
.createChild("div", "spectrum-alpha");
70 this._alphaElementBackground
= this._alphaElement
.createChild("div", "spectrum-alpha-background");
71 this._alphaSlider
= this._alphaElement
.createChild("div", "spectrum-slider");
73 var displaySwitcher
= this.contentElement
.createChild("div", "spectrum-display-switcher spectrum-switcher");
74 appendSwitcherIcon(displaySwitcher
);
75 displaySwitcher
.addEventListener("click", this._formatViewSwitch
.bind(this));
78 this._displayContainer
= this.contentElement
.createChild("div", "spectrum-text source-code");
79 this._textValues
= [];
80 for (var i
= 0; i
< 4; ++i
) {
81 var inputValue
= this._displayContainer
.createChild("input", "spectrum-text-value");
82 inputValue
.maxLength
= 4;
83 this._textValues
.push(inputValue
);
84 inputValue
.addEventListener("keydown", this._inputChanged
.bind(this), false);
85 inputValue
.addEventListener("input", this._inputChanged
.bind(this), false);
86 inputValue
.addEventListener("mousewheel", this._inputChanged
.bind(this), false);
89 this._textLabels
= this._displayContainer
.createChild("div", "spectrum-text-label");
92 this._hexContainer
= this.contentElement
.createChild("div", "spectrum-text spectrum-text-hex source-code");
93 this._hexValue
= this._hexContainer
.createChild("input", "spectrum-text-value");
94 this._hexValue
.maxLength
= 7;
95 this._hexValue
.addEventListener("keydown", this._inputChanged
.bind(this), false);
96 this._hexValue
.addEventListener("mousewheel", this._inputChanged
.bind(this), false);
98 var label
= this._hexContainer
.createChild("div", "spectrum-text-label");
99 label
.textContent
= "HEX";
101 WebInspector
.installDragHandle(this._hueElement
, dragStart
.bind(this, positionHue
.bind(this)), positionHue
.bind(this), null, "default");
102 WebInspector
.installDragHandle(this._alphaElement
, dragStart
.bind(this, positionAlpha
.bind(this)), positionAlpha
.bind(this), null, "default");
103 WebInspector
.installDragHandle(this._colorElement
, dragStart
.bind(this, positionColor
.bind(this)), positionColor
.bind(this), null, "default");
105 if (Runtime
.experiments
.isEnabled("colorPalettes")) {
106 this.element
.classList
.add("palettes-enabled");
107 /** @type {!Array.<!WebInspector.Spectrum.Palette>} */
109 this._palettePanel
= this._createPalettePanel();
110 this._palettePanelShowing
= false;
111 this._paletteContainer
= this.contentElement
.createChild("div", "spectrum-palette");
112 var paletteSwitcher
= this.contentElement
.createChild("div", "spectrum-palette-switcher spectrum-switcher");
113 appendSwitcherIcon(paletteSwitcher
);
114 paletteSwitcher
.addEventListener("click", this._togglePalettePanel
.bind(this, true));
115 new WebInspector
.Spectrum
.PaletteGenerator(this._generatedPaletteLoaded
.bind(this));
119 * @param {function(!Event)} callback
120 * @param {!Event} event
122 * @this {WebInspector.Spectrum}
124 function dragStart(callback
, event
)
126 this._hueAlphaLeft
= this._hueElement
.totalOffsetLeft();
127 this._colorOffset
= this._colorElement
.totalOffset();
133 * @param {!Event} event
134 * @this {WebInspector.Spectrum}
136 function positionHue(event
)
138 var hsva
= this._hsv
.slice();
139 hsva
[0] = Number
.constrain(1 - (event
.x
- this._hueAlphaLeft
) / this._hueAlphaWidth
, 0, 1);
140 this._innerSetColor(hsva
, "", undefined, WebInspector
.Spectrum
._ChangeSource
.Other
);
144 * @param {!Event} event
145 * @this {WebInspector.Spectrum}
147 function positionAlpha(event
)
149 var newAlpha
= Math
.round((event
.x
- this._hueAlphaLeft
) / this._hueAlphaWidth
* 100) / 100;
150 var hsva
= this._hsv
.slice();
151 hsva
[3] = Number
.constrain(newAlpha
, 0, 1);
152 var colorFormat
= undefined;
153 if (this._color().hasAlpha() && (this._colorFormat
=== WebInspector
.Color
.Format
.ShortHEX
|| this._colorFormat
=== WebInspector
.Color
.Format
.HEX
|| this._colorFormat
=== WebInspector
.Color
.Format
.Nickname
))
154 colorFormat
= WebInspector
.Color
.Format
.RGB
;
155 this._innerSetColor(hsva
, "", colorFormat
, WebInspector
.Spectrum
._ChangeSource
.Other
);
159 * @param {!Event} event
160 * @this {WebInspector.Spectrum}
162 function positionColor(event
)
164 var hsva
= this._hsv
.slice();
165 hsva
[1] = Number
.constrain((event
.x
- this._colorOffset
.left
) / this.dragWidth
, 0, 1);
166 hsva
[2] = Number
.constrain(1 - (event
.y
- this._colorOffset
.top
) / this.dragHeight
, 0, 1);
167 this._innerSetColor(hsva
, "", undefined, WebInspector
.Spectrum
._ChangeSource
.Other
);
171 WebInspector
.Spectrum
._ChangeSource
= {
177 WebInspector
.Spectrum
.Events
= {
178 ColorChanged
: "ColorChanged",
179 SizeChanged
: "SizeChanged"
182 WebInspector
.Spectrum
.prototype = {
186 _createPalettePanel: function()
188 var panel
= this.contentElement
.createChild("div", "palette-panel");
189 var title
= panel
.createChild("div", "palette-title");
190 title
.textContent
= WebInspector
.UIString("Color Palettes");
191 var toolbar
= new WebInspector
.Toolbar(panel
);
192 var closeButton
= new WebInspector
.ToolbarButton("Return to color picker", "delete-toolbar-item");
193 closeButton
.addEventListener("click", this._togglePalettePanel
.bind(this, false));
194 toolbar
.appendToolbarItem(closeButton
);
199 * @param {boolean} show
201 _togglePalettePanel: function(show
)
203 if (this._palettePanelShowing
=== show
)
205 this._palettePanelShowing
= show
;
206 this._palettePanel
.classList
.toggle("palette-panel-showing", show
);
210 * @param {string} colorText
211 * @param {number=} animationDelay
214 _createPaletteColor: function(colorText
, animationDelay
)
216 var element
= createElementWithClass("div", "spectrum-palette-color");
217 element
.style
.background
= String
.sprintf("linear-gradient(%s, %s), url(Images/checker.png)", colorText
, colorText
);
219 element
.animate([{ opacity
: 0 }, { opacity
: 1 }], { duration
: 100, delay
: animationDelay
, fill
: "backwards" });
220 WebInspector
.Tooltip
.install(element
, colorText
);
225 * @param {!WebInspector.Spectrum.Palette} palette
226 * @param {!Event=} event
228 _showPalette: function(palette
, event
)
230 this._paletteContainer
.removeChildren();
231 for (var i
= 0; i
< palette
.colors
.length
; i
++) {
232 var colorElement
= this._createPaletteColor(palette
.colors
[i
], i
* 100 / palette
.colors
.length
);
233 colorElement
.addEventListener("click", this._paletteColorSelected
.bind(this, palette
.colors
[i
]));
234 colorElement
.addEventListener("mouseover", this._liveApplyStart
.bind(this, palette
.colors
[i
]));
235 colorElement
.addEventListener("mouseout", this._liveApplyEnd
.bind(this));
236 this._paletteContainer
.appendChild(colorElement
);
238 this._togglePalettePanel(false);
240 var rowsNeeded
= Math
.max(1, Math
.ceil(palette
.colors
.length
/ 8));
241 var paletteColorHeight
= 12;
242 var paletteMargin
= 12;
243 this.element
.style
.height
= (this._paletteContainer
.offsetTop
+ paletteMargin
+ (paletteColorHeight
+ paletteMargin
) * rowsNeeded
) + "px";
244 this.dispatchEventToListeners(WebInspector
.Spectrum
.Events
.SizeChanged
);
248 * @param {string} colorText
250 _liveApplyStart: function(colorText
)
252 this._underlyingHSV
= this._hsv
;
253 this._underlyingFormat
= this._colorFormat
;
254 this._underlyingColorString
= this._colorString
;
255 var color
= WebInspector
.Color
.parse(colorText
);
258 this._innerSetColor(color
.hsva(), colorText
, color
.format(), WebInspector
.Spectrum
._ChangeSource
.Other
);
261 _liveApplyEnd: function()
263 if (!this._underlyingHSV
)
265 this._innerSetColor(this._underlyingHSV
, this._underlyingColorString
, this._underlyingFormat
, WebInspector
.Spectrum
._ChangeSource
.Other
);
266 delete this._underlyingHSV
;
267 delete this._underlyingFormat
;
268 delete this._underlyingColorString
;
272 * @param {!WebInspector.Spectrum.Palette} generatedPalette
274 _generatedPaletteLoaded: function(generatedPalette
)
276 this._palettes
.push(generatedPalette
);
277 this._palettes
.push(WebInspector
.Spectrum
.MaterialPalette
);
278 // TODO(samli): Load custom palettes.
279 for (var palette
of this._palettes
)
280 this._palettePanel
.appendChild(this._createPreviewPaletteElement(palette
));
281 this._showPalette(this._palettes
[0].colors
.length
? this._palettes
[0] : this._palettes
[1]);
285 * @param {!WebInspector.Spectrum.Palette} palette
288 _createPreviewPaletteElement: function(palette
)
290 var colorsPerPreviewRow
= 6;
291 var previewElement
= createElementWithClass("div", "palette-preview");
292 var titleElement
= previewElement
.createChild("div", "palette-preview-title");
293 titleElement
.textContent
= palette
.title
;
294 for (var i
= 0; i
< colorsPerPreviewRow
&& i
< palette
.colors
.length
; i
++)
295 previewElement
.appendChild(this._createPaletteColor(palette
.colors
[i
]));
296 previewElement
.addEventListener("click", this._showPalette
.bind(this, palette
));
297 return previewElement
;
301 * @param {string} colorText
303 _paletteColorSelected: function(colorText
)
305 var color
= WebInspector
.Color
.parse(colorText
);
308 this._innerSetColor(color
.hsva(), colorText
, color
.format(), WebInspector
.Spectrum
._ChangeSource
.Other
);
309 delete this._underlyingHSV
;
313 * @param {!WebInspector.Color} color
314 * @param {string} colorFormat
316 setColor: function(color
, colorFormat
)
318 this._originalFormat
= colorFormat
;
319 this._innerSetColor(color
.hsva(), "", colorFormat
, WebInspector
.Spectrum
._ChangeSource
.Model
);
323 * @param {!Array<number>|undefined} hsva
324 * @param {string|undefined} colorString
325 * @param {string|undefined} colorFormat
326 * @param {string} changeSource
328 _innerSetColor: function(hsva
, colorString
, colorFormat
, changeSource
)
330 if (hsva
!== undefined)
332 if (colorString
!== undefined)
333 this._colorString
= colorString
;
334 if (colorFormat
!== undefined) {
335 console
.assert(colorFormat
!== WebInspector
.Color
.Format
.Original
, "Spectrum's color format cannot be Original");
336 if (colorFormat
=== WebInspector
.Color
.Format
.RGBA
)
337 colorFormat
= WebInspector
.Color
.Format
.RGB
;
338 else if (colorFormat
=== WebInspector
.Color
.Format
.HSLA
)
339 colorFormat
= WebInspector
.Color
.Format
.HSL
;
340 this._colorFormat
= colorFormat
;
343 this._updateHelperLocations();
346 if (changeSource
!== WebInspector
.Spectrum
._ChangeSource
.Input
)
348 if (changeSource
!== WebInspector
.Spectrum
._ChangeSource
.Model
)
349 this.dispatchEventToListeners(WebInspector
.Spectrum
.Events
.ColorChanged
, this.colorString());
353 * @param {!WebInspector.Color} color
355 setContrastColor: function(color
)
357 this._contrastColor
= color
;
362 * @return {!WebInspector.Color}
366 return WebInspector
.Color
.fromHSVA(this._hsv
);
372 colorString: function()
374 if (this._colorString
)
375 return this._colorString
;
376 var cf
= WebInspector
.Color
.Format
;
377 var color
= this._color();
378 var colorString
= color
.asString(this._colorFormat
);
382 if (this._colorFormat
=== cf
.Nickname
|| this._colorFormat
=== cf
.ShortHEX
) {
383 colorString
= color
.asString(cf
.HEX
);
388 console
.assert(color
.hasAlpha());
389 return this._colorFormat
=== cf
.HSL
? /** @type {string} */(color
.asString(cf
.HSLA
)) : /** @type {string} */(color
.asString(cf
.RGBA
));
392 _updateHelperLocations: function()
394 var h
= this._hsv
[0];
395 var s
= this._hsv
[1];
396 var v
= this._hsv
[2];
397 var alpha
= this._hsv
[3];
399 // Where to show the little circle that displays your current selected color.
400 var dragX
= s
* this.dragWidth
;
401 var dragY
= this.dragHeight
- (v
* this.dragHeight
);
403 dragX
= Math
.max(-this._colorDragElementHeight
,
404 Math
.min(this.dragWidth
- this._colorDragElementHeight
, dragX
- this._colorDragElementHeight
));
405 dragY
= Math
.max(-this._colorDragElementHeight
,
406 Math
.min(this.dragHeight
- this._colorDragElementHeight
, dragY
- this._colorDragElementHeight
));
408 this._colorDragElement
.positionAt(dragX
, dragY
);
410 // Where to show the bar that displays your current selected hue.
411 var hueSlideX
= (1 - h
) * this._hueAlphaWidth
- this.slideHelperWidth
;
412 this._hueSlider
.style
.left
= hueSlideX
+ "px";
413 var alphaSlideX
= alpha
* this._hueAlphaWidth
- this.slideHelperWidth
;
414 this._alphaSlider
.style
.left
= alphaSlideX
+ "px";
417 _updateInput: function()
419 var cf
= WebInspector
.Color
.Format
;
420 if (this._colorFormat
=== cf
.HEX
|| this._colorFormat
=== cf
.ShortHEX
|| this._colorFormat
=== cf
.Nickname
) {
421 this._hexContainer
.hidden
= false;
422 this._displayContainer
.hidden
= true;
423 if (this._colorFormat
=== cf
.ShortHEX
&& this._color().canBeShortHex())
424 this._hexValue
.value
= this._color().asString(cf
.ShortHEX
);
426 this._hexValue
.value
= this._color().asString(cf
.HEX
);
428 // RGBA, HSLA display.
429 this._hexContainer
.hidden
= true;
430 this._displayContainer
.hidden
= false;
431 var isRgb
= this._colorFormat
=== cf
.RGB
;
432 this._textLabels
.textContent
= isRgb
? "RGBA" : "HSLA";
433 var colorValues
= isRgb
? this._color().canonicalRGBA() : this._color().canonicalHSLA();
434 for (var i
= 0; i
< 3; ++i
) {
435 this._textValues
[i
].value
= colorValues
[i
];
436 if (!isRgb
&& (i
=== 1 || i
=== 2))
437 this._textValues
[i
].value
+= "%";
439 this._textValues
[3].value
= Math
.round(colorValues
[3] * 100) / 100;
444 * @param {number} requiredContrast
446 _drawContrastRatioLine: function(requiredContrast
)
448 if (!this._contrastColor
|| !this.dragWidth
|| !this.dragHeight
)
451 /** const */ var width
= this.dragWidth
;
452 /** const */ var height
= this.dragHeight
;
453 /** const */ var dS
= 0.02;
454 /** const */ var epsilon
= 0.01;
457 WebInspector
.Color
.hsva2rgba(this._hsv
, fgRGBA
);
458 var fgLuminance
= WebInspector
.Color
.luminance(fgRGBA
);
459 var bgRGBA
= this._contrastColor
.rgba();
460 var bgLuminance
= WebInspector
.Color
.luminance(bgRGBA
);
461 var delta
= fgLuminance
< bgLuminance
? 1 : -1;
463 var lastV
= this._hsv
[2];
464 var currentSlope
= 0;
465 var candidateHSVA
= [this._hsv
[0], 0, 0, this._hsv
[3]];
466 var pathBuilder
= [];
467 var candidateRGBA
= [];
468 WebInspector
.Color
.hsva2rgba(candidateHSVA
, candidateRGBA
);
469 var flattenedRGBA
= [];
470 WebInspector
.Color
.flattenColors(candidateRGBA
, bgRGBA
, flattenedRGBA
);
473 * Approach the desired contrast ratio by modifying the given component
474 * from the given starting value.
475 * @param {number} index
479 function approach(index
, x
)
481 while (0 <= x
&& x
<= 1) {
482 candidateHSVA
[index
] = x
;
483 WebInspector
.Color
.hsva2rgba(candidateHSVA
, candidateRGBA
);
484 WebInspector
.Color
.flattenColors(candidateRGBA
, bgRGBA
, flattenedRGBA
);
485 var contrast
= WebInspector
.Color
.calculateContrastRatio(flattenedRGBA
, bgRGBA
);
486 var dContrast
= contrast
- requiredContrast
;
487 if (Math
.abs(dContrast
) < epsilon
) {
490 // 21 is the maximum possible value for contrast ratio:
491 // http://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html#contrast-ratiodef
492 x
+= delta
* (dContrast
/ 21);
498 for (var s
= 0; s
< 1 + dS
; s
+= dS
) {
500 candidateHSVA
[1] = s
;
502 v
= lastV
+ currentSlope
* dS
;
508 currentSlope
= (v
- lastV
) / dS
;
510 pathBuilder
.push(pathBuilder
.length
? "L" : "M");
511 pathBuilder
.push(s
* width
);
512 pathBuilder
.push((1 - v
) * height
);
518 candidateHSVA
[2] = 1;
521 pathBuilder
= pathBuilder
.concat(["L", s
* width
, 0])
524 this._contrastRatioLine
.setAttribute("d", pathBuilder
.join(" "));
527 _updateUI: function()
529 var h
= WebInspector
.Color
.fromHSVA([this._hsv
[0], 1, 1, 1]);
530 this._colorElement
.style
.backgroundColor
= /** @type {string} */ (h
.asString(WebInspector
.Color
.Format
.RGB
));
531 if (Runtime
.experiments
.isEnabled("colorContrastRatio")) {
532 // TODO(samli): Determine size of text and switch between AA/AAA ratings.
533 this._drawContrastRatioLine(4.5);
535 this._swatchInnerElement
.style
.backgroundColor
= /** @type {string} */ (this._color().asString(WebInspector
.Color
.Format
.RGBA
));
536 // Show border if the swatch is white.
537 this._swatchInnerElement
.classList
.toggle("swatch-inner-white", this._color().hsla()[2] > 0.9);
538 this._colorDragElement
.style
.backgroundColor
= /** @type {string} */ (this._color().asString(WebInspector
.Color
.Format
.RGBA
));
539 var noAlpha
= WebInspector
.Color
.fromHSVA(this._hsv
.slice(0,3).concat(1));
540 this._alphaElementBackground
.style
.backgroundImage
= String
.sprintf("linear-gradient(to right, rgba(0,0,0,0), %s)", noAlpha
.asString(WebInspector
.Color
.Format
.RGB
));
543 _formatViewSwitch: function()
545 var cf
= WebInspector
.Color
.Format
;
547 if (this._colorFormat
=== cf
.RGB
)
549 else if (this._colorFormat
=== cf
.HSL
&& !this._color().hasAlpha())
550 format
= this._originalFormat
=== cf
.ShortHEX
? cf
.ShortHEX
: cf
.HEX
;
551 this._innerSetColor(undefined, "", format
, WebInspector
.Spectrum
._ChangeSource
.Other
);
555 * @param {!Event} event
557 _inputChanged: function(event
)
560 * @param {!Element} element
563 function elementValue(element
)
565 return element
.value
;
568 var inputElement
= /** @type {!Element} */(event
.currentTarget
);
569 var arrowKeyOrMouseWheelEvent
= (event
.keyIdentifier
=== "Up" || event
.keyIdentifier
=== "Down" || event
.type
=== "mousewheel");
570 var pageKeyPressed
= (event
.keyIdentifier
=== "PageUp" || event
.keyIdentifier
=== "PageDown");
571 if (arrowKeyOrMouseWheelEvent
|| pageKeyPressed
) {
572 var newValue
= WebInspector
.createReplacementString(inputElement
.value
, event
);
574 inputElement
.value
= newValue
;
575 inputElement
.selectionStart
= 0;
576 inputElement
.selectionEnd
= newValue
.length
;
581 const cf
= WebInspector
.Color
.Format
;
583 if (this._colorFormat
=== cf
.HEX
|| this._colorFormat
=== cf
.ShortHEX
) {
584 colorString
= this._hexValue
.value
;
586 var format
= this._colorFormat
=== cf
.RGB
? "rgba" : "hsla";
587 var values
= this._textValues
.map(elementValue
).join(",");
588 colorString
= String
.sprintf("%s(%s)", format
, values
);
591 var color
= WebInspector
.Color
.parse(colorString
);
594 var hsv
= color
.hsva();
595 if (this._colorFormat
=== cf
.HEX
|| this._colorFormat
=== cf
.ShortHEX
)
596 this._colorFormat
= color
.canBeShortHex() ? cf
.ShortHEX
: cf
.HEX
;
597 this._innerSetColor(hsv
, colorString
, undefined, WebInspector
.Spectrum
._ChangeSource
.Input
);
602 this._hueAlphaWidth
= this._hueElement
.offsetWidth
;
603 this.slideHelperWidth
= this._hueSlider
.offsetWidth
/ 2;
604 this.dragWidth
= this._colorElement
.offsetWidth
;
605 this.dragHeight
= this._colorElement
.offsetHeight
;
606 this._colorDragElementHeight
= this._colorDragElement
.offsetHeight
/ 2;
607 this._innerSetColor(undefined, undefined, undefined, WebInspector
.Spectrum
._ChangeSource
.Model
);
608 this._toggleColorPicker(true);
609 WebInspector
.targetManager
.addModelListener(WebInspector
.ResourceTreeModel
, WebInspector
.ResourceTreeModel
.EventTypes
.ColorPicked
, this._colorPicked
, this);
614 this._toggleColorPicker(false);
615 WebInspector
.targetManager
.removeModelListener(WebInspector
.ResourceTreeModel
, WebInspector
.ResourceTreeModel
.EventTypes
.ColorPicked
, this._colorPicked
, this);
619 * @param {boolean=} enabled
620 * @param {!WebInspector.Event=} event
622 _toggleColorPicker: function(enabled
, event
)
624 if (enabled
=== undefined)
625 enabled
= !this._colorPickerButton
.toggled();
626 this._colorPickerButton
.setToggled(enabled
);
627 for (var target
of WebInspector
.targetManager
.targets())
628 target
.pageAgent().setColorPickerEnabled(enabled
);
632 * @param {!WebInspector.Event} event
634 _colorPicked: function(event
)
636 var rgbColor
= /** @type {!DOMAgent.RGBA} */ (event
.data
);
637 var rgba
= [rgbColor
.r
, rgbColor
.g
, rgbColor
.b
, (rgbColor
.a
/ 2.55 | 0) / 100];
638 var color
= WebInspector
.Color
.fromRGBA(rgba
);
639 this._innerSetColor(color
.hsva(), "", undefined, WebInspector
.Spectrum
._ChangeSource
.Other
);
640 InspectorFrontendHost
.bringToFront();
644 __proto__
: WebInspector
.VBox
.prototype
647 /** @typedef {{ title: string, colors: !Array.<string> }} */
648 WebInspector
.Spectrum
.Palette
;
652 * @param {function(!WebInspector.Spectrum.Palette)} callback
654 WebInspector
.Spectrum
.PaletteGenerator = function(callback
)
656 this._callback
= callback
;
657 var target
= WebInspector
.targetManager
.mainTarget();
660 var cssModel
= WebInspector
.CSSStyleModel
.fromTarget(target
);
661 /** @type {!Map.<string, number>} */
662 this._frequencyMap
= new Map();
663 var stylesheetPromises
= [];
664 for (var stylesheet
of cssModel
.allStyleSheets())
665 stylesheetPromises
.push(new Promise(this._processStylesheet
.bind(this, stylesheet
)));
666 Promise
.all(stylesheetPromises
)
667 .catchException(null)
668 .then(this._finish
.bind(this));
671 WebInspector
.Spectrum
.PaletteGenerator
.prototype = {
677 _frequencyComparator: function(a
, b
)
679 return this._frequencyMap
.get(b
) - this._frequencyMap
.get(a
);
684 var colors
= this._frequencyMap
.keysArray();
685 colors
= colors
.sort(this._frequencyComparator
.bind(this));
686 var paletteColors
= [];
687 var colorsPerRow
= 8;
688 while (paletteColors
.length
< colorsPerRow
&& colors
.length
) {
689 var colorText
= colors
.shift();
690 var color
= WebInspector
.Color
.parse(colorText
);
691 if (!color
|| color
.nickname() === "white" || color
.nickname() === "black")
693 paletteColors
.push(colorText
);
695 this._callback({ title
: "Page colors", colors
: paletteColors
});
699 * @param {!WebInspector.CSSStyleSheetHeader} stylesheet
700 * @param {function(?)} resolve
701 * @this {WebInspector.Spectrum.PaletteGenerator}
703 _processStylesheet: function(stylesheet
, resolve
)
706 * @param {?string} text
707 * @this {WebInspector.Spectrum.PaletteGenerator}
709 function parseContent(text
)
711 var regexResult
= text
.match(/((?:rgb|hsl)a?\([^)]+\)|#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3})/g) || [];
712 for (var c
of regexResult
) {
713 var frequency
= this._frequencyMap
.get(c
) || 0;
714 this._frequencyMap
.set(c
, ++frequency
);
719 stylesheet
.requestContent(parseContent
.bind(this));
723 WebInspector
.Spectrum
.MaterialPalette
= { title
: "Material", colors
: [