1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2005, 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) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * 
 26  * @private
 27  */
 28 DwtPropertySheet = function(parent, className, posStyle, labelSide) {
 29 	if (arguments.length == 0) return;
 30 	className = className || "DwtPropertySheet";
 31 	DwtComposite.call(this, {parent:parent, className:className, posStyle:posStyle});
 32 
 33 	this._labelSide = labelSide || DwtPropertySheet.DEFAULT;
 34 
 35 	this._propertyIdCount = 0;
 36 	this._propertyList = [];
 37 	this._propertyMap = {};
 38 
 39 	this._tabGroup = new DwtTabGroup(this.toString());
 40 
 41 	this._tableEl = document.createElement("TABLE");
 42 	// Cellspacing needed for IE in quirks mode
 43 	this._tableEl.cellSpacing = 6;
 44 
 45 	var element = this.getHtmlElement();
 46 	element.appendChild(this._tableEl);
 47 	this._setAllowSelection();
 48 }
 49 
 50 DwtPropertySheet.prototype = new DwtComposite;
 51 DwtPropertySheet.prototype.constructor = DwtPropertySheet;
 52 
 53 DwtPropertySheet.prototype.toString = 
 54 function() {
 55 	return "DwtPropertySheet";
 56 }
 57 
 58 // Constants
 59 
 60 DwtPropertySheet.RIGHT = "right";
 61 DwtPropertySheet.LEFT = "left";
 62 DwtPropertySheet.DEFAULT = DwtPropertySheet.LEFT;
 63 
 64 // Data
 65 
 66 DwtPropertySheet.prototype._labelCssClass = "Label";
 67 DwtPropertySheet.prototype._valueCssClass = "Field";
 68 
 69 // Public methods
 70 
 71 /**
 72  * Adds a property.
 73  *
 74  * @param label [string] The property label. The value is used to set the
 75  *				inner HTML of the property label cell.
 76  * @param value The property value. If the value is an instance of DwtControl
 77  *				the element returned by <code>getHtmlElement</code> is used;
 78  *				if the value is an instance of Element, it is added directly;
 79  *				anything else is set as the inner HTML of the property value
 80  *				cell.
 81  * @param required [boolean] Determines if the property should be marked as
 82  *				   required. This is denoted by an asterisk next to the label.
 83  */
 84 DwtPropertySheet.prototype.addProperty = function(label, value, required) {
 85 
 86 	var index = this._tableEl.rows.length;
 87 
 88 	var row = this._tableEl.insertRow(-1);
 89 	row.vAlign = this._vAlign ? this._vAlign : "top";
 90 
 91 	var labelId = Dwt.getNextId(),
 92 		valueId = Dwt.getNextId(),
 93 		tabValue;   // element or control that can be a tab group member
 94 
 95 	if (this._labelSide == DwtPropertySheet.LEFT) {
 96 		this._insertLabel(row, label, required, labelId, valueId);
 97 		tabValue = this._insertValue(row, value, required, labelId, valueId);
 98 	}
 99 	else {
100 		this._insertValue(row, value, required, labelId, valueId);
101 		tabValue = this._insertLabel(row, label, required, labelId, valueId);
102 	}
103 
104 	var id = this._propertyIdCount++;
105 	var property = {
106 		id:         id,
107 		index:      index,
108 		row:        row,
109 		visible:    true,
110 		labelId:    labelId,
111 		valueId:    valueId,
112 		tabValue:   tabValue
113 	};
114 	this._propertyList.push(property);
115 	this._propertyMap[id] = property;
116 	return id;
117 };
118 
119 DwtPropertySheet.prototype._insertLabel = function(row, label, required, labelId, valueId) {
120 
121 	var labelCell = row.insertCell(-1);
122 	labelCell.className = this._labelCssClass;
123 	labelCell.id = labelId;
124 	labelCell.setAttribute("for", valueId);
125 	if (this._labelSide != DwtPropertySheet.LEFT) {
126 		labelCell.width = "100%";
127 		labelCell.style.textAlign = "left";
128 	}
129 	labelCell.innerHTML = label;
130 	if (required) {
131 		var asterisk = this._tableEl.ownerDocument.createElement("SUP");
132 		asterisk.innerHTML = "*";
133 		labelCell.insertBefore(asterisk, labelCell.firstChild);
134 	}
135 };
136 
137 DwtPropertySheet.prototype._insertValue = function(row, value, required, labelId, valueId) {
138 
139 	var valueCell = row.insertCell(-1);
140 	valueCell.className = this._valueCssClass;
141 	valueCell.id = valueId;
142 
143 	if (!value) {
144 		valueCell.innerHTML = " ";
145 	}
146 	else if (value.isDwtControl) {
147 		valueCell.appendChild(value.getHtmlElement());
148 		this._tabGroup.addMember(value);
149 		var input = value.getInputElement && value.getInputElement();
150 		if (input) {
151 			input.setAttribute('aria-labelledby', labelId);
152 		}
153 	}
154 	else if (value.nodeType == AjxUtil.ELEMENT_NODE) {
155 		valueCell.appendChild(value);
156 		this._addTabGroupMemberEl(valueCell);
157 		value.setAttribute('aria-labelledby', labelId);
158 	}
159 	else {
160 		valueCell.innerHTML = String(value);
161 		this._addTabGroupMemberEl(valueCell);
162 		valueCell.setAttribute('aria-labelledby', labelId);
163 		value = valueCell;
164 	}
165 
166 	return value;
167 };
168 
169 /**
170  * Add element's leaf children to tabgroup.
171  *
172  * @param element HTML element.
173  */
174 DwtPropertySheet.prototype._addTabGroupMemberEl = function(element, isTabStop) {
175 
176 	var obj = this;
177 
178 	// recursive function to add leaf nodes
179 	function addChildren(el) {
180 		if (el.children.length > 0) {
181 			AjxUtil.foreach(el.children, function(child){
182 				addChildren(child);
183 			});
184 		}
185 		else {
186 			if (AjxUtil.isBoolean(isTabStop)) {
187 				obj.noTab = !isTabStop;
188 			}
189 			else {
190 				// add leaf to tabgroup
191 				obj._makeFocusable(el);
192 				obj._tabGroup.addMember(el);
193 			}
194 		}
195 	}
196 
197 	addChildren(element, isTabStop);
198 };
199 
200 DwtPropertySheet.prototype.getTabGroupMember = function() {
201 	return this._tabGroup;
202 };
203 
204 DwtPropertySheet.prototype.getProperty = function(id) {
205 	return this._propertyMap[id];
206 };
207 
208 DwtPropertySheet.prototype.removeProperty = function(id) {
209 	var prop = this._propertyMap[id];
210 	if (prop) {
211 		var propIndex = prop.index;
212 		if (prop.visible) {
213 			var tableIndex = this.__getTableIndex(propIndex);
214 			var row = this._tableEl.rows[tableIndex];
215 			row.parentNode.removeChild(row);
216 		}
217 		prop.row = null;
218 		for (var i = propIndex + 1; i < this._propertyList.length; i++) {
219 			this._propertyList[i].index--;
220 		}
221 		this._propertyList.splice(propIndex, 1);
222 		delete this._propertyMap[id];
223 	}
224 };
225 
226 DwtPropertySheet.prototype.setPropertyVisible = function(id, visible) {
227 
228 	var prop = this._propertyMap[id];
229 	if (prop && prop.visible !== visible) {
230 		prop.visible = visible;
231 		Dwt.setVisible(this._tableEl.rows[prop.index], visible);
232 		var tabValue = prop.tabValue;
233 		if (tabValue.isDwtControl) {
234 			tabValue.noTab = !visible;
235 		}
236 		else {
237 			this._addTabGroupMemberEl(tabValue, !visible)
238 		}
239 	}
240 };
241