1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 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) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * @overview
 26  * 
 27  */
 28 
 29 /**
 30  * Creates the briefcase detail list view.
 31  * @class
 32  * This class represents the briefcase detail list view.
 33  * 
 34  * @param	{ZmControl}		parent		the parent
 35  * @param	{ZmBriefcaseController}	controller		the controller
 36  * @param	{DwtDropTarget}		dropTgt		the drop target
 37  * 
 38  * @extends		ZmBriefcaseBaseView
 39  */
 40 ZmDetailListView = 	function(parent, controller, dropTgt) {
 41 
 42     this._controller = controller;
 43 
 44 	var headerList = this._getHeaderList(parent);
 45 
 46 	var params = {parent:parent, className:"ZmBriefcaseDetailListView",
 47 				  view: controller.getCurrentViewId(),
 48 				  controller:controller, headerList:headerList, dropTgt:dropTgt};
 49 	ZmBriefcaseBaseView.call(this, params);
 50 
 51     this.enableRevisionView(true);
 52 
 53     this._expanded = {};
 54     this._itemRowIdList = {};
 55 
 56 	if (controller.supportsDnD()) {
 57 		this._dragSrc = new DwtDragSource(Dwt.DND_DROP_MOVE);
 58 		this._dragSrc.addDragListener(this._dragListener.bind(this));
 59 		this.setDragSource(this._dragSrc);
 60 	
 61 		this._dropTgt = new DwtDropTarget("ZmDetailListView");
 62 		this._dropTgt.markAsMultiple();
 63 		this._dropTgt.addDropListener(this._dropListener.bind(this));
 64 		this.setDropTarget(this._dropTgt);
 65 	}
 66     // Finder to DetailView drag and drop
 67     this._initDragAndDrop();
 68 };
 69 
 70 ZmDetailListView.prototype = new ZmBriefcaseBaseView;
 71 ZmDetailListView.prototype.constructor = ZmDetailListView;
 72 
 73 ZmDetailListView.ROW_DOUBLE_CLASS	= "RowDouble";
 74 
 75 
 76 ZmDetailListView.SINGLE_COLUMN_SORT = [
 77 	{field:ZmItem.F_NAME, msg:"name"},
 78 	{field:ZmItem.F_SIZE, msg:"size"},
 79 	{field:ZmItem.F_DATE, msg:"date"}
 80 ];
 81 
 82 
 83 /**
 84  * Returns a string representation of the object.
 85  * 
 86  * @return		{String}		a string representation of the object
 87  */
 88 ZmDetailListView.prototype.toString =
 89 function() {
 90 	return "ZmDetailListView";
 91 };
 92 
 93 // Constants
 94 
 95 ZmDetailListView.KEY_ID = "_keyId";
 96 
 97 ZmDetailListView.COLWIDTH_ICON = 20;
 98 
 99 // Protected methods
