blob: 1f09c124c9b17abd9ca923c93794ddbdad6c7076 [file] [log] [blame]
// Copyright (c) 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @constructor
* @extends {WebInspector.Object}
*/
WebInspector.StylesPopoverHelper = function()
{
this._popover = new WebInspector.Popover();
this._popover.setCanShrink(false);
this._popover.setNoMargins(true);
this._popover.element.addEventListener("mousedown", consumeEvent, false);
this._hideProxy = this.hide.bind(this, true);
this._boundOnKeyDown = this._onKeyDown.bind(this);
this._repositionBound = this.reposition.bind(this);
this._boundFocusOut = this._onFocusOut.bind(this);
}
WebInspector.StylesPopoverHelper.prototype = {
/**
* @param {!Event} event
*/
_onFocusOut: function(event)
{
if (!event.relatedTarget || event.relatedTarget.isSelfOrDescendant(this._view.contentElement))
return;
this._hideProxy();
},
/**
* @return {boolean}
*/
isShowing: function()
{
return this._popover.isShowing();
},
/**
* @param {!WebInspector.Widget} view
* @param {!Element} anchorElement
* @param {function(boolean)=} hiddenCallback
*/
show: function(view, anchorElement, hiddenCallback)
{
if (this._popover.isShowing()) {
if (this._anchorElement === anchorElement)
return;
// Reopen the picker for another anchor element.
this.hide(true);
}
delete this._isHidden;
this._anchorElement = anchorElement;
this._view = view;
this._hiddenCallback = hiddenCallback;
this.reposition();
var document = this._popover.element.ownerDocument;
document.addEventListener("mousedown", this._hideProxy, false);
document.defaultView.addEventListener("resize", this._hideProxy, false);
this._view.contentElement.addEventListener("keydown", this._boundOnKeyDown, false);
this._scrollerElement = anchorElement.enclosingNodeOrSelfWithClass("style-panes-wrapper");
if (this._scrollerElement)
this._scrollerElement.addEventListener("scroll", this._repositionBound, false);
},
/**
* @param {!Event=} event
*/
reposition: function(event)
{
if (!this._previousFocusElement)
this._previousFocusElement = WebInspector.currentFocusElement();
// Unbind "blur" listener to avoid reenterability: |popover.showView| will hide the popover and trigger it synchronously.
this._view.contentElement.removeEventListener("focusout", this._boundFocusOut, false);
this._popover.showView(this._view, this._anchorElement);
this._view.contentElement.addEventListener("focusout", this._boundFocusOut, false);
WebInspector.setCurrentFocusElement(this._view.contentElement);
},
/**
* @param {boolean=} commitEdit
*/
hide: function(commitEdit)
{
if (this._isHidden)
return;
var document = this._popover.element.ownerDocument;
this._isHidden = true;
this._popover.hide();
if (this._scrollerElement)
this._scrollerElement.removeEventListener("scroll", this._repositionBound, false);
document.removeEventListener("mousedown", this._hideProxy, false);
document.defaultView.removeEventListener("resize", this._hideProxy, false);
if (this._hiddenCallback)
this._hiddenCallback.call(null, !!commitEdit);
WebInspector.setCurrentFocusElement(this._previousFocusElement);
delete this._previousFocusElement;
delete this._anchorElement;
if (this._view) {
this._view.detach();
this._view.contentElement.removeEventListener("keydown", this._boundOnKeyDown, false);
this._view.contentElement.removeEventListener("focusout", this._boundFocusOut, false);
delete this._view;
}
},
/**
* @param {!Event} event
*/
_onKeyDown: function(event)
{
if (event.key === "Enter") {
this.hide(true);
event.consume(true);
return;
}
if (event.key === "Escape") {
this.hide(false);
event.consume(true);
}
},
__proto__: WebInspector.Object.prototype
}
/**
* @constructor
* @param {!WebInspector.StylePropertyTreeElement} treeElement
* @param {!WebInspector.StylesPopoverHelper} stylesPopoverHelper
* @param {string} text
*/
WebInspector.BezierPopoverIcon = function(treeElement, stylesPopoverHelper, text)
{
this._treeElement = treeElement;
this._stylesPopoverHelper = stylesPopoverHelper;
this._createDOM(text);
this._boundBezierChanged = this._bezierChanged.bind(this);
}
WebInspector.BezierPopoverIcon.prototype = {
/**
* @return {!Element}
*/
element: function()
{
return this._element;
},
/**
* @param {string} text
*/
_createDOM: function(text)
{
this._element = createElement("nobr");
this._element.title = WebInspector.UIString("Open cubic bezier editor");
this._iconElement = this._element.createChild("div", "popover-icon bezier-icon");
var svg = this._iconElement.createSVGChild("svg");
svg.setAttribute("height", 10);
svg.setAttribute("width", 10);
this._iconElement.addEventListener("click", this._iconClick.bind(this), false);
var g = svg.createSVGChild("g");
var path = g.createSVGChild("path");
path.setAttribute("d", "M2,8 C2,3 8,7 8,2");
this._bezierValueElement = this._element.createChild("span");
this._bezierValueElement.textContent = text;
},
/**
* @param {!Event} event
*/
_iconClick: function(event)
{
event.consume(true);
if (this._stylesPopoverHelper.isShowing()) {
this._stylesPopoverHelper.hide(true);
return;
}
this._bezierEditor = new WebInspector.BezierEditor();
var geometry = WebInspector.Geometry.CubicBezier.parse(this._bezierValueElement.textContent);
this._bezierEditor.setBezier(geometry);
this._bezierEditor.addEventListener(WebInspector.BezierEditor.Events.BezierChanged, this._boundBezierChanged);
this._stylesPopoverHelper.show(this._bezierEditor, this._iconElement, this._onPopoverHidden.bind(this));
this._originalPropertyText = this._treeElement.property.propertyText;
this._treeElement.parentPane().setEditingStyle(true);
var uiLocation = WebInspector.cssWorkspaceBinding.propertyUILocation(this._treeElement.property, false /* forName */);
if (uiLocation)
WebInspector.Revealer.reveal(uiLocation, true /* omitFocus */);
},
/**
* @param {!WebInspector.Event} event
*/
_bezierChanged: function(event)
{
this._bezierValueElement.textContent = /** @type {string} */ (event.data);
this._treeElement.applyStyleText(this._treeElement.renderedPropertyText(), false);
},
/**
* @param {boolean} commitEdit
*/
_onPopoverHidden: function(commitEdit)
{
this._bezierEditor.removeEventListener(WebInspector.BezierEditor.Events.BezierChanged, this._boundBezierChanged);
delete this._bezierEditor;
var propertyText = commitEdit ? this._treeElement.renderedPropertyText() : this._originalPropertyText;
this._treeElement.applyStyleText(propertyText, true);
this._treeElement.parentPane().setEditingStyle(false);
delete this._originalPropertyText;
}
}
/**
* @constructor
* @param {!WebInspector.StylePropertyTreeElement} treeElement
* @param {!WebInspector.StylesPopoverHelper} stylesPopoverHelper
* @param {string} colorText
*/
WebInspector.ColorSwatchPopoverIcon = function(treeElement, stylesPopoverHelper, colorText)
{
this._treeElement = treeElement;
this._treeElement[WebInspector.ColorSwatchPopoverIcon._treeElementSymbol] = this;
this._stylesPopoverHelper = stylesPopoverHelper;
this._swatch = WebInspector.ColorSwatch.create();
this._swatch.setColorText(colorText);
this._swatch.setFormat(WebInspector.Color.detectColorFormat(this._swatch.color()));
var shiftClickMessage = WebInspector.UIString("Shift + Click to change color format.");
this._swatch.iconElement().title = WebInspector.UIString("Open color picker. %s", shiftClickMessage);
this._swatch.iconElement().addEventListener("click", this._iconClick.bind(this));
this._contrastColor = null;
this._boundSpectrumChanged = this._spectrumChanged.bind(this);
}
WebInspector.ColorSwatchPopoverIcon._treeElementSymbol = Symbol("WebInspector.ColorSwatchPopoverIcon._treeElementSymbol");
/**
* @param {!WebInspector.StylePropertyTreeElement} treeElement
* @return {?WebInspector.ColorSwatchPopoverIcon}
*/
WebInspector.ColorSwatchPopoverIcon.forTreeElement = function(treeElement)
{
return treeElement[WebInspector.ColorSwatchPopoverIcon._treeElementSymbol] || null;
}
WebInspector.ColorSwatchPopoverIcon.prototype = {
/**
* @return {!Element}
*/
element: function()
{
return this._swatch;
},
/**
* @param {!WebInspector.Color} color
*/
setContrastColor: function(color)
{
this._contrastColor = color;
if (this._spectrum)
this._spectrum.setContrastColor(this._contrastColor);
},
/**
* @param {!Event} event
*/
_iconClick: function(event)
{
event.consume(true);
this.showPopover();
},
showPopover: function()
{
if (this._stylesPopoverHelper.isShowing()) {
this._stylesPopoverHelper.hide(true);
return;
}
var color = this._swatch.color();
var format = this._swatch.format();
if (format === WebInspector.Color.Format.Original)
format = color.format();
this._spectrum = new WebInspector.Spectrum();
this._spectrum.setColor(color, format);
if (this._contrastColor)
this._spectrum.setContrastColor(this._contrastColor);
this._spectrum.addEventListener(WebInspector.Spectrum.Events.SizeChanged, this._spectrumResized, this);
this._spectrum.addEventListener(WebInspector.Spectrum.Events.ColorChanged, this._boundSpectrumChanged);
this._stylesPopoverHelper.show(this._spectrum, this._swatch.iconElement(), this._onPopoverHidden.bind(this));
this._originalPropertyText = this._treeElement.property.propertyText;
this._treeElement.parentPane().setEditingStyle(true);
var uiLocation = WebInspector.cssWorkspaceBinding.propertyUILocation(this._treeElement.property, false /* forName */);
if (uiLocation)
WebInspector.Revealer.reveal(uiLocation, true /* omitFocus */);
},
/**
* @param {!WebInspector.Event} event
*/
_spectrumResized: function(event)
{
this._stylesPopoverHelper.reposition();
},
/**
* @param {!WebInspector.Event} event
*/
_spectrumChanged: function(event)
{
var colorString = /** @type {string} */ (event.data);
this._swatch.setColorText(colorString);
this._treeElement.applyStyleText(this._treeElement.renderedPropertyText(), false);
},
/**
* @param {boolean} commitEdit
*/
_onPopoverHidden: function(commitEdit)
{
this._spectrum.removeEventListener(WebInspector.Spectrum.Events.ColorChanged, this._boundSpectrumChanged);
delete this._spectrum;
var propertyText = commitEdit ? this._treeElement.renderedPropertyText() : this._originalPropertyText;
this._treeElement.applyStyleText(propertyText, true);
this._treeElement.parentPane().setEditingStyle(false);
delete this._originalPropertyText;
}
}