1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 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) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * This class represents the export base view.
 26  * 
 27  * @extends		DwtForm
 28  * @private
 29  */
 30 ZmImportExportBaseView = function(params) {
 31 	if (arguments.length == 0) return;
 32 	DwtForm.call(this, params);
 33 	this.setScrollStyle(DwtControl.VISIBLE);
 34 	this._initSubType(ZmImportExportController.TYPE_CSV);
 35 	this._setFolderButton(appCtxt.getById(ZmOrganizer.ID_ROOT));
 36 };
 37 ZmImportExportBaseView.prototype = new DwtForm;
 38 ZmImportExportBaseView.prototype.constructor = ZmImportExportBaseView;
 39 
 40 ZmImportExportBaseView.prototype.toString = function() {
 41 	return "ZmImportExportBaseView";
 42 };
 43 
 44 //
 45 // Data
 46 //
 47 
 48 ZmImportExportBaseView.prototype._folderId = -1;
 49 
 50 //
 51 // Public methods
 52 //
 53 
 54 ZmImportExportBaseView.prototype.getFolderId = function() {
 55 	return this._folderId;
 56 };
 57 
 58 // DwtForm methods
 59 
 60 ZmImportExportBaseView.prototype.update = function() {
 61 	DwtForm.prototype.update.apply(this, arguments);
 62 
 63 	// update type hint
 64 	var type = this.getValue("TYPE", ZmImportExportController.TYPE_TGZ);
 65 	this.setValue("TYPE_HINT", this.TYPE_HINTS[type]);
 66 };
 67 
 68 ZmImportExportBaseView.prototype.setValue = function(name, value) {
 69     var ovalue = this.getValue(name);
 70 	DwtForm.prototype.setValue.apply(this, arguments);
 71 	if (name == "TYPE" && value != ovalue) {
 72 		var type = value;
 73 		this._initSubType(type);
 74 		var isTgz = type == ZmImportExportController.TYPE_TGZ;
 75 		this.setEnabled("ADVANCED", isTgz);
 76 		if (this.getValue("ADVANCED") && !isTgz) {
 77 			this.setValue("ADVANCED", false);
 78 			this.update();
 79 		}
 80 		var folder;
 81 		switch (type) {
 82 			case ZmImportExportController.TYPE_CSV: {
 83 				// TODO: Does this work for child accounts w/ fully-qualified ids?
 84 				folder = appCtxt.getById(ZmOrganizer.ID_ADDRBOOK);
 85 				break;
 86 			}
 87 			case ZmImportExportController.TYPE_ICS: {
 88 				folder = appCtxt.getById(ZmOrganizer.ID_CALENDAR);
 89 				break;
 90 			}
 91 			case ZmImportExportController.TYPE_TGZ: {
 92 				folder = appCtxt.getById(ZmOrganizer.ID_ROOT);
 93 				break;
 94 			}
 95 		}
 96 		this._setFolderButton(folder);
 97 	}
 98 };
 99 