100 
101 ZmDetailListView.prototype.enableRevisionView =
102 function(enabled){
103     this._revisionView = enabled;    
104 };
105 
106 ZmDetailListView.prototype._changeListener =
107 function(ev){
108     if(ev.event == ZmEvent.E_MOVE || ev.event == ZmEvent.E_DELETE){
109         if (this.getDnDSelection() && this.getDnDSelection instanceof AjxVector)
110             this.dragDeselect(this.getDnDSelection().get(0));
111         else if (this.getDnDSelection())
112             this.dragDeselect(this.getDnDSelection());
113     }
114 
115 
116     ZmBriefcaseBaseView.prototype._changeListener.call(this, ev);
117     if (this._revisionView && ( ev.event == ZmEvent.E_DELETE || ev.event == ZmEvent.E_MOVE )) {
118         var items = ev.getDetail("items") ? ev.getDetail("items") : [this._getItemFromEvent(ev)];
119         for (var i = 0, len = items.length; i < len; i++) {
120 			var item = items[i];
121             this.collapse(item, true);
122         }
123     }
124 };
125 
126 ZmDetailListView.prototype._getHeaderList =
127 function(parent) {
128 	// Columns: tag, name, type, size, date, owner, folder
129 	var headers = [];
130 	var view = this._view;
131 	if (appCtxt.get(ZmSetting.SHOW_SELECTION_CHECKBOX)) {
132 		headers.push(new DwtListHeaderItem({field:ZmItem.F_SELECTION, icon:"CheckboxUnchecked", width:ZmListView.COL_WIDTH_ICON,
133 											name:ZmMsg.selection}));
134 	}
135     if(this.isMultiColumn()){
136 
137         if(this._revisionView){
138             headers.push(new DwtListHeaderItem({field:ZmItem.F_EXPAND, icon: "NodeCollapsed", width:ZmDetailListView.COLWIDTH_ICON, name:ZmMsg.expand}));            
139         }
140 
141         if (appCtxt.get(ZmSetting.TAGGING_ENABLED)) {
142             headers.push(new DwtListHeaderItem({field:ZmItem.F_TAG, icon:"Tag", width:ZmDetailListView.COLWIDTH_ICON,
143                 name:ZmMsg.tag}));
144         }
145         headers.push(
146                 new DwtListHeaderItem({field:ZmItem.F_LOCK, icon: "Padlock", width:ZmDetailListView.COLWIDTH_ICON, name:ZmMsg.lock}),
147                 new DwtListHeaderItem({field:ZmItem.F_TYPE, icon:"GenericDoc", width:ZmDetailListView.COLWIDTH_ICON, name:ZmMsg.icon}),
148                 new DwtListHeaderItem({field:ZmItem.F_NAME, text:ZmMsg._name, sortable:ZmItem.F_NAME}),
149                 new DwtListHeaderItem({field:ZmItem.F_FILE_TYPE, text:ZmMsg.type, width:ZmMsg.COLUMN_WIDTH_TYPE_DLV}),
150                 new DwtListHeaderItem({field:ZmItem.F_SIZE, text:ZmMsg.size, width:ZmMsg.COLUMN_WIDTH_SIZE_DLV, sortable:ZmItem.F_SIZE}),
151                 new DwtListHeaderItem({field:ZmItem.F_DATE, text:ZmMsg.modified, width:ZmMsg.COLUMN_WIDTH_DATE_DLV, sortable:ZmItem.F_DATE}),
152                 new DwtListHeaderItem({field:ZmItem.F_FROM, text:ZmMsg.author, width:ZmMsg.COLUMN_WIDTH_OWNER_DLV}),
153                 new DwtListHeaderItem({field:ZmItem.F_FOLDER, text:ZmMsg.folder, width:ZmMsg.COLUMN_WIDTH_FOLDER_DLV}),
154                 new DwtListHeaderItem({field:ZmItem.F_VERSION, text:ZmMsg.version, width:ZmMsg.COLUMN_WIDTH_VERSION_DLV})
155                 );
156     }else{
157         headers.push(new DwtListHeaderItem({field:ZmItem.F_SORTED_BY, text:AjxMessageFormat.format(ZmMsg.arrangedBy, ZmMsg.name), sortable:ZmItem.F_NAME, resizeable:false}));
158     }
159 	return headers;
160 };
161 
162 ZmDetailListView.prototype._getHeaderToolTip =
163 function(field, itemIdx, isOutboundFolder) {
164 
165     var tooltip;
166     if(field == ZmItem.F_EXPAND){
167         tooltip = ZmMsg.expandCollapse;
168     }else if(field == ZmItem.F_LOCK){
169         tooltip = ZmMsg.fileLockStatus;
170     }else if(field == ZmItem.F_DATE){
171         tooltip = ZmMsg.sortByModified; 
172     }else if(field == ZmItem.F_FROM){
173         tooltip = ZmMsg.author;
174     }else if(field == ZmItem.F_VERSION){
175         tooltip = ZmMsg.latestVersion;
176     }else if(field == ZmItem.F_NAME){
177         tooltip = ZmMsg.sortByName;
178     }else{
179         tooltip = ZmBriefcaseBaseView.prototype._getHeaderToolTip.call(this, field, itemIdx, isOutboundFolder);
180     }   
181     return tooltip;
182 };
183 
184 
185 ZmDetailListView.prototype._getActionMenuForColHeader =
186 function(force) {
187 
188 	if (!this.isMultiColumn()) {
189 		if (!this._colHeaderActionMenu || force) {
190 			this._colHeaderActionMenu = this._getSortMenu(ZmDetailListView.SINGLE_COLUMN_SORT, ZmItem.F_NAME);
191 		}
192 		return this._colHeaderActionMenu;
193 	}
194 
195 	var menu = ZmListView.prototype._getActionMenuForColHeader.call(this, force);
196 
197 	return menu;
198 };
199 
200 
201 
202 ZmDetailListView.prototype._isExpandable =
203 function(item){
204     return (!item.isFolder && !item.isRevision && parseInt(item.version) > 1 );
205 };
206 
207 ZmDetailListView.prototype._getCellContents =
208 function(htmlArr, idx, item, field, colIdx, params) {
209 
210 	if (field == ZmItem.F_SELECTION) {
211 		var icon = params.bContained ? "CheckboxChecked" : "CheckboxUnchecked";
212 		idx = this._getImageHtml(htmlArr, idx, icon, this._getFieldId(item, field));
213     } else if (field == ZmItem.F_EXPAND) {
214 		idx = this._getImageHtml(htmlArr, idx, 
215 				this._isExpandable(item) ? (this._expanded[item.id] ? "NodeExpanded" : "NodeCollapsed" )
216 						: null, this._getFieldId(item, field));   
217 	} else if (field == ZmItem.F_TYPE) {
218 		htmlArr[idx++] = AjxImg.getImageHtml(item.getIcon());
219 	} else if (field == ZmItem.F_LOCK) {
220 		idx = this._getImageHtml(htmlArr, idx, (item.locked ? "Padlock" : "Blank_16") , this._getFieldId(item, field)); //AjxImg.getImageHtml(item.locked ? "Padlock" : "Blank_16");
221 	} else if (field == ZmItem.F_VERSION) {
222 		htmlArr[idx++] = item.version;
223 	} else if (field == ZmItem.F_NAME || field == ZmItem.F_SUBJECT) {
224 		htmlArr[idx++] = "<div id='"+this._getFieldId(item, ZmItem.F_NAME)+"'>"+this._getDisplayName(item)+"</div>";
225 	} else if (field == ZmItem.F_FILE_TYPE) {
226         if(item.isFolder){
227             htmlArr[idx++] = ZmMsg.folder;
228         }else{
229             var mimeInfo = item.contentType ? ZmMimeTable.getInfo(item.contentType) : null;
230             htmlArr[idx++] = mimeInfo ? mimeInfo.desc : " ";
231         }
232 	} else if (field == ZmItem.F_SIZE) {
233 	    htmlArr[idx++] = item.isFolder ? ZmMsg.folder : AjxUtil.formatSize(item.size);
234 	} else if (field == ZmItem.F_DATE) {
235 		if (item.contentChangeDate || item.modifyDate || item.createDate) {
236 			var displayDate;
237 			if (item.contentChangeDate) {
238 			    displayDate = item.contentChangeDate;
239 			} else if (item.modifyDate) {
240 				displayDate = item.modifyDate;
241 			} else {
242 				displayDate = item.createDate;
243 			}
244 			htmlArr[idx++] = AjxDateUtil.simpleComputeDateStr(displayDate);
245 		}
246 	} else if (field == ZmItem.F_FROM) {
247         var creator = item.modifier || item.creator;
248 		creator = creator ? creator.split("@") : [""];
249 		var cname = creator[0];
250 		var uname = appCtxt.get(ZmSetting.USERNAME);
251 		if (uname) {
252 			var user = uname.split("@");
253 			if (creator[1] != user[1]) {
254 				cname = creator.join("@");
255 			}
256 		}
257 		htmlArr[idx++] = "<span style='white-space:nowrap'>";
258 		htmlArr[idx++] = cname;
259 		htmlArr[idx++] = "</span>";
260 	} else if (field == ZmItem.F_FOLDER) {
261 		var briefcase = appCtxt.getById(item.folderId);
262 		htmlArr[idx++] = briefcase ? briefcase.getName() : item.folderId;
263 	} else if (field == ZmItem.F_SORTED_BY){
264         htmlArr[idx++] = this._getAbridgedContent(item, colIdx);
265     } 
266     else {
267 		idx = ZmListView.prototype._getCellContents.apply(this, arguments);
268 	}
269 
270 	return idx;
271 };
272 
273 ZmDetailListView.prototype._getDisplayName =
274 function(item){
275     var subject;
276     if(item.isRevision){
277         subject = (item.subject);
278     }else if(parseInt(item.version) > 1){
279         subject = AjxMessageFormat.format(ZmMsg.briefcaseFileVersion, [AjxStringUtil.htmlEncode(item.name), item.version])
280     }
281     return subject || (AjxStringUtil.htmlEncode(item.name));
282 };
283 
284 ZmDetailListView.prototype._getAbridgedContent =
285 function(item, colIdx) {
286 
287     var idx=0, html=[];
288 	var width = (AjxEnv.isIE || AjxEnv.isSafari) ? 22 : 16;
289 	
290     html[idx++] = "<table width=100% class='TopRow'><tr>";
291 
292     if(this._revisionView){
293         html[idx++] = "<td width=" + width + " id='" + this._getFieldId(item, ZmItem.F_FOLDER) + "'><center>";
294         idx = this._getCellContents(html, idx, item, ZmItem.F_EXPAND, colIdx);
295         html[idx++] = "</center></td>";
296     }
297 
298 	html[idx++] = "<td width=20 id='" + this._getFieldId(item, ZmItem.F_FOLDER) + "'><center>";
299 	html[idx++] = AjxImg.getImageHtml(item.getIcon());
300 	html[idx++] = "</center></td>";
301 	html[idx++] = "<td style='vertical-align:middle;' width=100% id='" + this._getFieldId(item, ZmItem.F_NAME) + "'>";
302     html[idx++] = this._getDisplayName(item);
303 	html[idx++] = "</td>";
304 
305     html[idx++] = "<td style='vertical-align:middle;text-align:right;' width=40 id='" + this._getFieldId(item, ZmItem.F_SIZE) + "'>";
306 	idx = this._getCellContents(html, idx, item, ZmItem.F_SIZE, colIdx);
307 	html[idx++] = "</td>";
308 
309     html[idx++] = "<td style='text-align:right' width=" + width + " >";
310     idx = this._getImageHtml(html, idx, item.getTagImageInfo(), this._getFieldId(item, ZmItem.F_TAG));
311 	html[idx++] = "</td>";
312 
313 	html[idx++] = "</tr>";
314     html[idx++] = "</table>";
315 
316     html[idx++] = "<table width=100% class='BottomRow'><tr>";
317     html[idx++] = "<td style='vertical-align:middle;padding-left:50px;'>";
318     idx = this._getCellContents(html, idx, item, ZmItem.F_FROM, colIdx);
319     html[idx++] = "<td style='vertical-align:middle;text-align:right;'>";
320     idx = this._getCellContents(html, idx, item, ZmItem.F_DATE, colIdx);
321     html[idx++] = "</td>";
322     html[idx++] = "<td style='text-align:center;' width=" + width + " id='" + this._getFieldId(item, ZmItem.F_LOCK)+"'> ";
323     idx =   this._getImageHtml(html, idx, (item.locked ? "Padlock" : "Blank_16") , this._getFieldId(item, ZmItem.F_LOCK));
324 	html[idx++] = "</td>";
325     html[idx++] = "</tr></table>";
326 
327 	return html.join('');
328 };
329 
330 ZmDetailListView.prototype._getDivClass =
331 function(base, item, params) {
332 	if (item.isRevision) {
333 	    return [base, "BriefcaseItemExpanded"].join(" ");
334 	} else {
335 		return ZmBriefcaseBaseView.prototype._getDivClass.apply(this, arguments);
336 	}
337 };
338 
339 ZmDetailListView.prototype.expandItem =
340 function(item) {
341 	if (item && this._isExpandable(item) && this._revisionView) {
342 		this.parent._toggle(item);
343 	}
344 };
345 
346 ZmDetailListView.prototype.expand =
347 function(item, revisions){
348 
349     if(!item || !revisions || revisions.size() == 0 ) return;
350 
351     this._addRevisionRows(item, revisions);
352        
353     this._setImage(item, ZmItem.F_EXPAND, "NodeExpanded");
354     this._expanded[item.id] = true;
355 };
356 
357 ZmDetailListView.prototype._addRevisionRows =
358 function(item, revisions){
359 
360     var rowIds = this._itemRowIdList[item.id];
361     if (rowIds && rowIds.length && rowIds.length == revisions.size() && this._rowsArePresent(item)){
362         this._showRows(rowIds, true);
363     }else{
364         var index = this._getRowIndex(item);
365         this._itemRowIdList[item.id] = [];
366         for(var i=0; i< revisions.size(); i++){
367             var rev = revisions.get(i);
368             var div = this._createItemHtml(rev);
369             //check if item exists before adding row
370             if (!document.getElementById(div.id))
371                 this._addRow(div, index+i+1);
372             else
373                 this._showRows([div.id],true);
374             this._itemRowIdList[item.id].push(div.id);
375         }
376     }
377     
378 };
379 
380 ZmDetailListView.prototype.collapse =
381 function(item, clear){
382 	var rowIds = this._itemRowIdList[item.id];
383 	this._showRows(rowIds, false);
384 	this._setImage(item, ZmItem.F_EXPAND, "NodeCollapsed");
385 	this._expanded[item.id] = false;
386 	if(clear && rowIds){
387 		var divId;
388 		var el;
389 		for (var i = 0; i < rowIds.length; i++) {
390 			divId = rowIds[i];
391 			el = document.getElementById(divId);
392 			if (el && el.parentNode) {
393 				el.parentNode.removeChild(el);
394 			}
395 		}
396 		this._itemRowIdList[item.id] = null;
397 	}
398 };
399 
400 ZmDetailListView.prototype.collapseAll =
401 function(){
402     var list = this.getItemList(), item;
403     for(var id in this._expanded){
404         if(this._expanded[id]){
405             item = list.getById(id);
406             if(item) this.collapse(item);
407         }
408     }
409 };
410 
411 ZmDetailListView.prototype.refreshItem =
412 function(item){
413      if(item && this._expanded[item.id]){
414          var rowIds = this._itemRowIdList[item.id];
415      }
416 };
417 
418 ZmDetailListView.prototype._showRows =
419 function(rowIds, show){
420    if (rowIds && rowIds.length) {
421         for (var i = 0; i < rowIds.length; i++) {
422             var row = document.getElementById(rowIds[i]);
423             if (row) {
424                 Dwt.setVisible(row, show);
425             }
426         }
427      }
428 };
429 
430 ZmDetailListView.prototype._rowsArePresent =
431 function(item) {
432 	var rowIds = this._itemRowIdList[item.id];
433 	if (rowIds && rowIds.length) {
434 		for (var i = 0; i < rowIds.length; i++) {
435 			if (document.getElementById(rowIds[i])) {
436 				return true;
437 			}
438 		}
439 	}
440 	this._itemRowIdList[item.id] = [];	// start over
441 	this._expanded[item.id] = false;
442 	return false;
443 };
444 
445 
446 
447 ZmDetailListView.prototype._allowFieldSelection =
448 function(id, field) {
449 	// allow left selection if clicking on blank icon
450 	if (field == ZmItem.F_EXPAND) {
451 		var item = appCtxt.getById(id);
452 		return (item && !this._isExpandable(item));
453 	} else {
454 		return ZmListView.prototype._allowFieldSelection.apply(this, arguments);
455 	}
456 };
457 
458 // listeners
459 
460 ZmDetailListView.prototype._sortColumn =
461 function(columnItem, bSortAsc) {
462 
463 	// call base class to save the new sorting pref
464 	ZmBriefcaseBaseView.prototype._sortColumn.apply(this, arguments);
465 
466 	var query = this._controller.getSearchString();
467 	var queryHint = this._controller.getSearchStringHint();
468 
469 	if (this._sortByString && (query || queryHint)) {
470 		var params = {
471 			query:		query,
472 			queryHint:	queryHint,
473 			types:		[ZmItem.BRIEFCASE_ITEM],
474 			sortBy:		this._sortByString
475 		};
476 		appCtxt.getSearchController().search(params);
477 	}
478 };
479 
480 ZmDetailListView.prototype.isMultiColumn =
481 function(controller) {
482 	var ctlr = controller || this._controller;
483 	return !ctlr.isReadingPaneOnRight();
484 };
485 
486 
487 ZmDetailListView.prototype.reRenderListView =
488 function(force) {
489 	var isMultiColumn = this.isMultiColumn();
490 	if (isMultiColumn != this._isMultiColumn || force) {
491 		this._saveState({selection:true, focus:true, scroll:true, expansion:true});
492 		this._isMultiColumn = isMultiColumn;
493 		this.headerColCreated = false;
494 		this._headerList = this._getHeaderList();
495 		this._rowHeight = null;
496 		this._normalClass = isMultiColumn ? DwtListView.ROW_CLASS : ZmDetailListView.ROW_DOUBLE_CLASS;
497 		var list = this._zmList || this.getList() || (new AjxVector());
498 		this.set(list);
499 		this._restoreState();
500 	}
501 };
502 
503 ZmDetailListView.prototype.setSize =
504 function(width, height) {
505 	ZmListView.prototype.setSize.call(this, width, height);
506 	this._resetColWidth();
507 };
508 
509 ZmDetailListView.prototype.resetSize =
510 function(newWidth, newHeight) {
511 	this.setSize(newWidth, newHeight);
512 	var height = (newHeight == Dwt.DEFAULT) ? newHeight : newHeight - DwtListView.HEADERITEM_HEIGHT;
513 	Dwt.setSize(this._parentEl, newWidth, height);
514 };
515 
516 ZmDetailListView.prototype._resetColWidth =
517 function() {
518 
519 	if (!this.headerColCreated) { return; }
520 
521 	var lastColIdx = this._getLastColumnIndex();
522     if (lastColIdx) {
523         var lastCol = this._headerList[lastColIdx];
524 		if (lastCol._field != ZmItem.F_SORTED_BY) {
525 			DwtListView.prototype._resetColWidth.apply(this, arguments);
526 		}
527 	}
528 };
529 
530 ZmDetailListView.prototype._getToolTip =
531 function(params) {
532 
533     if( params.field == ZmItem.F_LOCK){
534         var item = params.item;
535         if(item.locked){
536             var dateFormatter = AjxDateFormat.getDateTimeInstance(AjxDateFormat.LONG, AjxDateFormat.SHORT);
537             var subs = {
538                 title: ZmMsg.checkedOutFile,
539                 fileProperties:	[
540                     {name: ZmMsg.checkoutTo, value:item.lockUser},
541                     {name: ZmMsg.when, value: dateFormatter.format(item.lockTime)}
542                 ]
543             };
544             return AjxTemplate.expand("briefcase.Briefcase#Tooltip", subs);
545         }
546     }
547     
548 	return ZmBriefcaseBaseView.prototype._getToolTip.call(this, params);
549 };
550 
551 ZmDetailListView.prototype._folderChangeListener =
552 function(ev){
553 
554     // make sure this is current list view
555 	if (appCtxt.getCurrentController() != this._controller) { return; }
556 
557     ZmBriefcaseBaseView.prototype._folderChangeListener.call(this, ev);
558 
559     var organizers = ev.getDetail("organizers");
560 	var organizer = (organizers && organizers.length) ? organizers[0] : ev.source;
561     var currentFolderId = this._controller._folderId;
562 
563     var refresh = false;
564     if (ev.event == ZmEvent.E_CREATE) {
565         if(organizer && currentFolderId == organizer.parent.id)
566             refresh = true;
567     }else if(ev.event == ZmEvent.E_MODIFY) {
568         var fields = ev.getDetail("fields");        
569         if( fields[ZmOrganizer.F_NAME] || fields[ZmOrganizer.F_COLOR] )
570             refresh = true;
571     }else if(ev.event == ZmEvent.E_MOVE || ev.event == ZmEvent.E_DELETE){
572         refresh = true;
573         if (this.getDnDSelection() && this.getDnDSelection instanceof AjxVector)
574             this.dragDeselect(this.getDnDSelection().get(0));
575         else if (this.getDnDSelection())
576             this.dragDeselect(this.getDnDSelection());
577         if(currentFolderId != organizer.id){
578             this.collapseAll();
579         }
580     }
581 
582     if(refresh) {
583         appCtxt.getApp(ZmApp.BRIEFCASE).search({folderId: currentFolderId});
584     }
585         
586 };
587 
588 //drag and drop listeners
589 ZmDetailListView.prototype._dropListener =
590 function(ev) {
591     var data = ev.srcData.data;
592 	var div = this.getTargetItemDiv(ev.uiEvent);
593 	var dropFolder = this.getItemFromElement(div);
594 
595     //handle drag from tree to listview by calling controller
596     if (ev.srcData && ev.srcData.controller != appCtxt.getCurrentController()){
597         appCtxt.getCurrentController()._dropListener(ev);
598         return;
599     }
600 
601 	// only briefcase items can be dropped on us
602 	if (ev.action == DwtDropEvent.DRAG_ENTER) {
603 		ev.doIt = (dropFolder && (dropFolder instanceof ZmBriefcaseFolderItem) && (dropFolder.folder && dropFolder.folder.mayContain(data)));
604 		DBG.println(AjxDebug.DBG3, "DRAG_ENTER: doIt = " + ev.doIt);
605         this.dragSelect(div);
606 	} else if (ev.action == DwtDropEvent.DRAG_DROP) {
607         this.dragDeselect(div);
608 		appCtxt.getCurrentController()._doMove(data, dropFolder.folder);
609 	} else if (ev.action == DwtDropEvent.DRAG_LEAVE) {
610 		view.dragDeselect(div);
611 	} else if (ev.action == DwtDropEvent.DRAG_OP_CHANGED) {
612 		// nothing
613 	}
614 
615 };
616 
617 ZmDetailListView.prototype._dragListener =
618 function(ev) {
619 	if (ev.action == DwtDragEvent.SET_DATA) {
620 		ev.srcData = {data: ev.srcControl.getDnDSelection(), controller: this};
621 	}
622 };
623 
624 ZmDetailListView.prototype._createHeader =
625 function(htmlArr, idx, headerCol, i, numCols, id, defaultColumnSort) {
626 
627 	if (headerCol._field == ZmItem.F_SORTED_BY) {
628 		var field = headerCol._field;
629 		var textTdId = this._itemCountTextTdId = DwtId.makeId(this.view, ZmSetting.RP_RIGHT, "td");
630 		htmlArr[idx++] = "<td id='";
631 		htmlArr[idx++] = id;
632 		htmlArr[idx++] = "' class='";
633 		htmlArr[idx++] = (id == this._currentColId)	? "DwtListView-Column DwtListView-ColumnActive'" :
634 													  "DwtListView-Column'";
635 		htmlArr[idx++] = " width='auto'><table width='100%'><tr><td id='";
636 		htmlArr[idx++] = DwtId.getListViewHdrId(DwtId.WIDGET_HDR_LABEL, this._view, field);
637 		htmlArr[idx++] = "' class='DwtListHeaderItem-label'>";
638 		htmlArr[idx++] = headerCol._label;
639 		htmlArr[idx++] = "</td>";
640 
641 		// sort icon
642 		htmlArr[idx++] = "<td class='itemSortIcon' id='";
643 		htmlArr[idx++] = DwtId.getListViewHdrId(DwtId.WIDGET_HDR_ARROW, this._view, field);
644 		htmlArr[idx++] = "'>";
645 		htmlArr[idx++] = AjxImg.getImageHtml(this._bSortAsc ? "ColumnUpArrow" : "ColumnDownArrow");
646 		htmlArr[idx++] = "</td>";
647 
648 		// item count text
649 		htmlArr[idx++] = "<td align=right class='itemCountText' id='";
650 		htmlArr[idx++] = textTdId;
651 		htmlArr[idx++] = "'></td></tr></table></div></td>";
652 	} else {
653 		return DwtListView.prototype._createHeader.apply(this, arguments);
654 	}
655 };
656 
657 ZmDetailListView.prototype._initDragAndDrop =
658 function() {
659     this._dnd = new ZmDragAndDrop(this);
660 };
661 
662 ZmDetailListView.prototype._submitMyComputerAttachments =
663 function(files, node, isInline) {
664 	var selectionCallback = this._controller._uploadFileListener.bind(this._controller);
665 	var briefcaseApp = appCtxt.getApp(ZmApp.BRIEFCASE);
666 	briefcaseApp.initExternalDndUpload(files, node, isInline, selectionCallback);
667 };
668 
669 
670 ZmDetailListView.prototype._handleRename = function(item) {
671 	// Always collapse - should be harmless if already collapsed or has no versions.  We need
672 	// to insure any divs created for revisions are removed before moving the item - otherwise
673 	// they will be reused in their old location.
674 	this.collapse(item, true);
675 
676 	this.removeItem(item);
677 	var indices = this._sortIndex(this._list, item);
678 	if (indices) {
679 		this.addItem(item, indices.displayIndex, false, indices.listIndex);
680 	}
681 	item._nameUpdated = false;
682 };
683 
684 
685 /**
686  * Override the sorted Index calculation.  The DetailListView has a mismatch between its list
687  * and the actual displayed rows, which can contain versions of a file.
688  *
689  * @param	{AjxVector}			list		  vector containing the file entries
690  * @param	{ZmBriefcaseItem}	item		  file entry - find the position to insert it
691  *
692  * @return	Object                            See DwtListView.addItem
693  *			{number}			displayIndex  the index at which to add item to list view
694  *			{number}			listIndex	  index at which to add item to list
695  */
696 ZmDetailListView.prototype._sortIndex = function(list, item){
697 	if (!list) {
698 		return null;
699 	}
700 
701 	var lItem;
702 	var rowIds;
703 	var a = list.getArray();
704 	var displayIndex = 0;
705 	var itemName = item.name.toLowerCase();
706 	var i;
707 	for (i = 0; i < a.length; i++) {
708 		lItem = a[i];
709 		if (!lItem.isFolder && (itemName < lItem.name.toLowerCase())) {
710 			break;
711 		}
712 		rowIds = this._itemRowIdList[lItem.id];
713 		if (rowIds && rowIds.length) {
714 			displayIndex += rowIds.length + 1;
715 		} else {
716 			displayIndex++;
717 		}
718 	}
719 	// listIndex = insertion into the underlying list vector.
720 	// displayIndex:
721 	return { listIndex: i, displayIndex: displayIndex};
722 };