Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / devtools / front_end / elements / StylesPopoverHelper.js
blob95e32e36df668e1edf88c268fd1d8f2c1bc5fe61
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 /**
6  * @constructor
7  * @extends {WebInspector.Object}
8  */
9 WebInspector.StylesPopoverHelper = function()
11     this._popover = new WebInspector.Popover();
12     this._popover.setCanShrink(false);
13     this._popover.setNoMargins(true);
14     this._popover.element.addEventListener("mousedown", consumeEvent, false);
16     this._hideProxy = this.hide.bind(this, true);
17     this._boundOnKeyDown = this._onKeyDown.bind(this);
18     this._repositionBound = this.reposition.bind(this);
19     this._boundFocusOut = this._onFocusOut.bind(this);
22 WebInspector.StylesPopoverHelper.prototype = {
23     /**
24      * @param {!Event} event
25      */
26     _onFocusOut: function(event)
27     {
28         if (!event.relatedTarget || event.relatedTarget.isSelfOrDescendant(this._view.contentElement))
29             return;
30         this._hideProxy();
31     },
33     /**
34      * @return {boolean}
35      */
36     isShowing: function()
37     {
38         return this._popover.isShowing();
39     },
41     /**
42      * @param {!WebInspector.Widget} view
43      * @param {!Element} anchorElement
44      * @param {function(boolean)=} hiddenCallback
45      */
46     show: function(view, anchorElement, hiddenCallback)
47     {
48         if (this._popover.isShowing()) {
49             if (this._anchorElement === anchorElement)
50                 return;
52             // Reopen the picker for another anchor element.
53             this.hide(true);
54         }
56         delete this._isHidden;
57         this._anchorElement = anchorElement;
58         this._view = view;
59         this._hiddenCallback = hiddenCallback;
60         this.reposition();
62         var document = this._popover.element.ownerDocument;
63         document.addEventListener("mousedown", this._hideProxy, false);
64         document.defaultView.addEventListener("resize", this._hideProxy, false);
65         this._view.contentElement.addEventListener("keydown", this._boundOnKeyDown, false);
67         this._scrollerElement = anchorElement.enclosingNodeOrSelfWithClass("style-panes-wrapper");
68         if (this._scrollerElement)
69             this._scrollerElement.addEventListener("scroll", this._repositionBound, false);
70     },
72     /**
73      * @param {!Event=} event
74      */
75     reposition: function(event)
76     {
77         if (!this._previousFocusElement)
78             this._previousFocusElement = WebInspector.currentFocusElement();
79         // Unbind "blur" listener to avoid reenterability: |popover.showView| will hide the popover and trigger it synchronously.
80         this._view.contentElement.removeEventListener("focusout", this._boundFocusOut, false);
81         this._popover.showView(this._view, this._anchorElement);
82         this._view.contentElement.addEventListener("focusout", this._boundFocusOut, false);
83         WebInspector.setCurrentFocusElement(this._view.contentElement);
84     },
86     /**
87      * @param {boolean=} commitEdit
88      */
89     hide: function(commitEdit)
90     {
91         if (this._isHidden)
92             return;
93         var document = this._popover.element.ownerDocument;
94         this._isHidden = true;
95         this._popover.hide();
97         if (this._scrollerElement)
98             this._scrollerElement.removeEventListener("scroll", this._repositionBound, false);
100         document.removeEventListener("mousedown", this._hideProxy, false);
101         document.defaultView.removeEventListener("resize", this._hideProxy, false);
103         if (this._hiddenCallback)
104             this._hiddenCallback.call(null, !!commitEdit);
106         WebInspector.setCurrentFocusElement(this._previousFocusElement);
107         delete this._previousFocusElement;
108         delete this._anchorElement;
109         if (this._view) {
110             this._view.detach();
111             this._view.contentElement.removeEventListener("keydown", this._boundOnKeyDown, false);
112             this._view.contentElement.removeEventListener("focusout", this._boundFocusOut, false);
113             delete this._view;
114         }
115     },
117     /**
118      * @param {!Event} event
119      */
120     _onKeyDown: function(event)
121     {
122         if (event.keyIdentifier === "Enter") {
123             this.hide(true);
124             event.consume(true);
125             return;
126         }
127         if (event.keyIdentifier === "U+001B") { // Escape key
128             this.hide(false);
129             event.consume(true);
130         }
131     },
133     __proto__: WebInspector.Object.prototype
137  * @constructor
138  * @param {!WebInspector.StylePropertyTreeElement} treeElement
139  * @param {!WebInspector.StylesPopoverHelper} stylesPopoverHelper
140  * @param {string} text
141  */
142 WebInspector.BezierPopoverIcon = function(treeElement, stylesPopoverHelper, text)
144     this._treeElement = treeElement;
145     this._stylesPopoverHelper = stylesPopoverHelper;
146     this._createDOM(text);
148     this._boundBezierChanged = this._bezierChanged.bind(this);
151 WebInspector.BezierPopoverIcon.prototype = {
152     /**
153      * @return {!Element}
154      */
155     element: function()
156     {
157         return this._element;
158     },
160     /**
161      * @param {string} text
162      */
163     _createDOM: function(text)
164     {
165         this._element = createElement("nobr");
166         this._element.title = WebInspector.UIString("Open cubic bezier editor");
168         this._iconElement = this._element.createSVGChild("svg", "popover-icon bezier-icon");
169         this._iconElement.setAttribute("height", 10);
170         this._iconElement.setAttribute("width", 10);
171         this._iconElement.addEventListener("click", this._iconClick.bind(this), false);
172         var g = this._iconElement.createSVGChild("g");
173         var path = g.createSVGChild("path");
174         path.setAttribute("d", "M2,8 C2,3 8,7 8,2");
176         this._bezierValueElement = this._element.createChild("span");
177         this._bezierValueElement.textContent = text;
178     },
180     /**
181      * @param {!Event} event
182      */
183     _iconClick: function(event)
184     {
185         event.consume(true);
186         if (this._stylesPopoverHelper.isShowing()) {
187             this._stylesPopoverHelper.hide(true);
188             return;
189         }
191         this._bezierEditor = new WebInspector.BezierEditor();
192         var geometry = WebInspector.Geometry.CubicBezier.parse(this._bezierValueElement.textContent);
193         this._bezierEditor.setBezier(geometry);
194         this._bezierEditor.addEventListener(WebInspector.BezierEditor.Events.BezierChanged, this._boundBezierChanged);
195         this._stylesPopoverHelper.show(this._bezierEditor, this._iconElement, this._onPopoverHidden.bind(this));
197         this._originalPropertyText = this._treeElement.property.propertyText;
198         this._treeElement.parentPane().setEditingStyle(true);
199     },
201     /**
202      * @param {!WebInspector.Event} event
203      */
204     _bezierChanged: function(event)
205     {
206         this._bezierValueElement.textContent = /** @type {string} */ (event.data);
207         this._treeElement.applyStyleText(this._treeElement.renderedPropertyText(), false);
208     },
210     /**
211      * @param {boolean} commitEdit
212      */
213     _onPopoverHidden: function(commitEdit)
214     {
215         this._bezierEditor.removeEventListener(WebInspector.BezierEditor.Events.BezierChanged, this._boundBezierChanged);
216         delete this._bezierEditor;
218         var propertyText = commitEdit ? this._treeElement.renderedPropertyText() : this._originalPropertyText;
219         this._treeElement.applyStyleText(propertyText, true);
220         this._treeElement.parentPane().setEditingStyle(false);
221         delete this._originalPropertyText;
222     }
226  * @constructor
227  * @param {!WebInspector.StylePropertyTreeElement} treeElement
228  * @param {!WebInspector.StylesPopoverHelper} stylesPopoverHelper
229  * @param {string} colorText
230  */
231 WebInspector.ColorSwatchPopoverIcon = function(treeElement, stylesPopoverHelper, colorText)
233     this._treeElement = treeElement;
234     this._stylesPopoverHelper = stylesPopoverHelper;
236     this._swatch = WebInspector.ColorSwatch.create();
237     this._swatch.setColorText(colorText);
238     this._swatch.setFormat(WebInspector.ColorSwatchPopoverIcon._colorFormat(this._swatch.color()));
239     var shiftClickMessage = WebInspector.UIString("Shift + Click to change color format.");
240     this._swatch.iconElement().title = WebInspector.UIString("Open color picker. %s", shiftClickMessage);
241     this._swatch.iconElement().addEventListener("click", this._iconClick.bind(this));
242     this._contrastColor = null;
244     this._boundSpectrumChanged = this._spectrumChanged.bind(this);
248  * @param {!WebInspector.Color} color
249  * @return {!WebInspector.Color.Format}
250  */
251 WebInspector.ColorSwatchPopoverIcon._colorFormat = function(color)
253     const cf = WebInspector.Color.Format;
254     var format;
255     var formatSetting = WebInspector.moduleSetting("colorFormat").get();
256     if (formatSetting === cf.Original)
257         format = cf.Original;
258     else if (formatSetting === cf.RGB)
259         format = (color.hasAlpha() ? cf.RGBA : cf.RGB);
260     else if (formatSetting === cf.HSL)
261         format = (color.hasAlpha() ? cf.HSLA : cf.HSL);
262     else if (!color.hasAlpha())
263         format = (color.canBeShortHex() ? cf.ShortHEX : cf.HEX);
264     else
265         format = cf.RGBA;
267     return format;
270 WebInspector.ColorSwatchPopoverIcon.prototype = {
271     /**
272      * @return {!Element}
273      */
274     element: function()
275     {
276         return this._swatch;
277     },
279     /**
280      * @param {!WebInspector.Color} color
281      */
282     setContrastColor: function(color)
283     {
284         this._contrastColor = color;
285         if (this._spectrum)
286             this._spectrum.setContrastColor(this._contrastColor);
287     },
289     /**
290      * @param {!Event} event
291      */
292     _iconClick: function(event)
293     {
294         event.consume(true);
295         if (this._stylesPopoverHelper.isShowing()) {
296             this._stylesPopoverHelper.hide(true);
297             return;
298         }
300         var color = this._swatch.color();
301         var format = this._swatch.format();
302         if (format === WebInspector.Color.Format.Original)
303             format = color.format();
304         this._spectrum = new WebInspector.Spectrum();
305         this._spectrum.setColor(color, format);
306         if (this._contrastColor)
307             this._spectrum.setContrastColor(this._contrastColor);
309         this._spectrum.addEventListener(WebInspector.Spectrum.Events.SizeChanged, this._spectrumResized, this);
310         this._spectrum.addEventListener(WebInspector.Spectrum.Events.ColorChanged, this._boundSpectrumChanged);
311         this._stylesPopoverHelper.show(this._spectrum, this._swatch.iconElement(), this._onPopoverHidden.bind(this));
313         this._originalPropertyText = this._treeElement.property.propertyText;
314         this._treeElement.parentPane().setEditingStyle(true);
315     },
317     /**
318      * @param {!WebInspector.Event} event
319      */
320     _spectrumResized: function(event)
321     {
322         this._stylesPopoverHelper.reposition();
323     },
325     /**
326      * @param {!WebInspector.Event} event
327      */
328     _spectrumChanged: function(event)
329     {
330         var colorString = /** @type {string} */ (event.data);
331         this._swatch.setColorText(colorString);
332         this._treeElement.applyStyleText(this._treeElement.renderedPropertyText(), false);
333     },
335     /**
336      * @param {boolean} commitEdit
337      */
338     _onPopoverHidden: function(commitEdit)
339     {
340         this._spectrum.removeEventListener(WebInspector.Spectrum.Events.ColorChanged, this._boundSpectrumChanged);
341         delete this._spectrum;
343         var propertyText = commitEdit ? this._treeElement.renderedPropertyText() : this._originalPropertyText;
344         this._treeElement.applyStyleText(propertyText, true);
345         this._treeElement.parentPane().setEditingStyle(false);
346         delete this._originalPropertyText;
347     }