1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 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) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * Creates the briefcase base view.
 26  * @class
 27  * This class represents the base view.
 28  * 
 29  * @param	{Hash}	params		a hash of parameters
 30  * @param	{ZmControl}		params.parent		the parent
 31  * @param	{String}	params.className		the class name
 32  * @param	{constant}	params.view		the view
 33  * @param	{ZmBriefcaseController}	params.controller		the controller
 34  * @param	{DwtDropTarget}		params.dropTgt		the drop target
 35  * 
 36  * @extends		ZmListView
 37  */
 38 ZmBriefcaseBaseView = function(params) {
 39 
 40 	if (arguments.length == 0) { return; }
 41 	
 42 	params.posStyle = params.posStyle || DwtControl.ABSOLUTE_STYLE;
 43 	params.type = ZmItem.BRIEFCASE_ITEM;
 44 	params.pageless = (params.pageless !== false);
 45 	ZmListView.call(this, params);
 46 };
 47 
 48 ZmBriefcaseBaseView.prototype = new ZmListView;
 49 ZmBriefcaseBaseView.prototype.constructor = ZmBriefcaseBaseView;
 50 
 51 /**
 52  * Gets the title.
 53  * 
 54  * @return	{String}	the title
 55  */
 56 ZmBriefcaseBaseView.prototype.getTitle =
 57 function() {
 58 	//TODO: title is the name of the current folder
 59 	return [ZmMsg.zimbraTitle, this._controller.getApp().getDisplayName()].join(": ");
 60 };
 61 
 62 ZmBriefcaseBaseView.prototype._sortIndex =
 63 function(list, item){
 64     if(!list){
 65         return null;
 66     }
 67     var a = list.getArray(), index = a.length;
 68 	for(var i = 0; i < a.length; i++) {
 69         var lItem = a[i];
 70 		if (!lItem.isFolder && item.name.toLowerCase() < lItem.name.toLowerCase()) {
 71 			index = i;
 72             break;
 73 		}
 74 
 75 	}
 76 	return { listIndex: index, displayIndex: index};
 77 };
 78 
 79 ZmBriefcaseBaseView.prototype._changeListener =
 80 function(ev) {
 81 
 82 	if (ev.type != this.type) { return; }
 83 
 84 	var items = ev.getDetail("items");
 85 
 86 	if (ev.event == ZmEvent.E_CREATE) {
 87 		var indices;
 88 		for (var i = 0; i < items.length; i++) {
 89 			var item = items[i];
 90 			if (this._list && this._list.contains(item)) { continue; }			// skip if we already have it
 91 			if (this._list) {
 92 				indices = this._sortIndex(this._list, item);
 93 				if (indices) {
 94 					this.addItem(item, indices.displayIndex, false, indices.listIndex);
 95 					this.scrollToItem(item);
 96 					if(this.getSelection().length == 0) {
 97 						// Only select if nothing else is selected
 98 						this.setSelection(item);
 99 					}
100 				}
101 			} else {
102 				// Create the list and add the item
103 				this.addItem(item, 0, false, 0);
104 				this.setSelection(item);
105 			}
106 		}
107 	}
108 
109     if (ev.event == ZmEvent.E_MODIFY) {
110 		var updateList = false;
111 		var item;
112 		var nameUpdated;
113 		for (var i = 0; i < items.length; i++) {
114 			item = items[i];
115 			if (this._list && this._list.contains(item)) {
116 				nameUpdated = ev.getDetail(ZmBriefcaseBaseItem.NAME_UPDATED);
117 				if (nameUpdated) {
118 					this._handleRename(item);
119 				} else {
120 					this._handleModified(item);
121 				}
122 			}
123 		}
124     }
125 
126     ZmListView.prototype._changeListener.call(this, ev);
127 
128     if(ev.event == ZmEvent.E_MOVE){
129         var folderId = this._controller._folderId || this.folderId || this._folderId;
130         var item = items && items.length ? items[0] : items;
131         if(item && item.folderId == folderId && this._getRowIndex(item) === null){
132             this.addItem(item, 0, true);
133             item.handled = true;
134         }
135     }
136 
137 };
138 
139 ZmBriefcaseBaseView.prototype._handleRename = function(item) {
140 	this._handleModified(item);
141 };
142 
143 ZmBriefcaseBaseView.prototype._handleModified = function(item) {
144 	this._redrawItem(item);
145 	if (this._expanded && this._expanded[item.id]) {
146 		//if already expanded, update revisions row
147 		this.parent._expand(item);
148 	}
149 };
150 
151 
152 ZmBriefcaseBaseView.prototype._getToolTip =
153 function(params) {
154 
155 	var item = params.item;
156 	if (item.isFolder) { return null; }
157 
158 	var prop = [{name:ZmMsg.briefcasePropName, value:item.name}];
159 	if (item.size) {
160 		prop.push({name:ZmMsg.briefcasePropSize, value:AjxUtil.formatSize(item.size)});
161 	}
162 	if (item.contentChangeDate) {
163 		var dateFormatter = AjxDateFormat.getDateTimeInstance(AjxDateFormat.FULL, AjxDateFormat.MEDIUM);
164 		var dateStr = dateFormatter.format(item.contentChangeDate);
165 		prop.push({name:ZmMsg.briefcasePropModified, value:dateStr});
166 	}
167 
168     if(item.locked){
169         prop.push({name:ZmMsg.status, value:ZmMsg.locked});
170     }
171 
172 	var subs = {
173         title: ZmMsg.briefcaseFileProps,
174 		fileProperties:	prop,
175 		tagTooltip:		this._getTagToolTip(item)
176 	};
177 	return AjxTemplate.expand("briefcase.Briefcase#Tooltip", subs);
178 };
179 
180 /**
181  * Uploads files from drag-and-drop.
182  * 
183  * @private
184  */
185 ZmBriefcaseBaseView.prototype.uploadFiles =
186 function() {
187     var attachDialog = appCtxt.getUploadDialog();
188     var files = this.processUploadFiles();
189     attachDialog.uploadFiles(null, files, document.getElementById("zdnd_form"), {id:this._controller._folderId});
190 };
191 
192 /**
193  * @private
194  */
195 ZmBriefcaseBaseView.prototype.processUploadFiles =
196 function() {
197 	var files = [];
198 	var ulEle = document.getElementById('zdnd_ul');
199     if (ulEle) {
200         for (var i = 0; i < ulEle.childNodes.length; i++) {
201             var liEle = ulEle.childNodes[i];
202             var inputEl = liEle.childNodes[0];
203             if (inputEl.name != "_attFile_") continue;
204             if (!inputEl.value) continue;
205             var file = {
206                 fullname: inputEl.value,
207                 name: inputEl.value.replace(/^.*[\\\/:]/, "")
208             };
209             files.push(file);
210          }
211    }
212    return files;
213 };
214 
215 ZmBriefcaseBaseView.prototype.getListView =
216 function(){
217     return this;
218 };
219 
220 ZmBriefcaseBaseView.prototype.getTitle =
221 function(){
222     return [ZmMsg.zimbraTitle, ZmMsg.briefcase].join(': ');  
223 };
224 
225 ZmBriefcaseBaseView.prototype._cloneList =
226 function(list){
227     var newList = new ZmList(list.type, list.search);
228     var item;
229     for(var i=0; i<list.size(); i++){
230         item = list.get(i);
231         item.list = newList;
232         newList.add(item);
233     }
234     newList.setHasMore(list.hasMore());
235     return newList;
236 };
237 
238 ZmBriefcaseBaseView.prototype.appendFolders =
239 function(srcList){
240 
241     if(srcList._foldersAdded)
242         return srcList;
243 
244     var subs = this._folders = this._controller._getSubfolders();
245     var subsLen = subs ? subs.length : 0;
246     var newList = srcList;
247     if(subsLen > 0){
248         for(var i=subsLen-1; i>=0; i--){
249             newList.add(subs[i], 0);
250         }
251         newList._foldersAdded = true;
252     }
253     return newList;
254 };
255 
256 ZmBriefcaseBaseView.prototype.set =
257 function(list, sortField, doNotIncludeFolders){
258     this.cleanup();
259 
260     if(!doNotIncludeFolders){
261         list = this.appendFolders(list);
262     }
263 
264     this._zmList = list;
265     ZmListView.prototype.set.call(this, list, sortField);
266     if (this._expanded){
267     	var arr = list.getArray();
268     	var cnt = arr.length;
269     	for(var i=0;i<cnt;i++) {
270     		var item = arr[i];
271     		if(this._expanded[item.id]) {
272     			this.parent._expand(item);
273     		}
274     	}
275         
276     }
277 };
278 
279 ZmBriefcaseBaseView.prototype.renameFile =
280 function(item){
281     //TODO: Make rename field singleton across briefcase views
282     var fileNameEl = this._getFieldId(item, ZmItem.F_NAME);
283     fileNameEl = document.getElementById(fileNameEl);
284     var fileNameBounds = Dwt.getBounds(fileNameEl);
285 
286     var fileInput = this._enableRenameInput(true, fileNameBounds);
287     fileInput.setValue(item.isRevision ? item.parent.name : item.name);
288     this._fileItem = item;
289 };
290 
291 ZmBriefcaseBaseView.prototype._enableRenameInput =
292 function(enable, bounds){
293     var fileInput = this._getRenameInput();
294     if(enable){
295         fileInput.setBounds(bounds.x, bounds.y, bounds.width ,  18);
296         fileInput.setDisplay(Dwt.DISPLAY_INLINE);
297         fileInput.focus();
298     }else{
299         fileInput.setDisplay(Dwt.DISPLAY_NONE);
300         fileInput.setLocation("-10000px", "-10000px");
301     }
302     return fileInput;
303 };
304 
305 ZmBriefcaseBaseView.prototype._getRenameInput =
306 function(){
307     if(!this._renameField){
308         this._renameField = new DwtInputField({parent:appCtxt.getShell(), className:"RenameInput DwtInputField", posStyle: Dwt.ABSOLUTE_STYLE});
309         this._renameField.setZIndex(Dwt.Z_VIEW + 10); //One layer above the VIEW
310         this._renameField.setDisplay(Dwt.DISPLAY_NONE);
311         this._renameField.setLocation("-10000px", "-10000px");
312         this._renameField.addListener(DwtEvent.ONKEYUP, new AjxListener(this, this._handleKeyUp));
313     }
314     return this._renameField;
315 };
316 
317 ZmBriefcaseBaseView.prototype._mouseDownAction = function(mouseEv, div) {
318 	if (this._renameField && this._renameField.getVisibility() && this._fileItem) {
319 		this._doRename(this._fileItem);
320 		this.resetRenameFile();
321 	}
322 	ZmListView.prototype._mouseDownAction(mouseEv, div);
323 };
324 
325 
326 ZmBriefcaseBaseView.prototype._handleKeyUp =
327 function(ev) {
328     var allowDefault = true;
329 	var key = DwtKeyEvent.getCharCode(ev);
330     var item = this._fileItem;
331     if (DwtKeyEvent.IS_RETURN[key]) {
332         this._doRename(item);
333         allowDefault = false;
334     }
335     else if( key === DwtKeyEvent.KEY_ESCAPE){
336         this._redrawItem(item);
337         allowDefault = false;
338     }
339 	DwtUiEvent.setBehaviour(ev, true, allowDefault);
340 };
341 
342 ZmBriefcaseBaseView.prototype._doRename = function(item) {
343 	var fileName = this._renameField.getValue();
344 	if (fileName != '' && (fileName != item.name)) {
345 		var warning = appCtxt.getMsgDialog();
346 		if (this._checkDuplicate(fileName)) {
347 			this._redrawItem(item);
348 			warning.setMessage(AjxMessageFormat.format(ZmMsg.itemWithFileNameExits, fileName), DwtMessageDialog.CRITICAL_STYLE, ZmMsg.briefcase);
349 			warning.popup();
350 		} else if(ZmAppCtxt.INVALID_NAME_CHARS_RE.test(fileName)) {
351 			//Bug fix # 79986 show warning popup in case of invalid filename
352 			warning.setMessage(AjxMessageFormat.format(ZmMsg.errorInvalidName, AjxStringUtil.htmlEncode(fileName)), DwtMessageDialog.WARNING_STYLE, ZmMsg.briefcase);
353 			warning.popup();
354 		} else {
355 			item.rename(fileName, new AjxCallback(this, this.resetRenameFile));
356 		}
357 	} else {
358 		this.redrawItem(item);
359 	}
360 }
361 
362 
363 ZmBriefcaseBaseView.prototype.resetRenameFile =
364 function(){
365     this._enableRenameInput(false);
366     this._fileItem = null;
367 };
368 
369 ZmBriefcaseBaseView.prototype._redrawItem =
370 function(item){
371     this.resetRenameFile();
372     this.redrawItem(item);
373 };
374 
375 ZmBriefcaseBaseView.prototype._checkDuplicate =
376 function(name){
377 
378     name = name.toLowerCase();
379     var list = this.getList();
380     if(list){
381         list = list.getArray();
382         for (var i = 0; i < list.length; i++) {
383             var item = list[i];
384             if(item.name.toLowerCase() == name)
385                 return true;
386         }
387     }
388     return false;   
389 };
390 
391 ZmBriefcaseBaseView.prototype.cleanup = function() {
392     if (this._renameField) {
393         this.resetRenameFile();
394 	}
395 };
396 
397