Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(342)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/components/Spectrum.js

Issue 2608043002: DevTools: extract modules (with extensions) (Closed)
Patch Set: fixes Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2011 Brian Grinstead All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
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.
16 *
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.
27 */
28
29 /**
30 * @unrestricted
31 */
32 Components.Spectrum = class extends UI.VBox {
33 constructor() {
34 /**
35 * @param {!Element} parentElement
36 */
37 function appendSwitcherIcon(parentElement) {
38 var icon = parentElement.createSVGChild('svg');
39 icon.setAttribute('height', 16);
40 icon.setAttribute('width', 16);
41 var path = icon.createSVGChild('path');
42 path.setAttribute('d', 'M5,6 L11,6 L8,2 Z M5,10 L11,10 L8,14 Z');
43 return icon;
44 }
45
46 super(true);
47 this.registerRequiredCSS('components/spectrum.css');
48 this.contentElement.tabIndex = 0;
49 this.setDefaultFocusedElement(this.contentElement);
50
51 this._colorElement = this.contentElement.createChild('div', 'spectrum-color' );
52 this._colorDragElement = this._colorElement.createChild('div', 'spectrum-sat fill')
53 .createChild('div', 'spectrum-val fill')
54 .createChild('div', 'spectrum-dragger');
55 var contrastRatioSVG = this._colorElement.createSVGChild('svg', 'spectrum-co ntrast-container fill');
56 this._contrastRatioLine = contrastRatioSVG.createSVGChild('path', 'spectrum- contrast-line');
57
58 var toolbar = new UI.Toolbar('spectrum-eye-dropper', this.contentElement);
59 this._colorPickerButton = new UI.ToolbarToggle(Common.UIString('Toggle color picker'), 'largeicon-eyedropper');
60 this._colorPickerButton.setToggled(true);
61 this._colorPickerButton.addEventListener(
62 UI.ToolbarButton.Events.Click, this._toggleColorPicker.bind(this, undefi ned));
63 toolbar.appendToolbarItem(this._colorPickerButton);
64
65 var swatchElement = this.contentElement.createChild('span', 'swatch');
66 this._swatchInnerElement = swatchElement.createChild('span', 'swatch-inner') ;
67 this._swatchOverlayElement = swatchElement.createChild('span', 'swatch-overl ay');
68 this._swatchOverlayElement.addEventListener('click', this._onCopyIconClick.b ind(this));
69 this._swatchOverlayElement.addEventListener('mouseout', this._onCopyIconMous eout.bind(this));
70 this._swatchCopyIcon = UI.Icon.create('largeicon-copy', 'copy-color-icon');
71 this._swatchCopyIcon.title = Common.UIString('Copy color to clipboard');
72 this._swatchOverlayElement.appendChild(this._swatchCopyIcon);
73
74 this._hueElement = this.contentElement.createChild('div', 'spectrum-hue');
75 this._hueSlider = this._hueElement.createChild('div', 'spectrum-slider');
76 this._alphaElement = this.contentElement.createChild('div', 'spectrum-alpha' );
77 this._alphaElementBackground = this._alphaElement.createChild('div', 'spectr um-alpha-background');
78 this._alphaSlider = this._alphaElement.createChild('div', 'spectrum-slider') ;
79
80 var displaySwitcher = this.contentElement.createChild('div', 'spectrum-displ ay-switcher spectrum-switcher');
81 appendSwitcherIcon(displaySwitcher);
82 displaySwitcher.addEventListener('click', this._formatViewSwitch.bind(this)) ;
83
84 // RGBA/HSLA display.
85 this._displayContainer = this.contentElement.createChild('div', 'spectrum-te xt source-code');
86 this._textValues = [];
87 for (var i = 0; i < 4; ++i) {
88 var inputValue = this._displayContainer.createChild('input', 'spectrum-tex t-value');
89 inputValue.maxLength = 4;
90 this._textValues.push(inputValue);
91 inputValue.addEventListener('keydown', this._inputChanged.bind(this), fals e);
92 inputValue.addEventListener('input', this._inputChanged.bind(this), false) ;
93 inputValue.addEventListener('mousewheel', this._inputChanged.bind(this), f alse);
94 }
95
96 this._textLabels = this._displayContainer.createChild('div', 'spectrum-text- label');
97
98 // HEX display.
99 this._hexContainer = this.contentElement.createChild('div', 'spectrum-text s pectrum-text-hex source-code');
100 this._hexValue = this._hexContainer.createChild('input', 'spectrum-text-valu e');
101 this._hexValue.maxLength = 7;
102 this._hexValue.addEventListener('keydown', this._inputChanged.bind(this), fa lse);
103 this._hexValue.addEventListener('input', this._inputChanged.bind(this), fals e);
104 this._hexValue.addEventListener('mousewheel', this._inputChanged.bind(this), false);
105
106 var label = this._hexContainer.createChild('div', 'spectrum-text-label');
107 label.textContent = 'HEX';
108
109 UI.installDragHandle(
110 this._hueElement, dragStart.bind(this, positionHue.bind(this)), position Hue.bind(this), null, 'default');
111 UI.installDragHandle(
112 this._alphaElement, dragStart.bind(this, positionAlpha.bind(this)), posi tionAlpha.bind(this), null, 'default');
113 UI.installDragHandle(
114 this._colorElement, dragStart.bind(this, positionColor.bind(this)), posi tionColor.bind(this), null, 'default');
115
116 this.element.classList.add('palettes-enabled');
117 /** @type {!Map.<string, !Components.Spectrum.Palette>} */
118 this._palettes = new Map();
119 this._palettePanel = this.contentElement.createChild('div', 'palette-panel') ;
120 this._palettePanelShowing = false;
121 this._paletteContainer = this.contentElement.createChild('div', 'spectrum-pa lette');
122 this._paletteContainer.addEventListener('contextmenu', this._showPaletteColo rContextMenu.bind(this, -1));
123 this._shadesContainer = this.contentElement.createChild('div', 'palette-colo r-shades hidden');
124 UI.installDragHandle(
125 this._paletteContainer, this._paletteDragStart.bind(this), this._palette Drag.bind(this),
126 this._paletteDragEnd.bind(this), 'default');
127 var paletteSwitcher = this.contentElement.createChild('div', 'spectrum-palet te-switcher spectrum-switcher');
128 appendSwitcherIcon(paletteSwitcher);
129 paletteSwitcher.addEventListener('click', this._togglePalettePanel.bind(this , true));
130
131 this._deleteIconToolbar = new UI.Toolbar('delete-color-toolbar');
132 this._deleteButton = new UI.ToolbarButton('', 'largeicon-trash-bin');
133 this._deleteIconToolbar.appendToolbarItem(this._deleteButton);
134
135 var overlay = this.contentElement.createChild('div', 'spectrum-overlay fill' );
136 overlay.addEventListener('click', this._togglePalettePanel.bind(this, false) );
137
138 this._addColorToolbar = new UI.Toolbar('add-color-toolbar');
139 var addColorButton = new UI.ToolbarButton(Common.UIString('Add to palette'), 'largeicon-add');
140 addColorButton.addEventListener(UI.ToolbarButton.Events.Click, this._addColo rToCustomPalette, this);
141 this._addColorToolbar.appendToolbarItem(addColorButton);
142
143 this._loadPalettes();
144 new Components.Spectrum.PaletteGenerator(this._generatedPaletteLoaded.bind(t his));
145
146 /**
147 * @param {function(!Event)} callback
148 * @param {!Event} event
149 * @return {boolean}
150 * @this {Components.Spectrum}
151 */
152 function dragStart(callback, event) {
153 this._hueAlphaLeft = this._hueElement.totalOffsetLeft();
154 this._colorOffset = this._colorElement.totalOffset();
155 callback(event);
156 return true;
157 }
158
159 /**
160 * @param {!Event} event
161 * @this {Components.Spectrum}
162 */
163 function positionHue(event) {
164 var hsva = this._hsv.slice();
165 hsva[0] = Number.constrain(1 - (event.x - this._hueAlphaLeft) / this._hueA lphaWidth, 0, 1);
166 this._innerSetColor(hsva, '', undefined, Components.Spectrum._ChangeSource .Other);
167 }
168
169 /**
170 * @param {!Event} event
171 * @this {Components.Spectrum}
172 */
173 function positionAlpha(event) {
174 var newAlpha = Math.round((event.x - this._hueAlphaLeft) / this._hueAlphaW idth * 100) / 100;
175 var hsva = this._hsv.slice();
176 hsva[3] = Number.constrain(newAlpha, 0, 1);
177 var colorFormat = undefined;
178 if (hsva[3] !== 1 &&
179 (this._colorFormat === Common.Color.Format.ShortHEX || this._colorForm at === Common.Color.Format.HEX ||
180 this._colorFormat === Common.Color.Format.Nickname))
181 colorFormat = Common.Color.Format.RGB;
182 this._innerSetColor(hsva, '', colorFormat, Components.Spectrum._ChangeSour ce.Other);
183 }
184
185 /**
186 * @param {!Event} event
187 * @this {Components.Spectrum}
188 */
189 function positionColor(event) {
190 var hsva = this._hsv.slice();
191 hsva[1] = Number.constrain((event.x - this._colorOffset.left) / this.dragW idth, 0, 1);
192 hsva[2] = Number.constrain(1 - (event.y - this._colorOffset.top) / this.dr agHeight, 0, 1);
193 this._innerSetColor(hsva, '', undefined, Components.Spectrum._ChangeSource .Other);
194 }
195 }
196
197 _onCopyIconClick() {
198 this._swatchCopyIcon.setIconType('largeicon-checkmark');
199 InspectorFrontendHost.copyText(this.colorString());
200 }
201
202 _onCopyIconMouseout() {
203 this._swatchCopyIcon.setIconType('largeicon-copy');
204 }
205
206 _updatePalettePanel() {
207 this._palettePanel.removeChildren();
208 var title = this._palettePanel.createChild('div', 'palette-title');
209 title.textContent = Common.UIString('Color Palettes');
210 var toolbar = new UI.Toolbar('', this._palettePanel);
211 var closeButton = new UI.ToolbarButton('Return to color picker', 'largeicon- delete');
212 closeButton.addEventListener(UI.ToolbarButton.Events.Click, this._togglePale ttePanel.bind(this, false));
213 toolbar.appendToolbarItem(closeButton);
214 for (var palette of this._palettes.values())
215 this._palettePanel.appendChild(this._createPreviewPaletteElement(palette)) ;
216 }
217
218 /**
219 * @param {boolean} show
220 */
221 _togglePalettePanel(show) {
222 if (this._palettePanelShowing === show)
223 return;
224 if (show)
225 this._updatePalettePanel();
226 this._focus();
227 this._palettePanelShowing = show;
228 this.contentElement.classList.toggle('palette-panel-showing', show);
229 }
230
231 _focus() {
232 if (this.isShowing())
233 this.contentElement.focus();
234 }
235
236 /**
237 * @param {string} colorText
238 * @param {number=} animationDelay
239 * @return {!Element}
240 */
241 _createPaletteColor(colorText, animationDelay) {
242 var element = createElementWithClass('div', 'spectrum-palette-color');
243 element.style.background = String.sprintf('linear-gradient(%s, %s), url(Imag es/checker.png)', colorText, colorText);
244 if (animationDelay)
245 element.animate([{opacity: 0}, {opacity: 1}], {duration: 100, delay: anima tionDelay, fill: 'backwards'});
246 element.title = colorText;
247 return element;
248 }
249
250 /**
251 * @param {!Components.Spectrum.Palette} palette
252 * @param {boolean} animate
253 * @param {!Event=} event
254 */
255 _showPalette(palette, animate, event) {
256 this._resizeForSelectedPalette();
257 this._paletteContainer.removeChildren();
258 for (var i = 0; i < palette.colors.length; i++) {
259 var animationDelay = animate ? i * 100 / palette.colors.length : 0;
260 var colorElement = this._createPaletteColor(palette.colors[i], animationDe lay);
261 colorElement.addEventListener(
262 'mousedown', this._paletteColorSelected.bind(this, palette.colors[i], palette.matchUserFormat));
263 if (palette.mutable) {
264 colorElement.__mutable = true;
265 colorElement.__color = palette.colors[i];
266 colorElement.addEventListener('contextmenu', this._showPaletteColorConte xtMenu.bind(this, i));
267 } else if (palette === Components.Spectrum.MaterialPalette) {
268 colorElement.classList.add('has-material-shades');
269 var shadow = colorElement.createChild('div', 'spectrum-palette-color spe ctrum-palette-color-shadow');
270 shadow.style.background = palette.colors[i];
271 shadow = colorElement.createChild('div', 'spectrum-palette-color spectru m-palette-color-shadow');
272 shadow.style.background = palette.colors[i];
273 colorElement.title = Common.UIString(palette.colors[i] + '. Long-click t o show alternate shades.');
274 new UI.LongClickController(colorElement, this._showLightnessShades.bind( this, colorElement, palette.colors[i]));
275 }
276 this._paletteContainer.appendChild(colorElement);
277 }
278 this._paletteContainerMutable = palette.mutable;
279
280 if (palette.mutable) {
281 this._paletteContainer.appendChild(this._addColorToolbar.element);
282 this._paletteContainer.appendChild(this._deleteIconToolbar.element);
283 } else {
284 this._addColorToolbar.element.remove();
285 this._deleteIconToolbar.element.remove();
286 }
287
288 this._togglePalettePanel(false);
289 this._focus();
290 }
291
292 /**
293 * @param {!Element} colorElement
294 * @param {string} colorText
295 * @param {!Event} event
296 */
297 _showLightnessShades(colorElement, colorText, event) {
298 /**
299 * @param {!Element} element
300 * @this {!Components.Spectrum}
301 */
302 function closeLightnessShades(element) {
303 this._shadesContainer.classList.add('hidden');
304 element.classList.remove('spectrum-shades-shown');
305 this._shadesContainer.ownerDocument.removeEventListener('mousedown', this. _shadesCloseHandler, true);
306 delete this._shadesCloseHandler;
307 }
308
309 if (this._shadesCloseHandler)
310 this._shadesCloseHandler();
311
312 this._shadesContainer.classList.remove('hidden');
313 this._shadesContainer.removeChildren();
314 this._shadesContainer.animate(
315 [{transform: 'scaleY(0)', opacity: '0'}, {transform: 'scaleY(1)', opacit y: '1'}],
316 {duration: 200, easing: 'cubic-bezier(0.4, 0, 0.2, 1)'});
317 this._shadesContainer.style.top = colorElement.offsetTop + colorElement.pare ntElement.offsetTop + 'px';
318 this._shadesContainer.style.left = colorElement.offsetLeft + 'px';
319 colorElement.classList.add('spectrum-shades-shown');
320
321 var shades = Components.Spectrum.MaterialPaletteShades[colorText];
322 for (var i = shades.length - 1; i >= 0; i--) {
323 var shadeElement = this._createPaletteColor(shades[i], i * 200 / shades.le ngth + 100);
324 shadeElement.addEventListener('mousedown', this._paletteColorSelected.bind (this, shades[i], false));
325 this._shadesContainer.appendChild(shadeElement);
326 }
327
328 this._shadesContainer.focus();
329 this._shadesCloseHandler = closeLightnessShades.bind(this, colorElement);
330 this._shadesContainer.ownerDocument.addEventListener('mousedown', this._shad esCloseHandler, true);
331 }
332
333 /**
334 * @param {!Event} e
335 * @return {number}
336 */
337 _slotIndexForEvent(e) {
338 var localX = e.pageX - this._paletteContainer.totalOffsetLeft();
339 var localY = e.pageY - this._paletteContainer.totalOffsetTop();
340 var col = Math.min(localX / Components.Spectrum._colorChipSize | 0, Componen ts.Spectrum._itemsPerPaletteRow - 1);
341 var row = (localY / Components.Spectrum._colorChipSize) | 0;
342 return Math.min(
343 row * Components.Spectrum._itemsPerPaletteRow + col, this._customPalette Setting.get().colors.length - 1);
344 }
345
346 /**
347 * @param {!Event} e
348 * @return {boolean}
349 */
350 _isDraggingToBin(e) {
351 return e.pageX > this._deleteIconToolbar.element.totalOffsetLeft();
352 }
353
354 /**
355 * @param {!Event} e
356 * @return {boolean}
357 */
358 _paletteDragStart(e) {
359 var element = e.deepElementFromPoint();
360 if (!element || !element.__mutable)
361 return false;
362
363 var index = this._slotIndexForEvent(e);
364 this._dragElement = element;
365 this._dragHotSpotX =
366 e.pageX - (index % Components.Spectrum._itemsPerPaletteRow) * Components .Spectrum._colorChipSize;
367 this._dragHotSpotY =
368 e.pageY - (index / Components.Spectrum._itemsPerPaletteRow | 0) * Compon ents.Spectrum._colorChipSize;
369 return true;
370 }
371
372 /**
373 * @param {!Event} e
374 */
375 _paletteDrag(e) {
376 if (e.pageX < this._paletteContainer.totalOffsetLeft() || e.pageY < this._pa letteContainer.totalOffsetTop())
377 return;
378 var newIndex = this._slotIndexForEvent(e);
379 var offsetX = e.pageX - (newIndex % Components.Spectrum._itemsPerPaletteRow) * Components.Spectrum._colorChipSize;
380 var offsetY =
381 e.pageY - (newIndex / Components.Spectrum._itemsPerPaletteRow | 0) * Com ponents.Spectrum._colorChipSize;
382
383 var isDeleting = this._isDraggingToBin(e);
384 this._deleteIconToolbar.element.classList.add('dragging');
385 this._deleteIconToolbar.element.classList.toggle('delete-color-toolbar-activ e', isDeleting);
386 var dragElementTransform =
387 'translateX(' + (offsetX - this._dragHotSpotX) + 'px) translateY(' + (of fsetY - this._dragHotSpotY) + 'px)';
388 this._dragElement.style.transform = isDeleting ? dragElementTransform + ' sc ale(0.8)' : dragElementTransform;
389 var children = Array.prototype.slice.call(this._paletteContainer.children);
390 var index = children.indexOf(this._dragElement);
391 /** @type {!Map.<!Element, {left: number, top: number}>} */
392 var swatchOffsets = new Map();
393 for (var swatch of children)
394 swatchOffsets.set(swatch, swatch.totalOffset());
395
396 if (index !== newIndex)
397 this._paletteContainer.insertBefore(this._dragElement, children[newIndex > index ? newIndex + 1 : newIndex]);
398
399 for (var swatch of children) {
400 if (swatch === this._dragElement)
401 continue;
402 var before = swatchOffsets.get(swatch);
403 var after = swatch.totalOffset();
404 if (before.left !== after.left || before.top !== after.top) {
405 swatch.animate(
406 [
407 {
408 transform:
409 'translateX(' + (before.left - after.left) + 'px) translateY (' + (before.top - after.top) + 'px)'
410 },
411 {transform: 'none'}
412 ],
413 {duration: 100, easing: 'cubic-bezier(0, 0, 0.2, 1)'});
414 }
415 }
416 }
417
418 /**
419 * @param {!Event} e
420 */
421 _paletteDragEnd(e) {
422 if (this._isDraggingToBin(e))
423 this._dragElement.remove();
424 this._dragElement.style.removeProperty('transform');
425 var children = this._paletteContainer.children;
426 var colors = [];
427 for (var i = 0; i < children.length; ++i) {
428 if (children[i].__color)
429 colors.push(children[i].__color);
430 }
431 var palette = this._customPaletteSetting.get();
432 palette.colors = colors;
433 this._customPaletteSetting.set(palette);
434 this._showPalette(this._customPaletteSetting.get(), false);
435
436 this._deleteIconToolbar.element.classList.remove('dragging');
437 this._deleteIconToolbar.element.classList.remove('delete-color-toolbar-activ e');
438 }
439
440 _loadPalettes() {
441 this._palettes.set(Components.Spectrum.MaterialPalette.title, Components.Spe ctrum.MaterialPalette);
442 /** @type {!Components.Spectrum.Palette} */
443 var defaultCustomPalette = {title: 'Custom', colors: [], mutable: true};
444 this._customPaletteSetting = Common.settings.createSetting('customColorPalet te', defaultCustomPalette);
445 this._palettes.set(this._customPaletteSetting.get().title, this._customPalet teSetting.get());
446
447 this._selectedColorPalette =
448 Common.settings.createSetting('selectedColorPalette', Components.Spectru m.GeneratedPaletteTitle);
449 var palette = this._palettes.get(this._selectedColorPalette.get());
450 if (palette)
451 this._showPalette(palette, true);
452 }
453
454 /**
455 * @param {!Components.Spectrum.Palette} generatedPalette
456 */
457 _generatedPaletteLoaded(generatedPalette) {
458 if (generatedPalette.colors.length)
459 this._palettes.set(generatedPalette.title, generatedPalette);
460 if (this._selectedColorPalette.get() !== generatedPalette.title) {
461 return;
462 } else if (!generatedPalette.colors.length) {
463 this._paletteSelected(Components.Spectrum.MaterialPalette);
464 return;
465 }
466 this._showPalette(generatedPalette, true);
467 }
468
469 /**
470 * @param {!Components.Spectrum.Palette} palette
471 * @return {!Element}
472 */
473 _createPreviewPaletteElement(palette) {
474 var colorsPerPreviewRow = 5;
475 var previewElement = createElementWithClass('div', 'palette-preview');
476 var titleElement = previewElement.createChild('div', 'palette-preview-title' );
477 titleElement.textContent = palette.title;
478 for (var i = 0; i < colorsPerPreviewRow && i < palette.colors.length; i++)
479 previewElement.appendChild(this._createPaletteColor(palette.colors[i]));
480 for (; i < colorsPerPreviewRow; i++)
481 previewElement.createChild('div', 'spectrum-palette-color empty-color');
482 previewElement.addEventListener('click', this._paletteSelected.bind(this, pa lette));
483 return previewElement;
484 }
485
486 /**
487 * @param {!Components.Spectrum.Palette} palette
488 */
489 _paletteSelected(palette) {
490 this._selectedColorPalette.set(palette.title);
491 this._showPalette(palette, true);
492 }
493
494 _resizeForSelectedPalette() {
495 var palette = this._palettes.get(this._selectedColorPalette.get());
496 if (!palette)
497 return;
498 var numColors = palette.colors.length;
499 if (palette === this._customPaletteSetting.get())
500 numColors++;
501 var rowsNeeded = Math.max(1, Math.ceil(numColors / Components.Spectrum._item sPerPaletteRow));
502 if (this._numPaletteRowsShown === rowsNeeded)
503 return;
504 this._numPaletteRowsShown = rowsNeeded;
505 var paletteColorHeight = 12;
506 var paletteMargin = 12;
507 var paletteTop = 235;
508 this.element.style.height = (paletteTop + paletteMargin + (paletteColorHeigh t + paletteMargin) * rowsNeeded) + 'px';
509 this.dispatchEventToListeners(Components.Spectrum.Events.SizeChanged);
510 }
511
512 /**
513 * @param {string} colorText
514 * @param {boolean} matchUserFormat
515 */
516 _paletteColorSelected(colorText, matchUserFormat) {
517 var color = Common.Color.parse(colorText);
518 if (!color)
519 return;
520 this._innerSetColor(
521 color.hsva(), colorText, matchUserFormat ? this._colorFormat : color.for mat(),
522 Components.Spectrum._ChangeSource.Other);
523 }
524
525 /**
526 * @param {!Common.Event} event
527 */
528 _addColorToCustomPalette(event) {
529 var palette = this._customPaletteSetting.get();
530 palette.colors.push(this.colorString());
531 this._customPaletteSetting.set(palette);
532 this._showPalette(this._customPaletteSetting.get(), false);
533 }
534
535 /**
536 * @param {number} colorIndex
537 * @param {!Event} event
538 */
539 _showPaletteColorContextMenu(colorIndex, event) {
540 if (!this._paletteContainerMutable)
541 return;
542 var contextMenu = new UI.ContextMenu(event);
543 if (colorIndex !== -1) {
544 contextMenu.appendItem(Common.UIString('Remove color'), this._deletePalett eColors.bind(this, colorIndex, false));
545 contextMenu.appendItem(
546 Common.UIString('Remove all to the right'), this._deletePaletteColors. bind(this, colorIndex, true));
547 }
548 contextMenu.appendItem(Common.UIString('Clear palette'), this._deletePalette Colors.bind(this, -1, true));
549 contextMenu.show();
550 }
551
552 /**
553 * @param {number} colorIndex
554 * @param {boolean} toRight
555 */
556 _deletePaletteColors(colorIndex, toRight) {
557 var palette = this._customPaletteSetting.get();
558 if (toRight)
559 palette.colors.splice(colorIndex + 1, palette.colors.length - colorIndex - 1);
560 else
561 palette.colors.splice(colorIndex, 1);
562 this._customPaletteSetting.set(palette);
563 this._showPalette(this._customPaletteSetting.get(), false);
564 }
565
566 /**
567 * @param {!Common.Color} color
568 * @param {string} colorFormat
569 */
570 setColor(color, colorFormat) {
571 this._originalFormat = colorFormat;
572 this._innerSetColor(color.hsva(), '', colorFormat, Components.Spectrum._Chan geSource.Model);
573 }
574
575 /**
576 * @param {!Array<number>|undefined} hsva
577 * @param {string|undefined} colorString
578 * @param {string|undefined} colorFormat
579 * @param {string} changeSource
580 */
581 _innerSetColor(hsva, colorString, colorFormat, changeSource) {
582 if (hsva !== undefined)
583 this._hsv = hsva;
584 if (colorString !== undefined)
585 this._colorString = colorString;
586 if (colorFormat !== undefined) {
587 console.assert(colorFormat !== Common.Color.Format.Original, 'Spectrum\'s color format cannot be Original');
588 if (colorFormat === Common.Color.Format.RGBA)
589 colorFormat = Common.Color.Format.RGB;
590 else if (colorFormat === Common.Color.Format.HSLA)
591 colorFormat = Common.Color.Format.HSL;
592 this._colorFormat = colorFormat;
593 }
594
595 this._updateHelperLocations();
596 this._updateUI();
597
598 if (changeSource !== Components.Spectrum._ChangeSource.Input)
599 this._updateInput();
600 if (changeSource !== Components.Spectrum._ChangeSource.Model)
601 this.dispatchEventToListeners(Components.Spectrum.Events.ColorChanged, thi s.colorString());
602 }
603
604 /**
605 * @param {!Common.Color} color
606 */
607 setContrastColor(color) {
608 this._contrastColor = color;
609 this._updateUI();
610 }
611
612 /**
613 * @return {!Common.Color}
614 */
615 _color() {
616 return Common.Color.fromHSVA(this._hsv);
617 }
618
619 /**
620 * @return {string}
621 */
622 colorString() {
623 if (this._colorString)
624 return this._colorString;
625 var cf = Common.Color.Format;
626 var color = this._color();
627 var colorString = color.asString(this._colorFormat);
628 if (colorString)
629 return colorString;
630
631 if (this._colorFormat === cf.Nickname || this._colorFormat === cf.ShortHEX) {
632 colorString = color.asString(cf.HEX);
633 if (colorString)
634 return colorString;
635 }
636
637 console.assert(color.hasAlpha());
638 return this._colorFormat === cf.HSL ? /** @type {string} */ (color.asString( cf.HSLA)) :
639 /** @type {string} */ (color.asString( cf.RGBA));
640 }
641
642 _updateHelperLocations() {
643 var h = this._hsv[0];
644 var s = this._hsv[1];
645 var v = this._hsv[2];
646 var alpha = this._hsv[3];
647
648 // Where to show the little circle that displays your current selected color .
649 var dragX = s * this.dragWidth;
650 var dragY = this.dragHeight - (v * this.dragHeight);
651
652 dragX = Math.max(
653 -this._colorDragElementHeight,
654 Math.min(this.dragWidth - this._colorDragElementHeight, dragX - this._co lorDragElementHeight));
655 dragY = Math.max(
656 -this._colorDragElementHeight,
657 Math.min(this.dragHeight - this._colorDragElementHeight, dragY - this._c olorDragElementHeight));
658
659 this._colorDragElement.positionAt(dragX, dragY);
660
661 // Where to show the bar that displays your current selected hue.
662 var hueSlideX = (1 - h) * this._hueAlphaWidth - this.slideHelperWidth;
663 this._hueSlider.style.left = hueSlideX + 'px';
664 var alphaSlideX = alpha * this._hueAlphaWidth - this.slideHelperWidth;
665 this._alphaSlider.style.left = alphaSlideX + 'px';
666 }
667
668 _updateInput() {
669 var cf = Common.Color.Format;
670 if (this._colorFormat === cf.HEX || this._colorFormat === cf.ShortHEX || thi s._colorFormat === cf.Nickname) {
671 this._hexContainer.hidden = false;
672 this._displayContainer.hidden = true;
673 if (this._colorFormat === cf.ShortHEX && this._color().canBeShortHex())
674 this._hexValue.value = this._color().asString(cf.ShortHEX);
675 else
676 this._hexValue.value = this._color().asString(cf.HEX);
677 } else {
678 // RGBA, HSLA display.
679 this._hexContainer.hidden = true;
680 this._displayContainer.hidden = false;
681 var isRgb = this._colorFormat === cf.RGB;
682 this._textLabels.textContent = isRgb ? 'RGBA' : 'HSLA';
683 var colorValues = isRgb ? this._color().canonicalRGBA() : this._color().ca nonicalHSLA();
684 for (var i = 0; i < 3; ++i) {
685 this._textValues[i].value = colorValues[i];
686 if (!isRgb && (i === 1 || i === 2))
687 this._textValues[i].value += '%';
688 }
689 this._textValues[3].value = Math.round(colorValues[3] * 100) / 100;
690 }
691 }
692
693 /**
694 * @param {number} requiredContrast
695 */
696 _drawContrastRatioLine(requiredContrast) {
697 if (!this._contrastColor || !this.dragWidth || !this.dragHeight)
698 return;
699
700 /** const */ var width = this.dragWidth;
701 /** const */ var height = this.dragHeight;
702 /** const */ var dS = 0.02;
703 /** const */ var epsilon = 0.002;
704 /** const */ var H = 0;
705 /** const */ var S = 1;
706 /** const */ var V = 2;
707 /** const */ var A = 3;
708
709 var fgRGBA = [];
710 Common.Color.hsva2rgba(this._hsv, fgRGBA);
711 var fgLuminance = Common.Color.luminance(fgRGBA);
712 var bgRGBA = this._contrastColor.rgba();
713 var bgLuminance = Common.Color.luminance(bgRGBA);
714 var fgIsLighter = fgLuminance > bgLuminance;
715 var desiredLuminance = Common.Color.desiredLuminance(bgLuminance, requiredCo ntrast, fgIsLighter);
716
717 var lastV = this._hsv[V];
718 var currentSlope = 0;
719 var candidateHSVA = [this._hsv[H], 0, 0, this._hsv[A]];
720 var pathBuilder = [];
721 var candidateRGBA = [];
722 Common.Color.hsva2rgba(candidateHSVA, candidateRGBA);
723 var blendedRGBA = [];
724 Common.Color.blendColors(candidateRGBA, bgRGBA, blendedRGBA);
725
726 /**
727 * Approach the desired contrast ratio by modifying the given component
728 * from the given starting value.
729 * @param {number} index
730 * @param {number} x
731 * @param {boolean} onAxis
732 * @return {?number}
733 */
734 function approach(index, x, onAxis) {
735 while (0 <= x && x <= 1) {
736 candidateHSVA[index] = x;
737 Common.Color.hsva2rgba(candidateHSVA, candidateRGBA);
738 Common.Color.blendColors(candidateRGBA, bgRGBA, blendedRGBA);
739 var fgLuminance = Common.Color.luminance(blendedRGBA);
740 var dLuminance = fgLuminance - desiredLuminance;
741
742 if (Math.abs(dLuminance) < (onAxis ? epsilon / 10 : epsilon))
743 return x;
744 else
745 x += (index === V ? -dLuminance : dLuminance);
746 }
747 return null;
748 }
749
750 for (var s = 0; s < 1 + dS; s += dS) {
751 s = Math.min(1, s);
752 candidateHSVA[S] = s;
753
754 var v = lastV;
755 v = lastV + currentSlope * dS;
756
757 v = approach(V, v, s === 0);
758 if (v === null)
759 break;
760
761 currentSlope = (v - lastV) / dS;
762
763 pathBuilder.push(pathBuilder.length ? 'L' : 'M');
764 pathBuilder.push(s * width);
765 pathBuilder.push((1 - v) * height);
766 }
767
768 if (s < 1 + dS) {
769 s -= dS;
770 candidateHSVA[V] = 1;
771 s = approach(S, s, true);
772 if (s !== null)
773 pathBuilder = pathBuilder.concat(['L', s * width, -1]);
774 }
775
776 this._contrastRatioLine.setAttribute('d', pathBuilder.join(' '));
777 }
778
779 _updateUI() {
780 var h = Common.Color.fromHSVA([this._hsv[0], 1, 1, 1]);
781 this._colorElement.style.backgroundColor = /** @type {string} */ (h.asString (Common.Color.Format.RGB));
782 if (Runtime.experiments.isEnabled('colorContrastRatio')) {
783 // TODO(samli): Determine size of text and switch between AA/AAA ratings.
784 this._drawContrastRatioLine(4.5);
785 }
786 this._swatchInnerElement.style.backgroundColor =
787 /** @type {string} */ (this._color().asString(Common.Color.Format.RGBA)) ;
788 // Show border if the swatch is white.
789 this._swatchInnerElement.classList.toggle('swatch-inner-white', this._color( ).hsla()[2] > 0.9);
790 this._colorDragElement.style.backgroundColor =
791 /** @type {string} */ (this._color().asString(Common.Color.Format.RGBA)) ;
792 var noAlpha = Common.Color.fromHSVA(this._hsv.slice(0, 3).concat(1));
793 this._alphaElementBackground.style.backgroundImage =
794 String.sprintf('linear-gradient(to right, rgba(0,0,0,0), %s)', noAlpha.a sString(Common.Color.Format.RGB));
795 }
796
797 _formatViewSwitch() {
798 var cf = Common.Color.Format;
799 var format = cf.RGB;
800 if (this._colorFormat === cf.RGB)
801 format = cf.HSL;
802 else if (this._colorFormat === cf.HSL && !this._color().hasAlpha())
803 format = this._originalFormat === cf.ShortHEX ? cf.ShortHEX : cf.HEX;
804 this._innerSetColor(undefined, '', format, Components.Spectrum._ChangeSource .Other);
805 }
806
807 /**
808 * @param {!Event} event
809 */
810 _inputChanged(event) {
811 /**
812 * @param {!Element} element
813 * @return {string}
814 */
815 function elementValue(element) {
816 return element.value;
817 }
818
819 var inputElement = /** @type {!Element} */ (event.currentTarget);
820 var newValue = UI.createReplacementString(inputElement.value, event);
821 if (newValue) {
822 inputElement.value = newValue;
823 inputElement.selectionStart = 0;
824 inputElement.selectionEnd = newValue.length;
825 event.consume(true);
826 }
827
828 const cf = Common.Color.Format;
829 var colorString;
830 if (this._colorFormat === cf.HEX || this._colorFormat === cf.ShortHEX) {
831 colorString = this._hexValue.value;
832 } else {
833 var format = this._colorFormat === cf.RGB ? 'rgba' : 'hsla';
834 var values = this._textValues.map(elementValue).join(', ');
835 colorString = String.sprintf('%s(%s)', format, values);
836 }
837
838 var color = Common.Color.parse(colorString);
839 if (!color)
840 return;
841 var hsv = color.hsva();
842 if (this._colorFormat === cf.HEX || this._colorFormat === cf.ShortHEX)
843 this._colorFormat = color.canBeShortHex() ? cf.ShortHEX : cf.HEX;
844 this._innerSetColor(hsv, colorString, undefined, Components.Spectrum._Change Source.Input);
845 }
846
847 /**
848 * @override
849 */
850 wasShown() {
851 this._hueAlphaWidth = this._hueElement.offsetWidth;
852 this.slideHelperWidth = this._hueSlider.offsetWidth / 2;
853 this.dragWidth = this._colorElement.offsetWidth;
854 this.dragHeight = this._colorElement.offsetHeight;
855 this._colorDragElementHeight = this._colorDragElement.offsetHeight / 2;
856 this._innerSetColor(undefined, undefined, undefined, Components.Spectrum._Ch angeSource.Model);
857 this._toggleColorPicker(true);
858 SDK.targetManager.addModelListener(
859 SDK.ResourceTreeModel, SDK.ResourceTreeModel.Events.ColorPicked, this._c olorPicked, this);
860 }
861
862 /**
863 * @override
864 */
865 willHide() {
866 this._toggleColorPicker(false);
867 SDK.targetManager.removeModelListener(
868 SDK.ResourceTreeModel, SDK.ResourceTreeModel.Events.ColorPicked, this._c olorPicked, this);
869 }
870
871 /**
872 * @param {boolean=} enabled
873 * @param {!Common.Event=} event
874 */
875 _toggleColorPicker(enabled, event) {
876 if (enabled === undefined)
877 enabled = !this._colorPickerButton.toggled();
878 this._colorPickerButton.setToggled(enabled);
879 for (var target of SDK.targetManager.targets())
880 target.pageAgent().setColorPickerEnabled(enabled);
881 }
882
883 /**
884 * @param {!Common.Event} event
885 */
886 _colorPicked(event) {
887 var rgbColor = /** @type {!Protocol.DOM.RGBA} */ (event.data);
888 var rgba = [rgbColor.r, rgbColor.g, rgbColor.b, (rgbColor.a / 2.55 | 0) / 10 0];
889 var color = Common.Color.fromRGBA(rgba);
890 this._innerSetColor(color.hsva(), '', undefined, Components.Spectrum._Change Source.Other);
891 InspectorFrontendHost.bringToFront();
892 }
893 };
894
895 Components.Spectrum._ChangeSource = {
896 Input: 'Input',
897 Model: 'Model',
898 Other: 'Other'
899 };
900
901 /** @enum {symbol} */
902 Components.Spectrum.Events = {
903 ColorChanged: Symbol('ColorChanged'),
904 SizeChanged: Symbol('SizeChanged')
905 };
906
907 Components.Spectrum._colorChipSize = 24;
908 Components.Spectrum._itemsPerPaletteRow = 8;
909
910 /** @typedef {{ title: string, colors: !Array.<string>, mutable: boolean }} */
911 Components.Spectrum.Palette;
912 Components.Spectrum.GeneratedPaletteTitle = 'Page colors';
913
914 /**
915 * @unrestricted
916 */
917 Components.Spectrum.PaletteGenerator = class {
918 /**
919 * @param {function(!Components.Spectrum.Palette)} callback
920 */
921 constructor(callback) {
922 this._callback = callback;
923 /** @type {!Map.<string, number>} */
924 this._frequencyMap = new Map();
925 var stylesheetPromises = [];
926 for (var target of SDK.targetManager.targets(SDK.Target.Capability.DOM)) {
927 var cssModel = SDK.CSSModel.fromTarget(target);
928 for (var stylesheet of cssModel.allStyleSheets())
929 stylesheetPromises.push(new Promise(this._processStylesheet.bind(this, s tylesheet)));
930 }
931 Promise.all(stylesheetPromises).catchException(null).then(this._finish.bind( this));
932 }
933
934 /**
935 * @param {string} a
936 * @param {string} b
937 * @return {number}
938 */
939 _frequencyComparator(a, b) {
940 return this._frequencyMap.get(b) - this._frequencyMap.get(a);
941 }
942
943 _finish() {
944 /**
945 * @param {string} a
946 * @param {string} b
947 * @return {number}
948 */
949 function hueComparator(a, b) {
950 var hsva = paletteColors.get(a).hsva();
951 var hsvb = paletteColors.get(b).hsva();
952
953 // First trim the shades of gray
954 if (hsvb[1] < 0.12 && hsva[1] < 0.12)
955 return hsvb[2] * hsvb[3] - hsva[2] * hsva[3];
956 if (hsvb[1] < 0.12)
957 return -1;
958 if (hsva[1] < 0.12)
959 return 1;
960
961 // Equal hue -> sort by sat
962 if (hsvb[0] === hsva[0])
963 return hsvb[1] * hsvb[3] - hsva[1] * hsva[3];
964
965 return (hsvb[0] + 0.94) % 1 - (hsva[0] + 0.94) % 1;
966 }
967
968 var colors = this._frequencyMap.keysArray();
969 colors = colors.sort(this._frequencyComparator.bind(this));
970 /** @type {!Map.<string, !Common.Color>} */
971 var paletteColors = new Map();
972 var colorsPerRow = 24;
973 while (paletteColors.size < colorsPerRow && colors.length) {
974 var colorText = colors.shift();
975 var color = Common.Color.parse(colorText);
976 if (!color || color.nickname() === 'white' || color.nickname() === 'black' )
977 continue;
978 paletteColors.set(colorText, color);
979 }
980
981 this._callback({
982 title: Components.Spectrum.GeneratedPaletteTitle,
983 colors: paletteColors.keysArray().sort(hueComparator),
984 mutable: false
985 });
986 }
987
988 /**
989 * @param {!SDK.CSSStyleSheetHeader} stylesheet
990 * @param {function(?)} resolve
991 * @this {Components.Spectrum.PaletteGenerator}
992 */
993 _processStylesheet(stylesheet, resolve) {
994 /**
995 * @param {?string} text
996 * @this {Components.Spectrum.PaletteGenerator}
997 */
998 function parseContent(text) {
999 text = text.toLowerCase();
1000 var regexResult = text.match(/((?:rgb|hsl)a?\([^)]+\)|#[0-9a-f]{6}|#[0-9a- f]{3})/g) || [];
1001 for (var c of regexResult) {
1002 var frequency = this._frequencyMap.get(c) || 0;
1003 this._frequencyMap.set(c, ++frequency);
1004 }
1005 resolve(null);
1006 }
1007
1008 stylesheet.requestContent().then(parseContent.bind(this));
1009 }
1010 };
1011
1012 Components.Spectrum.MaterialPaletteShades = {
1013 '#F44336':
1014 ['#FFEBEE', '#FFCDD2', '#EF9A9A', '#E57373', '#EF5350', '#F44336', '#E5393 5', '#D32F2F', '#C62828', '#B71C1C'],
1015 '#E91E63':
1016 ['#FCE4EC', '#F8BBD0', '#F48FB1', '#F06292', '#EC407A', '#E91E63', '#D81B6 0', '#C2185B', '#AD1457', '#880E4F'],
1017 '#9C27B0':
1018 ['#F3E5F5', '#E1BEE7', '#CE93D8', '#BA68C8', '#AB47BC', '#9C27B0', '#8E24A A', '#7B1FA2', '#6A1B9A', '#4A148C'],
1019 '#673AB7':
1020 ['#EDE7F6', '#D1C4E9', '#B39DDB', '#9575CD', '#7E57C2', '#673AB7', '#5E35B 1', '#512DA8', '#4527A0', '#311B92'],
1021 '#3F51B5':
1022 ['#E8EAF6', '#C5CAE9', '#9FA8DA', '#7986CB', '#5C6BC0', '#3F51B5', '#3949A B', '#303F9F', '#283593', '#1A237E'],
1023 '#2196F3':
1024 ['#E3F2FD', '#BBDEFB', '#90CAF9', '#64B5F6', '#42A5F5', '#2196F3', '#1E88E 5', '#1976D2', '#1565C0', '#0D47A1'],
1025 '#03A9F4':
1026 ['#E1F5FE', '#B3E5FC', '#81D4FA', '#4FC3F7', '#29B6F6', '#03A9F4', '#039BE 5', '#0288D1', '#0277BD', '#01579B'],
1027 '#00BCD4':
1028 ['#E0F7FA', '#B2EBF2', '#80DEEA', '#4DD0E1', '#26C6DA', '#00BCD4', '#00ACC 1', '#0097A7', '#00838F', '#006064'],
1029 '#009688':
1030 ['#E0F2F1', '#B2DFDB', '#80CBC4', '#4DB6AC', '#26A69A', '#009688', '#00897 B', '#00796B', '#00695C', '#004D40'],
1031 '#4CAF50':
1032 ['#E8F5E9', '#C8E6C9', '#A5D6A7', '#81C784', '#66BB6A', '#4CAF50', '#43A04 7', '#388E3C', '#2E7D32', '#1B5E20'],
1033 '#8BC34A':
1034 ['#F1F8E9', '#DCEDC8', '#C5E1A5', '#AED581', '#9CCC65', '#8BC34A', '#7CB34 2', '#689F38', '#558B2F', '#33691E'],
1035 '#CDDC39':
1036 ['#F9FBE7', '#F0F4C3', '#E6EE9C', '#DCE775', '#D4E157', '#CDDC39', '#C0CA3 3', '#AFB42B', '#9E9D24', '#827717'],
1037 '#FFEB3B':
1038 ['#FFFDE7', '#FFF9C4', '#FFF59D', '#FFF176', '#FFEE58', '#FFEB3B', '#FDD83 5', '#FBC02D', '#F9A825', '#F57F17'],
1039 '#FFC107':
1040 ['#FFF8E1', '#FFECB3', '#FFE082', '#FFD54F', '#FFCA28', '#FFC107', '#FFB30 0', '#FFA000', '#FF8F00', '#FF6F00'],
1041 '#FF9800':
1042 ['#FFF3E0', '#FFE0B2', '#FFCC80', '#FFB74D', '#FFA726', '#FF9800', '#FB8C0 0', '#F57C00', '#EF6C00', '#E65100'],
1043 '#FF5722':
1044 ['#FBE9E7', '#FFCCBC', '#FFAB91', '#FF8A65', '#FF7043', '#FF5722', '#F4511 E', '#E64A19', '#D84315', '#BF360C'],
1045 '#795548':
1046 ['#EFEBE9', '#D7CCC8', '#BCAAA4', '#A1887F', '#8D6E63', '#795548', '#6D4C4 1', '#5D4037', '#4E342E', '#3E2723'],
1047 '#9E9E9E':
1048 ['#FAFAFA', '#F5F5F5', '#EEEEEE', '#E0E0E0', '#BDBDBD', '#9E9E9E', '#75757 5', '#616161', '#424242', '#212121'],
1049 '#607D8B':
1050 ['#ECEFF1', '#CFD8DC', '#B0BEC5', '#90A4AE', '#78909C', '#607D8B', '#546E7 A', '#455A64', '#37474F', '#263238']
1051 };
1052
1053 Components.Spectrum.MaterialPalette = {
1054 title: 'Material',
1055 mutable: false,
1056 matchUserFormat: true,
1057 colors: Object.keys(Components.Spectrum.MaterialPaletteShades)
1058 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698