1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 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, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * Creates a checkbox.
 26  * @constructor
 27  * @class
 28  * This class represents a checkbox.
 29  * 
 30  * @param {hash}	params	a hash of parameters
 31  * @param {DwtComposite}	params.parent	the parent widget
 32  * @param {DwtCheckbox.TEXT_LEFT|DwtCheckbox.TEXT_RIGHT}       [params.style=DwtCheckbox.TEXT_RIGHT] 	the text style
 33  * @param {string}       params.name		the input control name (required for IE)
 34  * @param {string}       params.value     the input control value
 35  * @param {boolean}       params.checked	the input control checked status (required for IE)
 36  * @param {string}       params.className	the CSS class
 37  * @param {constant}       params.posStyle	the positioning style (see {@link Dwt})
 38  * @param {string}       params.id		an explicit ID to use for the control's HTML element
 39  * @param {number}       params.index 	the index at which to add this control among parent's children
 40  * 
 41  *  @extends		DwtControl
 42  */
 43 DwtCheckbox = function(params) {
 44 	if (arguments.length == 0) { return; }
 45 
 46 	params = Dwt.getParams(arguments, DwtCheckbox.PARAMS);
 47 	params.className = params.className || "DwtCheckbox";
 48 
 49 	DwtControl.call(this, params);
 50 
 51 	this._textPosition = DwtCheckbox.DEFAULT_POSITION;
 52 	this._initName = params.name;
 53     this._initValue = params.value;
 54 	this._createHtml();
 55 
 56 	this.setSelected(params.checked);
 57 };
 58 
 59 DwtCheckbox.prototype = new DwtControl;
 60 DwtCheckbox.prototype.constructor = DwtCheckbox;
 61 
 62 DwtCheckbox.prototype.isDwtCheckbox = true;
 63 DwtCheckbox.prototype.isInputControl = true;
 64 DwtCheckbox.prototype.toString = function() { return "DwtCheckbox"; };
 65 
 66 //
 67 // Constants
 68 //
 69 DwtCheckbox.PARAMS = [
 70 	"parent",
 71 	"style",
 72 	"name",
 73 	"checked",
 74 	"className",
 75 	"posStyle",
 76 	"id",
 77 	"index",
 78     "value"
 79 ];
 80 /**
 81  * Defines the "left" text style position.
 82  */
 83 DwtCheckbox.TEXT_LEFT			= "left";
 84 /**
 85  * Defines the "right" text style position.
 86  */
 87 DwtCheckbox.TEXT_RIGHT			= "right";
 88 /**
 89  * Defines the default text style position.
 90  */
 91 DwtCheckbox.DEFAULT_POSITION	= DwtCheckbox.TEXT_RIGHT;
 92 
 93 //
 94 // Data
 95 //
 96 DwtCheckbox.prototype.TEMPLATE = "dwt.Widgets#DwtCheckbox";
 97 
 98 DwtCheckbox.prototype.INPUT_TYPE = 'checkbox';
 99 
