| /* |
| * Copyright (C) 2015 Apple Inc. All rights reserved. |
| * Copyright (C) 2016 Devin Rousso <dcrousso+webkit@gmail.com>. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| WebInspector.InlineSwatch = class InlineSwatch extends WebInspector.Object |
| { |
| constructor(type, value, readOnly) |
| { |
| super(); |
| |
| this._type = type; |
| |
| this._swatchElement = document.createElement("span"); |
| this._swatchElement.classList.add("inline-swatch", this._type.split("-").lastValue); |
| |
| switch (this._type) { |
| case WebInspector.InlineSwatch.Type.Bezier: |
| this._swatchElement.title = WebInspector.UIString("Click to open a cubic-bezier editor."); |
| break; |
| case WebInspector.InlineSwatch.Type.Spring: |
| this._swatchElement.title = WebInspector.UIString("Click to open a spring editor."); |
| break; |
| case WebInspector.InlineSwatch.Type.Gradient: |
| this._swatchElement.title = WebInspector.UIString("Click to select a gradient."); |
| break; |
| default: |
| console.assert(this._type === WebInspector.InlineSwatch.Type.Color); |
| this._swatchElement.title = WebInspector.UIString("Click to select a color. Shift-click to switch color formats."); |
| break; |
| } |
| |
| if (!readOnly) { |
| this._swatchElement.addEventListener("click", this._swatchElementClicked.bind(this)); |
| if (this._type === WebInspector.InlineSwatch.Type.Color) |
| this._swatchElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this)); |
| } |
| |
| this._swatchInnerElement = this._swatchElement.createChild("span"); |
| |
| this._value = value || this._fallbackValue(); |
| this._valueEditor = null; |
| |
| this._updateSwatch(); |
| } |
| |
| // Public |
| |
| get element() |
| { |
| return this._swatchElement; |
| } |
| |
| get value() |
| { |
| return this._value; |
| } |
| |
| set value(value) |
| { |
| this._value = value; |
| this._updateSwatch(true); |
| } |
| |
| // Protected |
| |
| didDismissPopover(popover) |
| { |
| if (!this._valueEditor) |
| return; |
| |
| if (typeof this._valueEditor.removeListeners === "function") |
| this._valueEditor.removeListeners(); |
| |
| this.dispatchEventToListeners(WebInspector.InlineSwatch.Event.Deactivated); |
| } |
| |
| // Private |
| |
| _fallbackValue() |
| { |
| switch (this._type) { |
| case WebInspector.InlineSwatch.Type.Bezier: |
| return WebInspector.CubicBezier.fromString("linear"); |
| case WebInspector.InlineSwatch.Type.Spring: |
| return WebInspector.Spring.fromString("1 100 10 0"); |
| case WebInspector.InlineSwatch.Type.Gradient: |
| return WebInspector.Gradient.fromString("linear-gradient(transparent, transparent)"); |
| case WebInspector.InlineSwatch.Type.Color: |
| return WebInspector.Color.fromString("white"); |
| default: |
| return null; |
| } |
| } |
| |
| _updateSwatch(dontFireEvents) |
| { |
| if (this._type === WebInspector.InlineSwatch.Type.Color || this._type === WebInspector.InlineSwatch.Type.Gradient) |
| this._swatchInnerElement.style.background = this._value ? this._value.toString() : null; |
| |
| if (!dontFireEvents) |
| this.dispatchEventToListeners(WebInspector.InlineSwatch.Event.ValueChanged, {value: this._value}); |
| } |
| |
| _swatchElementClicked(event) |
| { |
| this.dispatchEventToListeners(WebInspector.InlineSwatch.Event.BeforeClicked); |
| |
| if (this._type === WebInspector.InlineSwatch.Type.Color && event.shiftKey && this._value) { |
| let nextFormat = this._value.nextFormat(); |
| console.assert(nextFormat); |
| if (!nextFormat) |
| return; |
| |
| this._value.format = nextFormat; |
| this._updateSwatch(); |
| return; |
| } |
| |
| let bounds = WebInspector.Rect.rectFromClientRect(this._swatchElement.getBoundingClientRect()); |
| let popover = new WebInspector.Popover(this); |
| |
| popover.windowResizeHandler = () => { |
| let bounds = WebInspector.Rect.rectFromClientRect(this._swatchElement.getBoundingClientRect()); |
| popover.present(bounds.pad(2), [WebInspector.RectEdge.MIN_X]); |
| }; |
| |
| this._valueEditor = null; |
| if (this._type === WebInspector.InlineSwatch.Type.Bezier) { |
| this._valueEditor = new WebInspector.BezierEditor; |
| this._valueEditor.addEventListener(WebInspector.BezierEditor.Event.BezierChanged, this._valueEditorValueDidChange, this); |
| } else if (this._type === WebInspector.InlineSwatch.Type.Spring) { |
| this._valueEditor = new WebInspector.SpringEditor; |
| this._valueEditor.addEventListener(WebInspector.SpringEditor.Event.SpringChanged, this._valueEditorValueDidChange, this); |
| } else if (this._type === WebInspector.InlineSwatch.Type.Gradient) { |
| this._valueEditor = new WebInspector.GradientEditor; |
| this._valueEditor.addEventListener(WebInspector.GradientEditor.Event.GradientChanged, this._valueEditorValueDidChange, this); |
| this._valueEditor.addEventListener(WebInspector.GradientEditor.Event.ColorPickerToggled, (event) => popover.update()); |
| } else { |
| this._valueEditor = new WebInspector.ColorPicker; |
| this._valueEditor.addEventListener(WebInspector.ColorPicker.Event.ColorChanged, this._valueEditorValueDidChange, this); |
| } |
| |
| popover.content = this._valueEditor.element; |
| popover.present(bounds.pad(2), [WebInspector.RectEdge.MIN_X]); |
| |
| this.dispatchEventToListeners(WebInspector.InlineSwatch.Event.Activated); |
| |
| let value = this._value || this._fallbackValue(); |
| if (this._type === WebInspector.InlineSwatch.Type.Bezier) |
| this._valueEditor.bezier = value; |
| else if (this._type === WebInspector.InlineSwatch.Type.Spring) |
| this._valueEditor.spring = value; |
| else if (this._type === WebInspector.InlineSwatch.Type.Gradient) |
| this._valueEditor.gradient = value; |
| else |
| this._valueEditor.color = value; |
| } |
| |
| _valueEditorValueDidChange(event) |
| { |
| if (this._type === WebInspector.InlineSwatch.Type.Bezier) |
| this._value = event.data.bezier; |
| else if (this._type === WebInspector.InlineSwatch.Type.Spring) |
| this._value = event.data.spring; |
| else if (this._type === WebInspector.InlineSwatch.Type.Gradient) |
| this._value = event.data.gradient; |
| else |
| this._value = event.data.color; |
| |
| this._updateSwatch(); |
| } |
| |
| _handleContextMenuEvent(event) |
| { |
| if (!this._value) |
| return; |
| |
| let contextMenu = WebInspector.ContextMenu.createFromEvent(event); |
| |
| if (this._value.isKeyword() && this._value.format !== WebInspector.Color.Format.Keyword) { |
| contextMenu.appendItem(WebInspector.UIString("Format: Keyword"), () => { |
| this._value.format = WebInspector.Color.Format.Keyword; |
| this._updateSwatch(); |
| }); |
| } |
| |
| let hexInfo = this._getNextValidHEXFormat(); |
| if (hexInfo) { |
| contextMenu.appendItem(hexInfo.title, () => { |
| this._value.format = hexInfo.format; |
| this._updateSwatch(); |
| }); |
| } |
| |
| if (this._value.simple && this._value.format !== WebInspector.Color.Format.HSL) { |
| contextMenu.appendItem(WebInspector.UIString("Format: HSL"), () => { |
| this._value.format = WebInspector.Color.Format.HSL; |
| this._updateSwatch(); |
| }); |
| } else if (this._value.format !== WebInspector.Color.Format.HSLA) { |
| contextMenu.appendItem(WebInspector.UIString("Format: HSLA"), () => { |
| this._value.format = WebInspector.Color.Format.HSLA; |
| this._updateSwatch(); |
| }); |
| } |
| |
| if (this._value.simple && this._value.format !== WebInspector.Color.Format.RGB) { |
| contextMenu.appendItem(WebInspector.UIString("Format: RGB"), () => { |
| this._value.format = WebInspector.Color.Format.RGB; |
| this._updateSwatch(); |
| }); |
| } else if (this._value.format !== WebInspector.Color.Format.RGBA) { |
| contextMenu.appendItem(WebInspector.UIString("Format: RGBA"), () => { |
| this._value.format = WebInspector.Color.Format.RGBA; |
| this._updateSwatch(); |
| }); |
| } |
| } |
| |
| _getNextValidHEXFormat() |
| { |
| if (this._type !== WebInspector.InlineSwatch.Type.Color) |
| return false; |
| |
| function hexMatchesCurrentColor(hexInfo) { |
| let nextIsSimple = hexInfo.format === WebInspector.Color.Format.ShortHEX || hexInfo.format === WebInspector.Color.Format.HEX; |
| if (nextIsSimple && !this._value.simple) |
| return false; |
| |
| let nextIsShort = hexInfo.format === WebInspector.Color.Format.ShortHEX || hexInfo.format === WebInspector.Color.Format.ShortHEXAlpha; |
| if (nextIsShort && !this._value.canBeSerializedAsShortHEX()) |
| return false; |
| |
| return true; |
| } |
| |
| const hexFormats = [ |
| { |
| format: WebInspector.Color.Format.ShortHEX, |
| title: WebInspector.UIString("Format: Short Hex") |
| }, |
| { |
| format: WebInspector.Color.Format.ShortHEXAlpha, |
| title: WebInspector.UIString("Format: Short Hex with Alpha") |
| }, |
| { |
| format: WebInspector.Color.Format.HEX, |
| title: WebInspector.UIString("Format: Hex") |
| }, |
| { |
| format: WebInspector.Color.Format.HEXAlpha, |
| title: WebInspector.UIString("Format: Hex with Alpha") |
| } |
| ]; |
| |
| let currentColorIsHEX = hexFormats.some((info) => info.format === this._value.format); |
| |
| for (let i = 0; i < hexFormats.length; ++i) { |
| if (currentColorIsHEX && this._value.format !== hexFormats[i].format) |
| continue; |
| |
| for (let j = ~~currentColorIsHEX; j < hexFormats.length; ++j) { |
| let nextIndex = (i + j) % hexFormats.length; |
| if (hexMatchesCurrentColor.call(this, hexFormats[nextIndex])) |
| return hexFormats[nextIndex]; |
| } |
| return null; |
| } |
| return hexFormats[0]; |
| } |
| }; |
| |
| WebInspector.InlineSwatch.Type = { |
| Color: "inline-swatch-type-color", |
| Gradient: "inline-swatch-type-gradient", |
| Bezier: "inline-swatch-type-bezier", |
| Spring: "inline-swatch-type-spring", |
| }; |
| |
| WebInspector.InlineSwatch.Event = { |
| BeforeClicked: "inline-swatch-before-clicked", |
| ValueChanged: "inline-swatch-value-changed", |
| Activated: "inline-swatch-activated", |
| Deactivated: "inline-swatch-deactivated", |
| }; |