Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / elements / Spectrum.js
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  * @constructor
31  * @extends {WebInspector.VBox}
32  */
33 WebInspector.Spectrum = function()
34 {
35     WebInspector.VBox.call(this, true);
36     this.contentElement.appendChild(WebInspector.View.createStyleElement("elements/spectrum.css"));
37     this.contentElement.tabIndex = 0;
38
39     this._draggerElement = this.contentElement.createChild("div", "spectrum-color");
40     this._dragHelperElement = this._draggerElement.createChild("div", "spectrum-sat fill").createChild("div", "spectrum-val fill").createChild("div", "spectrum-dragger");
41
42     this._sliderElement = this.contentElement.createChild("div", "spectrum-hue");
43     this.slideHelper = this._sliderElement.createChild("div", "spectrum-slider");
44
45     var rangeContainer = this.contentElement.createChild("div", "spectrum-range-container");
46     var alphaLabel = rangeContainer.createChild("label");
47     alphaLabel.textContent = WebInspector.UIString("\u03B1:");
48
49     this._alphaElement = rangeContainer.createChild("input", "spectrum-range");
50     this._alphaElement.setAttribute("type", "range");
51     this._alphaElement.setAttribute("min", "0");
52     this._alphaElement.setAttribute("max", "100");
53     this._alphaElement.addEventListener("input", alphaDrag.bind(this), false);
54     this._alphaElement.addEventListener("change", alphaDrag.bind(this), false);
55
56     var displayContainer = this.contentElement.createChild("div", "spectrum-text");
57     var swatchElement = displayContainer.createChild("span", "swatch");
58     this._swatchInnerElement = swatchElement.createChild("span", "swatch-inner");
59     this._displayElement = displayContainer.createChild("span", "source-code spectrum-display-value");
60
61     WebInspector.Spectrum.draggable(this._sliderElement, hueDrag.bind(this));
62     WebInspector.Spectrum.draggable(this._draggerElement, colorDrag.bind(this), colorDragStart.bind(this));
63
64     /**
65      * @param {!Element} element
66      * @param {number} dragX
67      * @param {number} dragY
68      * @this {WebInspector.Spectrum}
69      */
70     function hueDrag(element, dragX, dragY)
71     {
72         this._hsv[0] = (this.slideHeight - dragY) / this.slideHeight;
73
74         this._onchange();
75     }
76
77     var initialHelperOffset;
78
79     /**
80      * @this {WebInspector.Spectrum}
81      */
82     function colorDragStart()
83     {
84         initialHelperOffset = { x: this._dragHelperElement.offsetLeft, y: this._dragHelperElement.offsetTop };
85     }
86
87     /**
88      * @param {!Element} element
89      * @param {number} dragX
90      * @param {number} dragY
91      * @param {!MouseEvent} event
92      * @this {WebInspector.Spectrum}
93      */
94     function colorDrag(element, dragX, dragY, event)
95     {
96         if (event.shiftKey) {
97             if (Math.abs(dragX - initialHelperOffset.x) >= Math.abs(dragY - initialHelperOffset.y))
98                 dragY = initialHelperOffset.y;
99             else
100                 dragX = initialHelperOffset.x;
101         }
102
103         this._hsv[1] = dragX / this.dragWidth;
104         this._hsv[2] = (this.dragHeight - dragY) / this.dragHeight;
105
106         this._onchange();
107     }
108
109     /**
110      * @this {WebInspector.Spectrum}
111      */
112     function alphaDrag()
113     {
114         this._hsv[3] = this._alphaElement.value / 100;
115
116         this._onchange();
117     }
118 };
119
120 WebInspector.Spectrum.Events = {
121     ColorChanged: "ColorChanged"
122 };
123
124 /**
125  * @param {!Element} element
126  * @param {function(!Element, number, number, !MouseEvent)=} onmove
127  * @param {function(!Element, !MouseEvent)=} onstart
128  * @param {function(!Element, !MouseEvent)=} onstop
129  */
130 WebInspector.Spectrum.draggable = function(element, onmove, onstart, onstop) {
131
132     var dragging;
133     var offset;
134     var scrollOffset;
135     var maxHeight;
136     var maxWidth;
137
138     /**
139      * @param {!Event} e
140      */
141     function consume(e)
142     {
143         e.consume(true);
144     }
145
146     /**
147      * @param {!Event} e
148      */
149     function move(e)
150     {
151         if (dragging) {
152             var dragX = Math.max(0, Math.min(e.pageX - offset.left + scrollOffset.left, maxWidth));
153             var dragY = Math.max(0, Math.min(e.pageY - offset.top + scrollOffset.top, maxHeight));
154
155             if (onmove)
156                 onmove(element, dragX, dragY, /** @type {!MouseEvent} */ (e));
157         }
158     }
159
160     /**
161      * @param {!Event} e
162      */
163     function start(e)
164     {
165         var mouseEvent = /** @type {!MouseEvent} */ (e);
166         var rightClick = mouseEvent.which ? (mouseEvent.which === 3) : (mouseEvent.button === 2);
167
168         if (!rightClick && !dragging) {
169
170             if (onstart)
171                 onstart(element, mouseEvent);
172
173             dragging = true;
174             maxHeight = element.clientHeight;
175             maxWidth = element.clientWidth;
176
177             scrollOffset = element.scrollOffset();
178             offset = element.totalOffset();
179
180             element.ownerDocument.addEventListener("selectstart", consume, false);
181             element.ownerDocument.addEventListener("dragstart", consume, false);
182             element.ownerDocument.addEventListener("mousemove", move, false);
183             element.ownerDocument.addEventListener("mouseup", stop, false);
184
185             move(mouseEvent);
186             consume(mouseEvent);
187         }
188     }
189
190     /**
191      * @param {!Event} e
192      */
193     function stop(e)
194     {
195         if (dragging) {
196             element.ownerDocument.removeEventListener("selectstart", consume, false);
197             element.ownerDocument.removeEventListener("dragstart", consume, false);
198             element.ownerDocument.removeEventListener("mousemove", move, false);
199             element.ownerDocument.removeEventListener("mouseup", stop, false);
200
201             if (onstop)
202                 onstop(element, /** @type {!MouseEvent} */ (e));
203         }
204
205         dragging = false;
206     }
207
208     element.addEventListener("mousedown", start, false);
209 };
210
211 WebInspector.Spectrum.prototype = {
212     /**
213      * @param {!WebInspector.Color} color
214      */
215     setColor: function(color)
216     {
217         this._hsv = color.hsva();
218     },
219
220     /**
221      * @return {!WebInspector.Color}
222      */
223     color: function()
224     {
225         return WebInspector.Color.fromHSVA(this._hsv);
226     },
227
228     _colorString: function()
229     {
230         var cf = WebInspector.Color.Format;
231         var format = this._originalFormat;
232         var color = this.color();
233         var originalFormatString = color.toString(this._originalFormat);
234         if (originalFormatString)
235             return originalFormatString;
236
237         if (color.hasAlpha()) {
238             // Everything except HSL(A) should be returned as RGBA if transparency is involved.
239             if (format === cf.HSLA || format === cf.HSL)
240                 return color.toString(cf.HSLA);
241             else
242                 return color.toString(cf.RGBA);
243         }
244
245         if (format === cf.ShortHEX)
246             return color.toString(cf.HEX);
247         console.assert(format === cf.Nickname);
248         return color.toString(cf.RGB);
249     },
250
251
252     set displayText(text)
253     {
254         this._displayElement.textContent = text;
255     },
256
257     _onchange: function()
258     {
259         this._updateUI();
260         this.dispatchEventToListeners(WebInspector.Spectrum.Events.ColorChanged, this._colorString());
261     },
262
263     _updateHelperLocations: function()
264     {
265         var h = this._hsv[0];
266         var s = this._hsv[1];
267         var v = this._hsv[2];
268
269         // Where to show the little circle that displays your current selected color.
270         var dragX = s * this.dragWidth;
271         var dragY = this.dragHeight - (v * this.dragHeight);
272
273         dragX = Math.max(-this._dragHelperElementHeight,
274                         Math.min(this.dragWidth - this._dragHelperElementHeight, dragX - this._dragHelperElementHeight));
275         dragY = Math.max(-this._dragHelperElementHeight,
276                         Math.min(this.dragHeight - this._dragHelperElementHeight, dragY - this._dragHelperElementHeight));
277
278         this._dragHelperElement.positionAt(dragX, dragY);
279
280         // Where to show the bar that displays your current selected hue.
281         var slideY = this.slideHeight - ((h * this.slideHeight) + this.slideHelperHeight);
282         this.slideHelper.style.top = slideY + "px";
283
284         this._alphaElement.value = this._hsv[3] * 100;
285     },
286
287     _updateUI: function()
288     {
289         this._updateHelperLocations();
290
291         this._draggerElement.style.backgroundColor = /** @type {string} */ (WebInspector.Color.fromHSVA([this._hsv[0], 1, 1, 1]).toString(WebInspector.Color.Format.RGB));
292         this._swatchInnerElement.style.backgroundColor = /** @type {string} */ (this.color().toString(WebInspector.Color.Format.RGBA));
293
294         this._alphaElement.value = this._hsv[3] * 100;
295     },
296
297     wasShown: function()
298     {
299         this.slideHeight = this._sliderElement.offsetHeight;
300         this.dragWidth = this._draggerElement.offsetWidth;
301         this.dragHeight = this._draggerElement.offsetHeight;
302         this._dragHelperElementHeight = this._dragHelperElement.offsetHeight / 2;
303         this.slideHelperHeight = this.slideHelper.offsetHeight / 2;
304         this._updateUI();
305     },
306
307     __proto__: WebInspector.VBox.prototype
308 }
309
310 /**
311  * @constructor
312  * @extends {WebInspector.Object}
313  */
314 WebInspector.SpectrumPopupHelper = function()
315 {
316     this._spectrum = new WebInspector.Spectrum();
317     this._spectrum.contentElement.addEventListener("keydown", this._onKeyDown.bind(this), false);
318
319     this._popover = new WebInspector.Popover();
320     this._popover.setCanShrink(false);
321     this._popover.element.addEventListener("mousedown", consumeEvent, false);
322
323     this._hideProxy = this.hide.bind(this, true);
324 }
325
326 WebInspector.SpectrumPopupHelper.Events = {
327     Hidden: "Hidden"
328 };
329
330 WebInspector.SpectrumPopupHelper.prototype = {
331     /**
332      * @return {!WebInspector.Spectrum}
333      */
334     spectrum: function()
335     {
336         return this._spectrum;
337     },
338
339     /**
340      * @return {boolean}
341      */
342     toggle: function(element, color, format)
343     {
344         if (this._popover.isShowing())
345             this.hide(true);
346         else
347             this.show(element, color, format);
348
349         return this._popover.isShowing();
350     },
351
352     /**
353      * @return {boolean}
354      */
355     show: function(element, color, format)
356     {
357         if (this._popover.isShowing()) {
358             if (this._anchorElement === element)
359                 return false;
360
361             // Reopen the picker for another anchor element.
362             this.hide(true);
363         }
364
365         delete this._isHidden;
366         this._anchorElement = element;
367
368         this._spectrum.setColor(color);
369         this._spectrum._originalFormat = format !== WebInspector.Color.Format.Original ? format : color.format();
370         this.reposition(element);
371
372         var document = this._popover.element.ownerDocument;
373         document.addEventListener("mousedown", this._hideProxy, false);
374         document.defaultView.addEventListener("resize", this._hideProxy, false);
375
376         WebInspector.targetManager.addModelListener(WebInspector.ResourceTreeModel, WebInspector.ResourceTreeModel.EventTypes.ColorPicked, this._colorPicked, this);
377         PageAgent.setColorPickerEnabled(true);
378         return true;
379     },
380
381     reposition: function(element)
382     {
383         if (!this._previousFocusElement)
384             this._previousFocusElement = WebInspector.currentFocusElement();
385         this._popover.showView(this._spectrum, element);
386         WebInspector.setCurrentFocusElement(this._spectrum.contentElement);
387     },
388
389     /**
390      * @param {boolean=} commitEdit
391      */
392     hide: function(commitEdit)
393     {
394         if (this._isHidden)
395             return;
396         var document = this._popover.element.ownerDocument;
397         this._isHidden = true;
398         this._popover.hide();
399
400         document.removeEventListener("mousedown", this._hideProxy, false);
401         document.defaultView.removeEventListener("resize", this._hideProxy, false);
402
403         PageAgent.setColorPickerEnabled(false);
404         WebInspector.targetManager.removeModelListener(WebInspector.ResourceTreeModel, WebInspector.ResourceTreeModel.EventTypes.ColorPicked, this._colorPicked, this);
405
406         this.dispatchEventToListeners(WebInspector.SpectrumPopupHelper.Events.Hidden, !!commitEdit);
407
408         WebInspector.setCurrentFocusElement(this._previousFocusElement);
409         delete this._previousFocusElement;
410
411         delete this._anchorElement;
412     },
413
414     _onKeyDown: function(event)
415     {
416         if (event.keyIdentifier === "Enter") {
417             this.hide(true);
418             event.consume(true);
419             return;
420         }
421         if (event.keyIdentifier === "U+001B") { // Escape key
422             this.hide(false);
423             event.consume(true);
424         }
425     },
426
427     /**
428      * @param {!WebInspector.Event} event
429      */
430     _colorPicked: function(event)
431     {
432         var color = /** @type {!DOMAgent.RGBA} */ (event.data);
433         var rgba = [color.r, color.g, color.b, (color.a / 2.55 | 0) / 100];
434         this._spectrum.setColor(WebInspector.Color.fromRGBA(rgba));
435         this._spectrum._onchange();
436         InspectorFrontendHost.bringToFront();
437     },
438
439     __proto__: WebInspector.Object.prototype
440 }
441
442 /**
443  * @constructor
444  * @param {boolean=} readOnly
445  */
446 WebInspector.ColorSwatch = function(readOnly)
447 {
448     this.element = createElementWithClass("span", "swatch");
449     this._swatchInnerElement = this.element.createChild("span", "swatch-inner");
450     var shiftClickMessage = WebInspector.UIString("Shift-click to change color format.");
451     this.element.title = readOnly ? shiftClickMessage : String.sprintf("%s\n%s", WebInspector.UIString("Click to open a colorpicker."), shiftClickMessage);
452     this.element.addEventListener("mousedown", consumeEvent, false);
453     this.element.addEventListener("dblclick", consumeEvent, false);
454 }
455
456 WebInspector.ColorSwatch.prototype = {
457     /**
458      * @param {string} colorString
459      */
460     setColorString: function(colorString)
461     {
462         this._swatchInnerElement.style.backgroundColor = colorString;
463     }
464 }