1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2013, 2014, 2015, 2016 Synacor, Inc.
  5  *
  6  * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at: https://www.zimbra.com/license
  9  * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15
 10  * have been added to cover use of software over a computer network and provide for limited attribution
 11  * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B.
 12  *
 13  * Software distributed under the License is distributed on an "AS IS" basis,
 14  * WITHOUT WARRANTY OF ANY KIND, either express or implied.
 15  * See the License for the specific language governing rights and limitations under the License.
 16  * The Original Code is Zimbra Open Source Web Client.
 17  * The Initial Developer of the Original Code is Zimbra, Inc.  All rights to the Original Code were
 18  * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015.
 19  *
 20  * All portions of the code are Copyright (C) 2006, 2007, 2008, 2009, 2010, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * Creates a button
 26  * @constructor
 27  * @class
 28  * This class ntegrates {@link DwtButton} with a popup {@link DwtColorPicker}. This class is useful to
 29  * present a color picker button with an integrated drop-down for choosing from
 30  * a color palette. You can use addSelectionListener to register a handler
 31  * that will get called when a new color is selected.  Inspect "ev.detail" to
 32  * retrieve the color (guaranteed to be in #RRGGBB format).
 33  * <p>
 34  * The button also features a DIV that displays the currently selected color.
 35  * Upon clicking that DIV, the color will be cleared (in this event, ev.detail
 36  * will be the empty string in your selection listener).  Note you must call
 37  * showColorDisplay() in order for this DIV to be displayed.
 38  * <p>
 39  * All constructor arguments are passed forward to the {@link DwtButton} constructor.
 40  *
 41  * @extends DwtButton
 42  * @author Mihai Bazon
 43  * 
 44  * @param {hash}	params		a hash of parameters
 45  * @param  {DwtComposite}     params.parent		the parent widget
 46  * @param  {constant}     params.style			the button style
 47  * @param  {string}     params.className		the CSS class
 48  * @param  {constant}     params.posStyle		the positioning style
 49  * @param  {string}     params.id			the ID to use for the control's HTML element
 50  * @param  {number}     params.index 		the index at which to add this control among parent's children
 51  * @param  {boolean}     params.allowColorInput if <code>true</code>, allow a text field to allow user to input their customized RGB value
 52  * @param  {boolean}     params.noFillLabel	if <code>true</code>, do not fill label
 53  * 
 54  * @extends		DwtButton
 55  */
 56 DwtButtonColorPicker = function(params) {
 57     if (arguments.length == 0) { return; }
 58 	params = Dwt.getParams(arguments, DwtButtonColorPicker.PARAMS);
 59 	params.actionTiming = DwtButton.ACTION_MOUSEUP;
 60     DwtButton.call(this, params);
 61 
 62 	// WARNING: we pass boolean instead of a DwtDialog because (1) we don't
 63 	// have a dialog right now and (2) DwtMenu doesn't seem to make use of
 64 	// this parameter in other ways than to establish the zIndex.  That's
 65 	// unnecessarily complex :-(
 66 	var m = new DwtMenu({parent:this, style:DwtMenu.COLOR_PICKER_STYLE});
 67 	this.setMenu(m);
 68 	var cp = new DwtColorPicker(m, null, null, params.noFillLabel, params.allowColorInput);
 69 	cp.addSelectionListener(new AjxListener(this, this._colorPicked));
 70     this.__colorPicker = cp ;    //for xform item _DWT_COLORPICKER_
 71 	// no color initially selected
 72 	this.__color = "";
 73 };
 74 
 75 DwtButtonColorPicker.PARAMS = ["parent", "style", "className", "posStyle", "id", "index", "noFillLabel", "allowColorInput"];
 76 
 77 DwtButtonColorPicker.prototype = new DwtButton;
 78 DwtButtonColorPicker.prototype.constructor = DwtButtonColorPicker;
 79 
 80 //
 81 // Constants
 82 //
 83 
 84 DwtButtonColorPicker._RGB_RE = /rgb\(([0-9]{1,3}),\s*([0-9]{1,3}),\s*([0-9]{1,3})\)/;
 85 
 86 DwtButtonColorPicker._hexdigits = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' ];
 87 
 88 //
 89 // Data
 90 //
 91 
 92 //MOW:  DwtButtonColorPicker.prototype.TEMPLATE = "dwt.Widgets#ZButtonColorPicker";
 93 
 94 //
 95 // Public methods
 96 //
 97 
 98 /**
 99  * Utility function that converts the given integer to its hexadecimal representation.
100  *
101  * @param {number}		n 		the number to convert
102  * @param {number}		[pad] 	the number of digits in the final number (zero-padded if required)
103  * @return	{string}	the hexadecimal representation
104  */
105 DwtButtonColorPicker.toHex =
106 function(n, pad) {
107 	var digits = [];
108 	while (n) {
109 		var d = DwtButtonColorPicker._hexdigits[n & 15];
110 		digits.push(d);
111 		n = n >> 4;
112 	}
113 	if (pad != null) {
114 		pad -= digits.length;
115 		while (pad-- > 0)
116 			digits.push('0');
117 	}
118 	digits.reverse();
119 	return digits.join("");
120 };
121 
122 /**
123  * Shows the color display. Call this function to display a DIV that shows the currently
124  * selected color. This DIV also has the ability to clear the current color.
125  * 
126  * @param	{boolean}	disableMouseOver		if <code>true</code>, disable the mouse over
127  */
128 DwtButtonColorPicker.prototype.showColorDisplay =
129 function(disableMouseOver) {
130     if (!this._colorEl) return;
131 
132     if (!disableMouseOver) {
133 		this._colorEl.onmouseover = DwtButtonColorPicker.__colorDisplay_onMouseOver;
134 		this._colorEl.onmouseout = DwtButtonColorPicker.__colorDisplay_onMouseOut;
135 		this._colorEl.onmousedown = DwtButtonColorPicker.__colorDisplay_onMouseDown;
136 	}
137 };
138 
139 /**
140  * Gets the color.
141  * 
142  * @return {string}		the currently selected color
143  */
144 DwtButtonColorPicker.prototype.getColor =
145 function() {
146 	return this.__color;
147 };
148 
149 /**
150  * Set the current color.
151  *
152  * @param {string} color 		the desired color. Pass the empty string "" to clear the selection.
153  */ 
154 DwtButtonColorPicker.prototype.setColor =
155 function(color) {
156 	// let's make sure we keep it in #RRGGBB format
157 	var rgb = color.match(DwtButtonColorPicker._RGB_RE);
158 	if (rgb) {
159 		color = "#" +
160 			DwtButtonColorPicker.toHex(parseInt(rgb[1]), 2) +
161 			DwtButtonColorPicker.toHex(parseInt(rgb[2]), 2) +
162 			DwtButtonColorPicker.toHex(parseInt(rgb[3]), 2);
163 	}
164 	this.__color = color;
165     var colorEl = this._colorEl;
166     if (colorEl)
167 		colorEl.style.backgroundColor = color;
168 };
169 
170 //
171 // Protected methods
172 //
173 
174 DwtButtonColorPicker.prototype._createHtmlFromTemplate = function(templateId, data) {
175     DwtButton.prototype._createHtmlFromTemplate.call(this, templateId, data);
176 
177 	// set the color display bit inside the title of the widget
178 	var displayHtml = AjxTemplate.expand('dwt.Widgets#ZButtonColorDisplay', data);
179 	this.setText(displayHtml);
180 
181     this._colorEl = document.getElementById(data.id+"_color");
182 };
183 
184 
185 // override "_setMinWidth" since that doesn't apply for this type of button
186 DwtButtonColorPicker.prototype._setMinWidth = function() {}
187 
188 
189 /// Protected function that is called when a color is chosen from the popup
190 /// DwtColorPicker.  Sets the current color to the chosen one and calls the
191 /// DwtButton's selection handlers if any.
192 DwtButtonColorPicker.prototype._colorPicked = function(ev) {
193 
194 	var color = ev.detail || '#000000';
195 	this.__color = this.__detail = color;
196     var colorEl = this._colorEl;
197     if (colorEl) {
198 		colorEl.style.backgroundColor = color;
199 	}
200 	if (this.isListenerRegistered(DwtEvent.SELECTION)) {
201 		var selEv = DwtShell.selectionEvent;
202 		// DwtUiEvent.copy(selEv, ev);
203 		selEv.item = this;
204 		selEv.detail = color;
205 		this.notifyListeners(DwtEvent.SELECTION, selEv);
206 	}
207 };
208 
209 //
210 // Private methods
211 //
212 
213 /// When the color display DIV is hovered, we show a small "X" icon to suggest
214 /// the end user that the selected color can be cleared.
215 DwtButtonColorPicker.prototype.__colorDisplay_onMouseOver =
216 function(ev, div) {
217 	if (!this.getEnabled())
218 		return;
219 	Dwt.addClass(div, "ImgDisable");
220 };
221 
222 DwtButtonColorPicker.prototype.__colorDisplay_onMouseOut =
223 function(ev, div) {
224 	if (!this.getEnabled())
225 		return;
226 	Dwt.delClass(div, "ImgDisable");
227 };
228 
229 /// Clears the selected color.  This function is called when the color display
230 /// DIV is clicked.
231 DwtButtonColorPicker.prototype.__colorDisplay_onMouseDown =
232 function(ev, div) {
233 	if (!this.getEnabled())
234 		return;
235 	var dwtev = DwtShell.mouseEvent;
236 	dwtev.setFromDhtmlEvent(ev);
237 	this.__color = this.__detail = div.style.backgroundColor = "";
238 
239  	if (this.isListenerRegistered(DwtEvent.SELECTION)) {
240  		var selEv = DwtShell.selectionEvent;
241  		// DwtUiEvent.copy(selEv, ev);
242  		selEv.item = this;
243  		selEv.detail = "";
244  		this.notifyListeners(DwtEvent.SELECTION, selEv);
245  	}
246 
247 	dwtev._stopPropagation = true;
248 	dwtev._returnValue = false;
249 	dwtev.setToDhtmlEvent(ev);
250 	return false;
251 };
252 
253 // static event dispatchers
254 
255 DwtButtonColorPicker.__colorDisplay_onMouseOver =
256 function(ev) {
257 	var obj = DwtControl.getTargetControl(ev);
258 	obj.__colorDisplay_onMouseOver(ev, this);
259 };
260 
261 DwtButtonColorPicker.__colorDisplay_onMouseOut =
262 function(ev) {
263 	var obj = DwtControl.getTargetControl(ev);
264 	obj.__colorDisplay_onMouseOut(ev, this);
265 };
266 
267 DwtButtonColorPicker.__colorDisplay_onMouseDown =
268 function(ev) {
269 	var obj = DwtControl.getTargetControl(ev);
270 	obj.__colorDisplay_onMouseDown(ev, this);
271 };
272