diff options
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Views/InlineSwatch.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/Views/InlineSwatch.js | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/Views/InlineSwatch.js b/Source/WebInspectorUI/UserInterface/Views/InlineSwatch.js new file mode 100644 index 000000000..85a09d59d --- /dev/null +++ b/Source/WebInspectorUI/UserInterface/Views/InlineSwatch.js @@ -0,0 +1,340 @@ +/* + * 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.Color: + this._swatchElement.title = WebInspector.UIString("Click to select a color. Shift-click to switch color formats."); + break; + case WebInspector.InlineSwatch.Type.Gradient: + this._swatchElement.title = WebInspector.UIString("Edit custom gradient"); + break; + case WebInspector.InlineSwatch.Type.Bezier: + this._swatchElement.title = WebInspector.UIString("Edit “cubic-bezier“ function"); + break; + case WebInspector.InlineSwatch.Type.Spring: + this._swatchElement.title = WebInspector.UIString("Edit “spring“ function"); + break; + case WebInspector.InlineSwatch.Type.Variable: + this._swatchElement.title = WebInspector.UIString("View variable value"); + break; + default: + WebInspector.reportInternalError(`Unknown InlineSwatch type "${type}"`); + break; + } + + this._boundSwatchElementClicked = null; + if (!readOnly) { + this._boundSwatchElementClicked = this._swatchElementClicked.bind(this); + this._swatchElement.addEventListener("click", this._boundSwatchElementClicked); + 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); + } + + // Popover delegate + + didDismissPopover(popover) + { + if (!this._valueEditor) + return; + + if (typeof this._valueEditor.removeListeners === "function") + this._valueEditor.removeListeners(); + + if (this._boundSwatchElementClicked) + this._swatchElement.addEventListener("click", this._boundSwatchElementClicked); + + 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.Gradient: + return WebInspector.Gradient.fromString("linear-gradient(transparent, transparent)"); + case WebInspector.InlineSwatch.Type.Spring: + return WebInspector.Spring.fromString("1 100 10 0"); + 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.Color) { + this._valueEditor = new WebInspector.ColorPicker; + this._valueEditor.addEventListener(WebInspector.ColorPicker.Event.ColorChanged, this._valueEditorValueDidChange, this); + this._valueEditor.addEventListener(WebInspector.ColorPicker.Event.FormatChanged, (event) => popover.update()); + } 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 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.Variable) { + this._valueEditor = {}; + + this._valueEditor.element = document.createElement("div"); + this._valueEditor.element.classList.add("inline-swatch-variable-popover"); + + this._valueEditor.codeMirror = WebInspector.CodeMirrorEditor.create(this._valueEditor.element, { + mode: "css", + readOnly: "nocursor", + }); + this._valueEditor.codeMirror.on("update", () => { + popover.update(); + }); + } + + if (!this._valueEditor) + return; + + popover.content = this._valueEditor.element; + popover.present(bounds.pad(2), [WebInspector.RectEdge.MIN_X]); + + if (this._boundSwatchElementClicked) + this._swatchElement.removeEventListener("click", this._boundSwatchElementClicked); + + this.dispatchEventToListeners(WebInspector.InlineSwatch.Event.Activated); + + let value = this._value || this._fallbackValue(); + if (this._type === WebInspector.InlineSwatch.Type.Color) + this._valueEditor.color = value; + else if (this._type === WebInspector.InlineSwatch.Type.Gradient) + this._valueEditor.gradient = value; + else 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.Variable) + this._valueEditor.codeMirror.setValue(value); + } + + _valueEditorValueDidChange(event) + { + if (this._type === WebInspector.InlineSwatch.Type.Color) + this._value = event.data.color; + else if (this._type === WebInspector.InlineSwatch.Type.Gradient) + this._value = event.data.gradient; + else 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; + + 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", + Variable: "inline-swatch-type-variable", +}; + +WebInspector.InlineSwatch.Event = { + BeforeClicked: "inline-swatch-before-clicked", + ValueChanged: "inline-swatch-value-changed", + Activated: "inline-swatch-activated", + Deactivated: "inline-swatch-deactivated", +}; |