100 //
101 // Protected methods
102 //
103 
104 // initializers
105 
106 ZmImportExportBaseView.prototype._initSubType = function(type) {
107 	var select = this.getControl("SUBTYPE");
108 	if (!select) return;
109 
110 	var options = this._getSubTypeOptions(type);
111 	if (!options || options.length == 0) return;
112 
113 	select.clearOptions();
114 	for (var i = 0; i < options.length; i++) {
115 		select.addOption(options[i]);
116 	}
117 	select.setSelectedValue(options[0].value);
118 };
119 
120 ZmImportExportBaseView.prototype._getSubTypeOptions = function(type) {
121 	if (!ZmImportExportBaseView.prototype.TGZ_OPTIONS) {
122 		ZmImportExportBaseView.prototype.TGZ_OPTIONS = [
123 			{ displayValue: ZmMsg["zimbra-tgz"],			value: "zimbra-tgz" }
124 		];
125 		ZmImportExportBaseView.prototype.CSV_OPTIONS = [];
126 		var formats = appCtxt.get(ZmSetting.AVAILABLE_CSVFORMATS);
127 		for (var i = 0; i < formats.length; i++) {
128 			var format = formats[i];
129 			if (format) {
130 				ZmImportExportBaseView.prototype.CSV_OPTIONS.push(
131 					{ displayValue: ZmMsg[format] || format, value: format }
132 				);
133 			}
134 		}
135 		ZmImportExportBaseView.prototype.ICS_OPTIONS = [
136 			{ displayValue: ZmMsg["zimbra-ics"],			value: "zimbra-ics" }
137 		];
138 	}
139 	var options;
140 	switch (type) {
141 		case ZmImportExportController.TYPE_TGZ: {
142 			options = this.TGZ_OPTIONS;
143 			break;
144 		}
145 		case ZmImportExportController.TYPE_CSV: {
146 			options = this.CSV_OPTIONS;
147 			break;
148 		}
149 		case ZmImportExportController.TYPE_ICS: {
150 			options = this.ICS_OPTIONS;
151 			break;
152 		}
153 	}
154 	return options;
155 };
156 
157 // handlers
158 
159 ZmImportExportBaseView.prototype._type_onclick = function(radioId, groupId) {
160 	// enable advanced options
161 	var type = this.getValue("TYPE");
162 	this.setValue("TYPE", type);
163 };
164 
165 ZmImportExportBaseView.prototype._folderButton_onclick = function() {
166 	// init state
167 	if (!this._handleFolderDialogOkCallback) {
168 		this._handleFolderDialogOkCallback = new AjxCallback(this, this._handleFolderDialogOk);
169 	}
170 
171 	if (!this._TREES) {
172 		this._TREES = {};
173 		this._TREES[ZmImportExportController.TYPE_TGZ] = [];
174         for (var org in ZmOrganizer.VIEWS) {
175             if (org == ZmId.APP_VOICE){
176                 continue;  //Skip voice folders for import/export (Bug: 72269)
177             }
178             var settingId = ZmApp.SETTING[ZmOrganizer.APP2ORGANIZER_R[org]];
179             if (settingId == null || appCtxt.get(settingId)) {
180                 this._TREES[ZmImportExportController.TYPE_TGZ].push(org);
181             }
182         }
183 		this._TREES[ZmImportExportController.TYPE_CSV] = appCtxt.get(ZmSetting.CONTACTS_ENABLED) ? [ZmOrganizer.ADDRBOOK] : [];
184 		this._TREES[ZmImportExportController.TYPE_ICS] = appCtxt.get(ZmSetting.CALENDAR_ENABLED) ? [ZmOrganizer.CALENDAR] : [];
185 	}
186 
187 	// pop-up dialog
188 	var dialog = appCtxt.getChooseFolderDialog();
189 	dialog.registerCallback(DwtDialog.OK_BUTTON, this._handleFolderDialogOkCallback);
190 	var type = this.getValue("TYPE") || ZmImportExportController.TYPE_TGZ;
191 	var acctName = appCtxt.multiAccounts ? appCtxt.getActiveAccount().name : "";
192 	var params = {
193 		treeIds:		this._TREES[type],
194 		overviewId:		dialog.getOverviewId([this.toString(), type, acctName].join("_")),
195 		description:	"",
196 		skipReadOnly:	true,
197 		omit:			{},
198 		forceSingle:	true,
199 		showDrafts:		(this instanceof ZmExportView),
200 		hideNewButton:	(this instanceof ZmExportView)
201 	};
202 	params.omit[ZmOrganizer.ID_TRASH] = true;
203 	dialog.popup(params);
204 };
205 
206 ZmImportExportBaseView.prototype._handleFolderDialogOk = function(folder) {
207 	appCtxt.getChooseFolderDialog().popdown();
208 	this._setFolderButton(folder);
209 	return true;
210 };
211 
212 ZmImportExportBaseView.prototype._setFolderButton = function(folder) {
213 	// NOTE: Selecting a header is the same as "all folders"
214 	this._folderId = folder ? folder.id : -1;
215 	if (folder) {
216 		var isRoot = folder.nId == ZmOrganizer.ID_ROOT;
217 		this.setLabel("FOLDER_BUTTON", isRoot ? ZmMsg.allFolders : AjxStringUtil.htmlEncode(folder.name));
218 	}
219 	else {
220 		this.setLabel("FOLDER_BUTTON", ZmMsg.browse);
221 	}
222 };
223 
224 //
225 // Class
226 //
227 
228 ZmImportExportDataTypes = function(params) {
229 	if (arguments.length == 0) return;
230 	DwtComposite.apply(this, arguments);
231 	this._tabGroup = new DwtTabGroup(this._htmlElId);
232 	this._createHtml();
233 };
234 ZmImportExportDataTypes.prototype = new DwtComposite;
235 ZmImportExportDataTypes.prototype.constructor = ZmImportExportDataTypes;
236 
237 ZmImportExportDataTypes.prototype.toString = function() {
238 	return "ZmImportExportDataTypes";
239 };
240 
241 // Data
242 
243 ZmImportExportDataTypes.prototype.TEMPLATE = "data.ImportExport#DataTypes";
244 
245 // Public methods
246 
247 ZmImportExportDataTypes.prototype.getTabGroupMember = function() {
248 	return this._tabGroup;
249 };
250 
251 ZmImportExportDataTypes.prototype.setValue = function(value) {
252 	// NOTE: Special case "" as *all* types -- this will include things
253 	//       like conversations, etc, that are implicitly added if no
254 	//       data types are specified for import/export.
255 	if (value == "") {
256 		var children = this.getChildren();
257 		for (var i = 0; i < children.length; i++) {
258 			var checkbox = children[i];
259 			checkbox.setSelected(true);
260 		}
261 		return;
262 	}
263 
264 	// return only those types that are checked
265 	var types = value ? value.split(",") : [];
266 	var type = {};
267 	for (var i = 0; i < types.length; i++) {
268 		type[types[i]] = true;
269 	}
270 	var children = this.getChildren();
271 	for (var i = 0; i < children.length; i++) {
272 		var checkbox = children[i];
273 		var selected = true;
274 		var types = checkbox.getValue().split(",");
275 		for (var j = 0; j < types.length; j++) {
276 			if (!type[types[j]]) {
277 				selected = false;
278 				break;
279 			}
280 		}
281 		checkbox.setSelected(selected);
282 	}
283 };
284 
285 ZmImportExportDataTypes.prototype.getValue = function() {
286 	// NOTE: Special case "" as *all* types. 
287 	if (this.isAllSelected()) {
288 		return "";
289 	}
290 
291 	var types = [];
292 	var children = this.getChildren();
293 	for (var i = 0; i < children.length; i++) {
294 		var checkbox = children[i];
295 		if (checkbox.isSelected()) {
296 			types.push(checkbox.getValue());
297 		}
298 	}
299 	return types.join(",");
300 };
301 
302 /**
303  * Checks if "all" is selected.
304  * 
305  * @return	{Boolean}	<code>true</code> if all is selected
306  */
307 ZmImportExportDataTypes.prototype.isAllSelected = function() {
308 	var children = this.getChildren();
309 	for (var i = 0; i < children.length; i++) {
310 		var checkbox = children[i];
311 		if (!checkbox.isSelected()) {
312 			return false;
313 		}
314 	}
315 	return true;
316 };
317 
318 ZmImportExportDataTypes.prototype.setEnabled = function(enabled) {
319 	DwtComposite.prototype.setEnabled.apply(this, arguments);
320 	var children = this.getChildren();
321 	for (var i = 0; i < children.length; i++) {
322 		var checkbox = children[i];
323 		checkbox.setEnabled(enabled);
324 	}
325 };
326 
327 // Protected methods
328 
329 ZmImportExportDataTypes.prototype._createHtml = function(templateId) {
330 	this._createHtmlFromTemplate(templateId || this.TEMPLATE, {id:this._htmlElId});
331 };
332 
333 ZmImportExportDataTypes.prototype._createHtmlFromTemplate =
334 function(templateId, data) {
335 	// get number of checkboxes
336 	data.count = 0;
337 	for (var appName in ZmApp.ORGANIZER) {
338 		var orgType = ZmApp.ORGANIZER[appName];
339 		var views = ZmOrganizer.VIEWS[orgType];
340 		if (!views || views.length == 0) continue;
341 		data.count++;
342 	}
343 
344 	// create cells
345 	DwtComposite.prototype._createHtmlFromTemplate.call(this, templateId, data);
346 
347 	// create checkboxes and place in cells
348 	var i = 0;
349 	for (var appName in ZmApp.ORGANIZER) {
350 		var orgType = ZmApp.ORGANIZER[appName];
351 		var views = ZmOrganizer.VIEWS[orgType];
352 		if (!views || views.length == 0) continue;
353 
354 		var checkbox = new ZmImportExportDataTypeCheckbox({parent:this,checked:true});
355 		checkbox.setImage(ZmApp.ICON[appName]);
356 		checkbox.setText(ZmMsg[ZmApp.NAME[appName]] || ZmApp.NAME[appName] || appName);
357 		// NOTE: I know it's the default join string but I prefer
358 		//       explicit behavior.
359 		checkbox.setValue(views.join(","));
360 		checkbox.replaceElement(data.id+"_cell_"+i);
361 
362 		this._tabGroup.addMember(checkbox);
363 
364 		i++;
365 	}
366 };
367 
368 //
369 // Class
370 //
371 
372 ZmImportExportDataTypeCheckbox = function(params) {
373 	if (arguments.length == 0) return;
374 	DwtCheckbox.apply(this, arguments);
375 };
376 ZmImportExportDataTypeCheckbox.prototype = new DwtCheckbox;
377 ZmImportExportDataTypeCheckbox.prototype.constructor = ZmImportExportDataTypeCheckbox;
378 
379 // Data
380 
381 ZmImportExportDataTypeCheckbox.prototype.TEMPLATE = "data.ImportExport#DataTypeCheckbox";
382 
383 // Public methods
384 
385 ZmImportExportDataTypeCheckbox.prototype.setTextPosition = function(position) {
386 	DwtCheckbox.prototype.setTextPosition.call(this, DwtCheckbox.TEXT_RIGHT);
387 };
388 
389 ZmImportExportDataTypeCheckbox.prototype.setImage = function(imageName) {
390 	if (this._imageEl) {
391 		this._imageEl.className = AjxImg.getClassForImage(imageName);
392 	}
393 };
394 
395 // Protected methods
396 
397 ZmImportExportDataTypeCheckbox.prototype._createHtmlFromTemplate =
398 function(templateId, data) {
399 	DwtCheckbox.prototype._createHtmlFromTemplate.apply(this, arguments);
400 	this._imageEl = document.getElementById(data.id+"_image");
401 };
402