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