| OLD | NEW |
| (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 }; | |
| OLD | NEW |