100 //
101 // Public methods
102 //
103 DwtCheckbox.prototype.getInputElement =
104 function() {
105 	return this._inputEl;
106 };
107 
108 DwtCheckbox.prototype._focus =
109 function() {
110 	Dwt.addClass(this.getHtmlElement(), DwtControl.FOCUSED);
111 };
112 
113 DwtCheckbox.prototype._blur =
114 function() {
115 	Dwt.delClass(this.getHtmlElement(), DwtControl.FOCUSED);
116 };
117 
118 // listeners
119 
120 /**
121  * Adds a selection listener.
122  * 
123  * @param	{AjxListener}	listener		the listener
124  */
125 DwtCheckbox.prototype.addSelectionListener =
126 function(listener) {
127 	this.addListener(DwtEvent.SELECTION, listener);
128 };
129 
130 /**
131  * Removes a selection listener.
132  * 
133  * @param	{AjxListener}	listener		the listener
134  */
135 DwtCheckbox.prototype.removeSelectionListener =
136 function(listener) {
137 	this.removeListener(DwtEvent.SELECTION, listener);
138 };
139 
140 // properties
141 
142 /**
143  * Sets the enabled state.
144  * 
145  * @param	{boolean}	enabled		if <code>true</code>, the checkbox is enabled
146  */
147 DwtCheckbox.prototype.setEnabled =
148 function(enabled) {
149 	if (enabled != this._enabled) {
150 		DwtControl.prototype.setEnabled.call(this, enabled);
151 		this._inputEl.disabled = !enabled;
152 		var className = enabled ? "Text" : "DisabledText";
153 		if (this._textElLeft) this._textElLeft.className = className;
154 		if (this._textElRight) this._textElRight.className = className;
155 	}
156 };
157 
158 /**
159  * Sets the selected state.
160  * 
161  * @param	{boolean}	selected		if <code>true</code>, the checkbox is selected
162  */
163 DwtCheckbox.prototype.setSelected =
164 function(selected) {
165 	if (this._inputEl && this._inputEl.checked != selected) {
166 		this._inputEl.checked = selected;
167 	}
168 };
169 
170 /**
171  * Checks if the checkbox is selected state.
172  * 
173  * @return	{boolean}	<code>true</code> if the checkbox is selected
174  */
175 DwtCheckbox.prototype.isSelected =
176 function() {
177 	return this._inputEl && this._inputEl.checked;
178 };
179 
180 /**
181  * Sets the checkbox text.
182  * 
183  * @param		{string}	text		the text
184  */
185 DwtCheckbox.prototype.setText =
186 function(text) {
187 	if (this._textEl && this._text != text) {
188 		this._text = text;
189 		this._textEl.innerHTML = text || "";
190 	}
191 };
192 
193 /**
194  * Gets the checkbox text.
195  * 
196  * @return	{string}	the text
197  */
198 DwtCheckbox.prototype.getText =
199 function() {
200 	return this._text;
201 };
202 
203 /**
204  * Sets the text position.
205  * 
206  * @param	{DwtCheckbox.TEXT_LEFT|DwtCheckbox.TEXT_RIGHT}		position	the position
207  */
208 DwtCheckbox.prototype.setTextPosition =
209 function(position) {
210 	this._textEl = position == DwtCheckbox.TEXT_LEFT ? this._textElLeft : this._textElRight;
211 	if (this._textPosition != position) {
212 		this._textPosition = position;
213 		if (this._textElLeft) this._textElLeft.innerHTML = "";
214 		if (this._textElRight) this._textElRight.innerHTML = "";
215 		this.setText(this._text);
216 	}
217 };
218 
219 /**
220  * Gets the text position.
221  * 
222  * @return	{DwtCheckbox.TEXT_LEFT|DwtCheckbox.TEXT_RIGHT}		the position
223  */
224 DwtCheckbox.prototype.getTextPosition =
225 function() {
226 	return this._textPosition;
227 };
228 
229 /**
230  * Sets the value.
231  * 
232  * @param	{string}		value		the value
233  */
234 DwtCheckbox.prototype.setValue =
235 function(value) {
236     var object = this._inputEl || this;
237 	if (object.value !== value) {
238         object.value = value;
239     }
240 };
241 
242 /**
243  * Gets the value.
244  * 
245  * @return		{string}		the value
246  */
247 DwtCheckbox.prototype.getValue =
248 function() {
249     var object = this._inputEl || this;
250 	return object.value != null ? object.value : this.getText();
251 };
252 
253 /**
254  * Gets the input element.
255  * 
256  * @return		{Element}		the element
257  */
258 DwtCheckbox.prototype.getInputElement =
259 function() {
260 	return this._inputEl;
261 };
262 
263 //
264 // DwtControl methods
265 //
266 
267 DwtCheckbox.prototype.setToolTipContent = function(content) {
268     if (content && !this.__mouseEventsSet) {
269         // NOTE: We need mouse events in order to initiate tooltips on hover.
270         // TODO: This should be done transparently in DwtControl for all
271         // TODO: controls with tooltips.
272         this.__mouseEventsSet = true;
273         this._setMouseEvents();
274     }
275     DwtControl.prototype.setToolTipContent.apply(this, arguments);
276 };
277 
278 //
279 // Protected methods
280 //
281 
282 /**
283  * The input field inherits the id for accessibility purposes.
284  * 
285  * @private
286  */
287 DwtCheckbox.prototype._replaceElementHook =
288 function(oel, nel, inheritClass, inheritStyle) {
289 	nel = this.getInputElement();
290 	DwtControl.prototype._replaceElementHook.call(this, oel, nel, inheritClass, inheritStyle);
291 	if (oel.id) {
292 		this.setHtmlElementId(oel.id+"_control");
293 		nel.id = oel.id;
294 		if (this._textEl) {
295 			this._textEl.setAttribute(AjxEnv.isIE ? "htmlFor" : "for", oel.id);
296 		}
297 	}
298 };
299 
300 //
301 // Private methods
302 //
303 
304 DwtCheckbox.prototype._createHtml =
305 function(templateId) {
306 	var data = { id: this._htmlElId };
307 	this._createHtmlFromTemplate(templateId || this.TEMPLATE, data);
308 };
309 
310 DwtCheckbox.prototype._createHtmlFromTemplate =
311 function(templateId, data) {
312 	// NOTE: If  you don't set the name and checked status when
313 	//       creating checkboxes and radio buttons on IE, they will
314 	//       not take the first programmatic value. So we pass in
315 	//       the init values from the constructor.
316 	data.name = this._initName || this._htmlElId;
317     data.value = this._initValue;
318 	data.type = this.INPUT_TYPE;
319 	DwtControl.prototype._createHtmlFromTemplate.call(this, templateId, data);
320 	this._inputEl = document.getElementById(data.id+"_input");
321 	if (this._inputEl) {
322 		var keyboardMgr = DwtShell.getShell(window).getKeyboardMgr();
323 		var handleFocus = AjxCallback.simpleClosure(keyboardMgr.grabFocus, keyboardMgr, this.getInputElement());
324 		Dwt.setHandler(this._inputEl, DwtEvent.ONFOCUS, handleFocus);
325 		Dwt.setHandler(this._inputEl, DwtEvent.ONCLICK, DwtCheckbox.__handleClick);
326 		this.setFocusElement();
327 	}
328 	this._textElLeft = document.getElementById(data.id+"_text_left");
329 	this._textElRight = document.getElementById(data.id+"_text_right");
330 	this.setTextPosition(this._textPosition);
331 };
332 
333 //
334 // Private functions
335 //
336 
337 DwtCheckbox.__handleClick =
338 function(evt) {
339 	var event = DwtUiEvent.getEvent(evt);
340 	var target = DwtUiEvent.getTarget(event);
341 
342 	var selEv = DwtShell.selectionEvent;
343 	DwtUiEvent.copy(selEv, event);
344 	selEv.item = this;
345 	selEv.detail = target.checked;
346 
347 	var checkbox = DwtControl.findControl(target);
348 	checkbox.setSelected(target.checked);
349 	checkbox.focus();
350 	checkbox.notifyListeners(DwtEvent.SELECTION, selEv);
351 };
352