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 * This file contains the briefcase controller class. 27 * 28 */ 29 30 /** 31 * Creates the briefcase controller. 32 * @class 33 * This class represents the briefcase controller for the content view used by the briefcase application. 34 * 35 * @author Parag Shah 36 * 37 * @param {DwtControl} container the containing shell 38 * @param {ZmApp} app the containing application 39 * @param {constant} type type of controller 40 * @param {string} sessionId the session id 41 * @param {ZmSearchResultsController} searchResultsController containing controller 42 * 43 * @extends ZmListController 44 */ 45 ZmBriefcaseController = function(container, app, type, sessionId, searchResultsController) { 46 47 if (arguments.length == 0) { return; } 48 49 ZmListController.apply(this, arguments); 50 51 this._idMap = {}; 52 53 this._listChangeListener = this._fileListChangeListener.bind(this); 54 55 this._listeners[ZmOperation.OPEN_FILE] = this._openFileListener.bind(this); 56 this._listeners[ZmOperation.SAVE_FILE] = this._saveFileListener.bind(this); 57 this._listeners[ZmOperation.SEND_FILE] = this._sendFileListener.bind(this); 58 this._listeners[ZmOperation.SEND_FILE_AS_ATT] = this._sendFileAsAttachmentListener.bind(this); 59 this._listeners[ZmOperation.NEW_FILE] = this._uploadFileListener.bind(this); 60 this._listeners[ZmOperation.VIEW_FILE_AS_HTML] = this._viewAsHtmlListener.bind(this); 61 this._listeners[ZmOperation.EDIT_FILE] = this._editFileListener.bind(this); 62 this._listeners[ZmOperation.RENAME_FILE] = this._renameFileListener.bind(this); 63 this._listeners[ZmOperation.DETACH_WIN] = this._newWinListener.bind(this); 64 65 this._listeners[ZmOperation.NEW_DOC] = this._handleDoc.bind(this, ZmOperation.NEW_DOC); 66 67 this._listeners[ZmOperation.CHECKIN] = this._handleCheckin.bind(this); 68 this._listeners[ZmOperation.CHECKOUT] = this._checkoutListener.bind(this); 69 this._listeners[ZmOperation.DISCARD_CHECKOUT] = this._handleDiscardCheckout.bind(this); 70 this._listeners[ZmOperation.RESTORE_VERSION] = this._restoreVerListener.bind(this); 71 72 if (this.supportsDnD()) { 73 this._dragSrc = new DwtDragSource(Dwt.DND_DROP_MOVE); 74 this._dragSrc.addDragListener(this._dragListener.bind(this)); 75 } 76 77 this._parentView = {}; 78 }; 79 80 ZmBriefcaseController.prototype = new ZmListController; 81 ZmBriefcaseController.prototype.constructor = ZmBriefcaseController; 82 83 ZmBriefcaseController.prototype.isZmBriefcaseController = true; 84 ZmBriefcaseController.prototype.toString = function() { return "ZmBriefcaseController"; }; 85 86 // Constants 87 ZmBriefcaseController._VIEWS = {}; 88 ZmBriefcaseController._VIEWS[ZmId.VIEW_BRIEFCASE_DETAIL] = "ZmPreviewPaneView"; 89 90 ZmBriefcaseController.RP_IDS = [ZmSetting.RP_BOTTOM, ZmSetting.RP_RIGHT, ZmSetting.RP_OFF]; 91 92 // reading pane options 93 ZmBriefcaseController.PREVIEW_PANE_TEXT = {}; 94 ZmBriefcaseController.PREVIEW_PANE_TEXT[ZmSetting.RP_OFF] = ZmMsg.previewPaneOff; 95 ZmBriefcaseController.PREVIEW_PANE_TEXT[ZmSetting.RP_BOTTOM] = ZmMsg.previewPaneAtBottom; 96 ZmBriefcaseController.PREVIEW_PANE_TEXT[ZmSetting.RP_RIGHT] = ZmMsg.previewPaneOnRight; 97 98 ZmBriefcaseController.PREVIEW_PANE_ICON = {}; 99 ZmBriefcaseController.PREVIEW_PANE_ICON[ZmSetting.RP_OFF] = "SplitPaneOff"; 100 ZmBriefcaseController.PREVIEW_PANE_ICON[ZmSetting.RP_BOTTOM] = "SplitPane"; 101 ZmBriefcaseController.PREVIEW_PANE_ICON[ZmSetting.RP_RIGHT] = "SplitPaneVertical"; 102 103 // convert key mapping to view menu item 104 ZmBriefcaseController.ACTION_CODE_TO_MENU_ID = {}; 105 ZmBriefcaseController.ACTION_CODE_TO_MENU_ID[ZmKeyMap.READING_PANE_OFF] = ZmSetting.RP_OFF; 106 ZmBriefcaseController.ACTION_CODE_TO_MENU_ID[ZmKeyMap.READING_PANE_BOTTOM] = ZmSetting.RP_BOTTOM; 107 ZmBriefcaseController.ACTION_CODE_TO_MENU_ID[ZmKeyMap.READING_PANE_RIGHT] = ZmSetting.RP_RIGHT; 108 109 //List Views 110 111 ZmBriefcaseController.LIST_VIEW = {}; 112 ZmBriefcaseController.LIST_VIEW[ZmId.VIEW_BRIEFCASE_DETAIL] = {image: "GenericDoc", text: ZmMsg.byLatestFile }; 113 ZmBriefcaseController.LIST_VIEW[ZmId.VIEW_BRIEFCASE_REVISION] = {image: "VersionHistory", text: ZmMsg.byVersionHistory }; 114 115 /** 116 * The list view as a whole is the drop target, since it's the lowest-level widget. Still, we 117 * need to find out which item got dropped onto, so we get that from the original UI event 118 * (a mouseup). The header is within the list view, but not an item, so it's not a valid drop 119 * target. One drawback of having the list view be the drop target is that we can't exercise 120 * fine-grained control on what's a valid drop target. If you enter via an item and then drag to 121 * the header, it will appear to be valid. 122 * 123 * @protected 124 */ 125 ZmBriefcaseController.prototype._dropListener = 126 function(ev) { 127 var view = this._listView[this._currentViewId]; 128 var div = view.getTargetItemDiv(ev.uiEvent); 129 var item = view.getItemFromElement(div); 130 if(!item || !( item.isRevision || item.isFolder) ) { 131 ZmListController.prototype._dropListener.call(this,ev); 132 } else { 133 ev.doIt = false; 134 } 135 } 136 137 ZmBriefcaseController.prototype._standardActionMenuOps = 138 function() { 139 return [ZmOperation.TAG_MENU, ZmOperation.DELETE, ZmOperation.MOVE]; 140 }; 141 142 /** 143 * @private 144 */ 145 ZmBriefcaseController.prototype._getSecondaryToolBarOps = 146 function() { 147 var list = []; 148 if (appCtxt.get(ZmSetting.MAIL_ENABLED)) { 149 list.push(ZmOperation.SEND_FILE, ZmOperation.SEND_FILE_AS_ATT, ZmOperation.SEP); 150 } 151 list.push(ZmOperation.DETACH_WIN, ZmOperation.SEP); 152 153 list.push(ZmOperation.CHECKOUT, ZmOperation.CHECKIN, ZmOperation.DISCARD_CHECKOUT, ZmOperation.RESTORE_VERSION); 154 155 list.push(ZmOperation.SEP); 156 list.push(ZmOperation.RENAME_FILE); 157 158 return list; 159 }; 160 161 162 ZmBriefcaseController.prototype._getToolBarOps = 163 function() { 164 var ops = [ZmOperation.NEW_FILE, 165 ZmOperation.SAVE_FILE, 166 ZmOperation.SEP, 167 ZmOperation.EDIT_FILE, 168 ZmOperation.SEP, 169 ZmOperation.DELETE, 170 ZmOperation.SEP, 171 ZmOperation.MOVE_MENU, 172 ZmOperation.TAG_MENU 173 ]; 174 175 /*if (appCtxt.get(ZmSetting.DOCS_ENABLED)) { 176 ops.push(ZmOperation.NEW_DOC,ZmOperation.SEP); 177 }*/ 178 179 180 return ops; 181 }; 182 183 ZmBriefcaseController.prototype._getRightSideToolBarOps = 184 function(noViewMenu) { 185 return [ZmOperation.VIEW_MENU]; 186 }; 187 188 189 ZmBriefcaseController.prototype._handleDoc = 190 function(op) { 191 this._app.handleOp(op); 192 }; 193 194 ZmBriefcaseController.prototype._initializeToolBar = 195 function(view) { 196 197 if (!this._toolbar[view]) { 198 ZmListController.prototype._initializeToolBar.call(this, view); 199 this._setupViewMenu(view, true); 200 var toolbar = this._toolbar[view]; 201 toolbar.addFiller(); 202 this._initializeNavToolBar(view); 203 appCtxt.notifyZimlets("initializeToolbar", [this._app, toolbar, this, view], {waitUntilLoaded:true}); 204 } else { 205 this._setupDeleteButton(this._toolbar[view]); 206 this._setupViewMenu(view, false); 207 } 208 }; 209 210 // If we're in the Trash folder, change the "Delete" button tooltip 211 ZmBriefcaseController.prototype._setupDeleteButton = 212 function(parent) { 213 var folder = this._getSearchFolder(); 214 var inTrashFolder = (folder && folder.nId == ZmFolder.ID_TRASH); 215 var tooltip = inTrashFolder ? ZmMsg.deletePermanentTooltip : ZmMsg.deleteTooltip; 216 var deleteButton = parent.getButton(ZmOperation.DELETE); 217 if(deleteButton){ 218 deleteButton.setToolTipContent(ZmOperation.getToolTip(ZmOperation.DELETE, this.getKeyMapName(), tooltip)); 219 } 220 }; 221 222 ZmBriefcaseController.prototype._initializeNavToolBar = 223 function(view) { 224 this._itemCountText[view] = this._toolbar[view].getButton(ZmOperation.TEXT); 225 }; 226 227 ZmBriefcaseController.prototype._resetOperations = 228 function(parent, num) { 229 if (!parent) { return; } 230 231 // call base class 232 ZmListController.prototype._resetOperations.call(this, parent, num); 233 234 var items = this._listView[this._currentViewId].getSelection(); 235 var isFolderSelected=false, noOfFolders = 0, isRevisionSelected=false, isBriefcaseItemSelected=false, isMixedSelected=false; 236 var isWebDocSelected= false, hasLocked = false, allLocked = true, sameLockOwner=true; 237 var hasHighestRevisionSelected = false, hasOldRevisionSelected = false; 238 if (items) { 239 for (var i = 0; i < items.length; i++) { 240 var item = items[i]; 241 if (item.isFolder) { 242 isFolderSelected = true; 243 noOfFolders++; 244 }else if(item.isRevision){ 245 isRevisionSelected = true; 246 if(item.parent.version == item.version){ 247 hasHighestRevisionSelected = true; 248 } 249 else { 250 hasOldRevisionSelected = true; 251 } 252 }else{ 253 isBriefcaseItemSelected = true; 254 } 255 256 isWebDocSelected = isWebDocSelected || ( !item.isFolder && item.isWebDoc() ); 257 258 allLocked = allLocked && item.locked; 259 260 hasLocked = hasLocked || item.locked; 261 262 sameLockOwner = sameLockOwner && (item.locked && item.lockUser == appCtxt.getActiveAccount().name); 263 } 264 } 265 266 isMixedSelected = isFolderSelected ? (isBriefcaseItemSelected || isRevisionSelected) : (isBriefcaseItemSelected && isRevisionSelected); 267 268 var briefcase = appCtxt.getById(this._folderId); 269 if(!(briefcase instanceof ZmBriefcase)){ 270 briefcase = null; 271 } 272 var isTrash = (briefcase && briefcase.nId == ZmOrganizer.ID_TRASH); 273 var isShared = ((briefcase && briefcase.nId != ZmOrganizer.ID_TRASH && briefcase.isShared())); 274 var isReadOnly = briefcase ? briefcase.isReadOnly() : false; 275 var isMultiFolder = (noOfFolders > 1); 276 var isItemSelected = (num>0); 277 var isZimbraAccount = appCtxt.getActiveAccount().isZimbraAccount; 278 var isMailEnabled = appCtxt.get(ZmSetting.MAIL_ENABLED); 279 var isAdmin = briefcase && briefcase.isAdmin(); 280 281 var item = items[0]; 282 //bug 65351 283 // treat the latest revision selection as if it was a file selection. 284 // isOldRevision is true if the item is a revision but not the latest. 285 var isOldRevision = hasOldRevisionSelected ? true : item && item.revision && !hasHighestRevisionSelected; 286 287 parent.enable([ZmOperation.SEND_FILE, ZmOperation.SEND_FILE_AS_ATT], (isZimbraAccount && isMailEnabled && isItemSelected && !isMultiFolder && !isFolderSelected)); 288 parent.enable(ZmOperation.TAG_MENU, (!isReadOnly && isItemSelected && !isFolderSelected && !isOldRevision)); 289 parent.enable([ZmOperation.NEW_FILE, ZmOperation.VIEW_MENU], true); 290 parent.enable([ZmOperation.NEW_DOC], true); 291 parent.enable([ZmOperation.MOVE, ZmOperation.MOVE_MENU], ( isItemSelected && !isReadOnly && !isShared && !isOldRevision)); 292 parent.enable(ZmOperation.NEW_FILE, !(isTrash || isReadOnly)); 293 parent.enable(ZmOperation.DETACH_WIN, (isItemSelected && !isFolderSelected && num==1)); 294 295 var firstItem = items && items[0]; 296 var isWebDoc = firstItem && !firstItem.isFolder && firstItem.isWebDoc(); 297 var isLocked = firstItem && !firstItem.isFolder && firstItem.locked; 298 var isLockOwner = isLocked && (item.lockUser == appCtxt.getActiveAccount().name); 299 300 301 //Rename Operation 302 parent.enable(ZmOperation.RENAME_FILE, ( num ==1 && !isFolderSelected && !isReadOnly && !isOldRevision && (isLocked ? isLockOwner : true) )); 303 304 //Download - Files 305 parent.enable(ZmOperation.SAVE_FILE, num >0 && (!isFolderSelected || isBriefcaseItemSelected)); 306 307 // Edit 308 parent.enable(ZmOperation.OPEN_FILE, (num == 1 && isWebDoc)); 309 parent.enable(ZmOperation.EDIT_FILE, !isReadOnly && ( !isLocked || isLockOwner ) && isWebDoc && !isOldRevision && num == 1); 310 311 //Delete Operation 312 parent.enable(ZmOperation.DELETE, (!isReadOnly && isItemSelected && (hasHighestRevisionSelected ? !hasOldRevisionSelected : true) && !isMixedSelected && (isLocked ? isLockOwner : true))); 313 314 if(parent && parent instanceof ZmActionMenu){ 315 316 //Open - webDocs 317 parent.getOp(ZmOperation.OPEN_FILE) && parent.getOp(ZmOperation.OPEN_FILE).setVisible(isItemSelected && !isMultiFolder && isWebDoc); 318 319 } 320 //Case 1: Multiple Admins 321 //Case 2: Stale Lock ( Handle exception ) 322 323 //Checkin 324 var op = parent.getOp(ZmOperation.CHECKIN); 325 if (op) { 326 var checkinEnabled = !isReadOnly && isLockOwner && !isWebDoc && !isOldRevision; 327 op.setVisible(checkinEnabled); 328 parent.enable(ZmOperation.CHECKIN, checkinEnabled && num == 1); 329 } 330 331 //Checkout 332 op = parent.getOp(ZmOperation.CHECKOUT); 333 if (op) { 334 var checkoutEnabled = !isReadOnly && !hasLocked && !isRevisionSelected && !isFolderSelected; 335 op.setVisible(!isOldRevision && !isLocked); 336 parent.enable(ZmOperation.CHECKOUT, checkoutEnabled); 337 } 338 339 //Discard Checkout 340 op = parent.getOp(ZmOperation.DISCARD_CHECKOUT); 341 if (op) { 342 var discardCheckoutEnabled = sameLockOwner && !isRevisionSelected; 343 op.setVisible(discardCheckoutEnabled); 344 parent.enable(ZmOperation.DISCARD_CHECKOUT, discardCheckoutEnabled && (isAdmin || sameLockOwner || !isShared)); 345 } 346 347 //Versioning 348 op = parent.getOp(ZmOperation.RESTORE_VERSION); 349 if (op) { 350 var versionEnabled = (!isReadOnly && num == 1 && isOldRevision); 351 var isHightestVersion = item && item.isRevision && ( item.parent.version == item.version ); 352 op.setVisible(isOldRevision); 353 parent.enable(ZmOperation.RESTORE_VERSION, versionEnabled && !isHightestVersion); 354 } 355 356 var isDocOpEnabled = !(isTrash || isReadOnly); 357 if (appCtxt.get(ZmSetting.DOCS_ENABLED)) { 358 parent.enable(ZmOperation.NEW_DOC, isDocOpEnabled); 359 } 360 361 // ZmShare is not present when the virtual account loads 362 AjxPackage.require("Briefcase"); 363 AjxPackage.require("Share"); 364 365 if (appCtxt.isExternalAccount() && items.length && isItemSelected) { 366 367 var roleFromPerm = ZmShare.getRoleFromPerm(briefcase.perm); 368 369 if (roleFromPerm === ZmShare.ROLE_NONE) { 370 parent.enable ([ZmOperation.SEND_FILE, 371 ZmOperation.SEND_FILE_AS_ATT, 372 ZmOperation.RENAME_FILE, 373 ZmOperation.MOVE, 374 ZmOperation.MOVE_MENU, 375 ZmOperation.NEW_FILE, 376 ZmOperation.TAG_MENU, 377 ZmOperation.EDIT_FILE, 378 ZmOperation.OPEN_FILE, 379 ZmOperation.CHECKIN, 380 ZmOperation.CHECKOUT, 381 ZmOperation.DISCARD_CHECKOUT, 382 ZmOperation.RESTORE_VERSION, 383 ZmOperation.DETACH_WIN, 384 ZmOperation.DELETE 385 ], false); 386 parent.setItemVisible(ZmOperation.TAG_MENU, false); 387 } 388 else if (roleFromPerm === ZmShare.ROLE_MANAGER) { 389 parent.enable ([ 390 ZmOperation.RENAME_FILE, 391 ZmOperation.NEW_FILE, 392 ZmOperation.OPEN_FILE, 393 ZmOperation.CHECKIN, 394 ZmOperation.CHECKOUT, 395 ZmOperation.DISCARD_CHECKOUT, 396 ZmOperation.DETACH_WIN, 397 ZmOperation.DELETE 398 ], true); 399 } 400 } 401 }; 402 403 ZmBriefcaseController.prototype._getTagMenuMsg = 404 function() { 405 return ZmMsg.tagFile; 406 }; 407 408 ZmBriefcaseController.prototype._doDelete = function(items, hardDelete) { 409 410 items = items || this._listView[this._currentViewId].getSelection(); 411 var item = items instanceof Array ? items[0] : items; 412 if (!item) { 413 return; 414 } 415 416 var message = items.length > 1 ? item.isRevision ? ZmMsg.confirmPermanentDeleteItemList : ZmMsg.confirmDeleteItemList : null; 417 if (!message) { 418 if (hardDelete || this._folderId == String(ZmOrganizer.ID_TRASH) || (item.isRevision && item.parent.version !== item.version)) { 419 var pattern = ZmMsg.confirmPermanentDeleteItem; 420 } 421 else { 422 var pattern = ZmMsg.confirmDeleteItem; 423 } 424 var delMsgFormatter = new AjxMessageFormat(pattern); 425 message = delMsgFormatter.format(AjxStringUtil.htmlEncode(item.name)); 426 } 427 428 var dialog = appCtxt.getConfirmationDialog(); 429 if (AjxEnv.isIE || AjxEnv.isModernIE) { 430 dialog.addPopupListener(ZmBriefcaseController._onDeleteDialogPopup); 431 } 432 dialog.popup(message, this._doDelete2.bind(this, items, hardDelete)); 433 }; 434 435 ZmBriefcaseController.prototype._doDelete2 = function(items, hardDelete) { 436 437 var item = items instanceof Array ? items[0] : items, 438 i; 439 440 if (item.isRevision && item.parent.version !== item.version) { 441 var view = this._parentView[this._currentViewId]; 442 view.deleteVersions(items); 443 } 444 else if (item.isFolder) { 445 //Bug fix # 80600 force the BatchCommand to use JSON, mimicking the way right click delete behaves 446 var delBatchCmd = new ZmBatchCommand(true, null, true), folder; 447 for (i = 0; i < items.length; i++) { 448 folder = items[i].folder; 449 if (folder.isHardDelete()) { 450 delBatchCmd.add(new AjxCallback(folder, folder._delete, [delBatchCmd])); 451 } 452 else { 453 var trashFolder = appCtxt.getById(ZmFolder.ID_TRASH); 454 delBatchCmd.add(new AjxCallback(folder, folder.move, [trashFolder, false, null, delBatchCmd])); 455 } 456 } 457 delBatchCmd.run(); 458 } 459 else { 460 for (i = 0; i < items.length; i++) { 461 if (items[i].isRevision) { 462 items[i] = items[i].parent; 463 } 464 } 465 ZmListController.prototype._doDelete.call(this, items, hardDelete, null, true); 466 } 467 }; 468 469 // view management 470 471 ZmBriefcaseController.getDefaultViewType = 472 function() { 473 return ZmId.VIEW_BRIEFCASE_DETAIL; 474 }; 475 ZmBriefcaseController.prototype.getDefaultViewType = ZmBriefcaseController.getDefaultViewType; 476 477 ZmBriefcaseController.prototype._createNewView = 478 function(view) { 479 480 var viewType = appCtxt.getViewTypeFromId(view); 481 var viewCtor = eval(ZmBriefcaseController._VIEWS[viewType]); 482 this._parentView[view] = new viewCtor(this._container, this, this._dropTgt); 483 var listView = this._parentView[view].getListView(); 484 if (this._dragSrc) { 485 listView.setDragSource(this._dragSrc); 486 } 487 488 return listView; 489 }; 490 491 ZmBriefcaseController.prototype._setViewContents = 492 function(view) { 493 // If the controller is being used via the ZmBriefcaseTabView (for attaching briefcase files 494 // to a mail message), then there is only a list view in use, not a parent with multiple views. 495 if (this._parentView[view]) { 496 this._parentView[view].set(this._list, this._switchView); 497 } 498 this._switchView = false; 499 }; 500 501 ZmBriefcaseController.prototype._getDefaultFocusItem = 502 function() { 503 return this._listView[this._currentViewId]; 504 }; 505 506 // Returns a list of subfolders of the given folder, as ZmBriefcaseItem objects 507 ZmBriefcaseController.prototype._getSubfolders = 508 function(folderId) { 509 510 var folderId = folderId || this._currentSearch.folderId; 511 var folder = folderId && appCtxt.getById(folderId); 512 var subfolders = []; 513 if (folder) { 514 var children = folder.children; 515 for (var i = 0, len = children.size(); i < len; i++) { 516 folder = children.get(i); 517 if(folder.type == ZmOrganizer.BRIEFCASE) 518 subfolders.push(new ZmBriefcaseFolderItem(children.get(i))); 519 } 520 } 521 522 return subfolders; 523 }; 524 525 526 // view management 527 528 /** 529 * Shows the search results. 530 * 531 * @param {Object} results the search results 532 */ 533 ZmBriefcaseController.prototype.show = 534 function(results) { 535 536 this._folderId = results && results.search && results.search.folderId; 537 this.setList(results.getResults(ZmItem.BRIEFCASE_ITEM)); 538 this._list.setHasMore(results.getAttribute("more")); 539 540 ZmListController.prototype.show.call(this, results, this._currentViewId); 541 542 this._setup(this._currentViewId); 543 544 // start fresh with search results 545 var lv = this._listView[this._currentViewId]; 546 lv.offset = 0; 547 lv._folderId = this._folderId; 548 549 var elements = this.getViewElements(this._currentViewId, this._parentView[this._currentViewId]); 550 551 this._setView({ view: this._currentViewId, 552 viewType: this._currentViewType, 553 noPush: this.isSearchResults, 554 elements: elements, 555 isAppView: true}); 556 if (this.isSearchResults) { 557 // if we are switching views, make sure app view mgr is up to date on search view's components 558 appCtxt.getAppViewMgr().setViewComponents(this.searchResultsController.getCurrentViewId(), elements, true); 559 } 560 this._resetNavToolBarButtons(); 561 }; 562 563 ZmBriefcaseController.prototype.getFolderId = function() { 564 return this._folderId; 565 } 566 567 /** 568 * Change how briefcase items are displayed. 569 * 570 * @param {constant} view the view to show 571 * @param {Boolean} force if <code>true</code>, render view even if it's the current view 572 */ 573 ZmBriefcaseController.prototype.switchView = 574 function(view, force) { 575 576 var viewChanged = (force || view != this._currentViewId); 577 578 if (viewChanged) { 579 var lv = this._listView[this._currentViewId]; 580 if (lv) { 581 lv.cleanup(); 582 } 583 this._switchView = true; 584 this._currentViewId = view; 585 this._setup(view); 586 } 587 this._resetOperations(this._toolbar[view], 0); 588 589 if (viewChanged) { 590 var elements = this.getViewElements(view, this._parentView[view]); 591 592 this._setView({ view: view, 593 viewType: this._currentViewType, 594 elements: elements, 595 isAppView: true}); 596 this._resetNavToolBarButtons(); 597 } 598 Dwt.setTitle(this.getCurrentView().getTitle()); 599 }; 600 601 ZmBriefcaseController.prototype._preHideCallback = 602 function() { 603 604 var lv = this._listView[this._currentViewId]; 605 if(lv) lv.cleanup(); 606 607 return ZmController.prototype._preHideCallback.call(this); 608 }; 609 610 ZmBriefcaseController.prototype.getItemById = 611 function(itemId) { 612 return (this._idMap[itemId] ? this._idMap[itemId].item : null); 613 }; 614 615 ZmBriefcaseController.prototype.__popupUploadDialog = 616 function(title, callback) { 617 618 619 var folderId = this._folderId; 620 if(!folderId || folderId == ZmOrganizer.ID_TRASH) 621 folderId = ZmOrganizer.ID_BRIEFCASE; 622 623 if(this.chkFolderPermission(folderId)){ 624 var cFolder = appCtxt.getById(folderId); 625 var uploadDialog = appCtxt.getUploadDialog(); 626 uploadDialog.popup(this, cFolder, callback, title, null, false, true, true, ZmBriefcaseApp.ACTION_KEEP_MINE); 627 } 628 }; 629 630 ZmBriefcaseController.prototype.chkFolderPermission = 631 function(folderId){ 632 var briefcase = appCtxt.getById(folderId); 633 if(briefcase.isRemote() && briefcase.isReadOnly()){ 634 var dialog = appCtxt.getMsgDialog(); 635 dialog.setMessage(ZmMsg.errorPermissionCreate, DwtMessageDialog.WARNING_STYLE); 636 dialog.popup(); 637 return false; 638 } 639 return true; 640 }; 641 642 ZmBriefcaseController.prototype._listSelectionListener = 643 function(ev) { 644 Dwt.setLoadingTime("ZmBriefcaseItem"); 645 ZmListController.prototype._listSelectionListener.call(this, ev); 646 647 if (ev.detail == DwtListView.ITEM_DBL_CLICKED) { 648 var item = ev.item; 649 650 if(item.isFolder){ 651 this._app.search({folderId:item.id}); 652 return; 653 } 654 655 var restUrl = item.getRestUrl(false, false, true); //get it with the version number even if clicked on the base item (see ZmBriefcaseBaseItem.prototype.getRestUrl in ZmBriefcaseItem.js) 656 //added for bug: 45150 657 restUrl = AjxStringUtil.fixCrossDomainReference(restUrl); 658 if (item.isWebDoc()) { 659 restUrl += (restUrl.match(/\?/) ? "&" : "?") + "localeId=" + AjxEnv.DEFAULT_LOCALE; 660 661 } 662 if (restUrl) { 663 if(item.isDownloadable() && !this._alwaysOpenInNewWindow(item)) { 664 this._downloadFile(restUrl); 665 }else { 666 window.open(restUrl, this._getWindowName(item.name), item.isWebDoc() ? "" : ZmBriefcaseApp.getDocWindowFeatures()); 667 } 668 } 669 } 670 }; 671 672 ZmBriefcaseController.prototype._alwaysOpenInNewWindow = 673 function(item){ 674 675 return (item.contentType == ZmMimeTable.APP_ADOBE_PDF && this.hasPDFReader()) 676 || (item.contentType == ZmMimeTable.TEXT_XML) || (item.contentType == ZmMimeTable.APP_XML); 677 678 }; 679 680 ZmBriefcaseController.prototype.hasPDFReader = 681 function(){ 682 if(AjxUtil.isUndefined(this._hasPDFReader)){ 683 this._hasPDFReader = AjxPluginDetector.detectPDFReader(); 684 } 685 return this._hasPDFReader; 686 } 687 688 ZmBriefcaseController.prototype._listActionListener = 689 function(ev) { 690 691 var item = ev.item; 692 693 if (item && item.isFolder) { 694 ev.detail = DwtTree.ITEM_ACTIONED; 695 var overviewController = appCtxt.getOverviewController(); 696 var treeController = overviewController.getTreeController(ZmOrganizer.BRIEFCASE); 697 item.setData(ZmTreeView.KEY_TYPE, ZmOrganizer.BRIEFCASE); 698 item.setData(Dwt.KEY_OBJECT, item.folder); 699 item.setData(ZmTreeView.KEY_ID, this._app.getOverviewId()); 700 item.setData(Dwt.KEY_ID, item.id); 701 treeController._treeViewListener(ev); 702 return; 703 } 704 705 ZmListController.prototype._listActionListener.call(this, ev); 706 707 var actionMenu = this.getActionMenu(); 708 actionMenu.popup(0, ev.docX, ev.docY); 709 if (ev.ersatz) { 710 actionMenu.setSelectedItem(0); // menu popped up via keyboard nav 711 } 712 713 714 }; 715 716 ZmBriefcaseController.prototype._restoreVerListener = 717 function(){ 718 var view = this._parentView[this._currentViewId]; 719 view._restoreVerListener(); 720 721 }; 722 723 //Checkin/Checkout 724 725 ZmBriefcaseController.prototype._checkoutListener = 726 function(){ 727 var items = this._getSelectedItems(); 728 if(items.length > 1){ 729 for(var i=0; i< items.length; i++){ 730 var item = items[i]; 731 if(item && item instanceof ZmBriefcaseItem){ 732 this.checkout(item); 733 } 734 } 735 }else{ 736 var item = items[0]; 737 if(item && item instanceof ZmBriefcaseItem){ 738 this.checkout(item, item.isWebDoc() ? null : new AjxCallback(this, this._postCheckout, item)); 739 } 740 } 741 }; 742 743 ZmBriefcaseController.prototype._postCheckout = 744 function(item){ 745 if(AjxEnv.isSafari){ 746 setTimeout(AjxCallback.simpleClosure(this.downloadFile, this, item), 100); 747 }else{ 748 this.downloadFile(item); 749 } 750 }; 751 752 ZmBriefcaseController.prototype._handleCheckin = 753 function(){ 754 var item = this._getSelectedItem(); 755 if(item && item instanceof ZmBriefcaseItem){ 756 var dlg = this._getCheckinDlg(); 757 dlg.popup(item, this._doneCheckin.bind(this, item)); 758 } 759 }; 760 761 ZmBriefcaseController.prototype._doneCheckin = 762 function(item, files){ 763 //Update item attribs 764 var file = files[0]; 765 item.version = file.version; 766 item.name = file.name; 767 this.unlockItem(item, new AjxCallback(this, this.refreshItem, item)); 768 769 }; 770 771 ZmBriefcaseController.prototype._handleDiscardCheckout = 772 function(){ 773 var items = this._getSelectedItems(); 774 for(var i=0; i< items.length; i++){ 775 var item = items[i]; 776 if(item && item instanceof ZmBriefcaseItem) 777 this.unlockItem(item); 778 } 779 }; 780 781 ZmBriefcaseController.prototype.refreshItem = 782 function(item){ 783 //TODO: Handle version notifications than hard refresh 784 var view = this._parentView[this._currentViewId]; 785 view.refreshItem(item); 786 }; 787 788 ZmBriefcaseController.prototype.checkout = 789 function(item, callback){ 790 this.lockItem(item, callback); 791 }; 792 793 ZmBriefcaseController.prototype.checkin = 794 function(item, callback){ 795 this.unlockItem(item, callback); 796 }; 797 798 ZmBriefcaseController.prototype.unlockItem = 799 function(item, callback){ 800 item.unlock(callback, new AjxCallback(this, this._handleErrorResponse, item)); 801 }; 802 803 ZmBriefcaseController.prototype.lockItem = 804 function(item, callback){ 805 item.lock(callback, new AjxCallback(this, this._handleErrorResponse, item)); 806 }; 807 808 ZmBriefcaseController.prototype._handleErrorResponse = 809 function(item, response){ 810 if(!(response && response.code)) return; 811 812 var msg; 813 switch(response.code){ 814 case ZmCsfeException.CANNOT_UNLOCK: 815 msg = ZmMsg.unlockSufficientPermission; 816 break; 817 818 case ZmCsfeException.CANNOT_LOCK: 819 msg = ZmMsg.lockSuffientPermissions; 820 break; 821 } 822 823 if(msg){ 824 var dialog = appCtxt.getMsgDialog(); 825 dialog.setMessage(msg, DwtMessageDialog.WARNING_STYLE); 826 dialog.popup(); 827 } 828 829 return msg; 830 }; 831 832 ZmBriefcaseController.prototype._getSelectedItem = 833 function(){ 834 var view = this._listView[this._currentViewId]; 835 var items = view.getSelection(); 836 return ( items && items.length > 0 ) ? items[0] : null; 837 }; 838 839 ZmBriefcaseController.prototype._getSelectedItems = 840 function(){ 841 var view = this._listView[this._currentViewId]; 842 return view.getSelection(); 843 }; 844 845 ZmBriefcaseController.prototype._getCheckinDlg = 846 function(){ 847 if(!this._checkinDlg){ 848 this._checkinDlg = new ZmCheckinDialog(appCtxt.getShell()); 849 } 850 return this._checkinDlg; 851 }; 852 853 //End of Checkin/Checkout 854 855 ZmBriefcaseController.prototype._getActionMenuOps = 856 function() { 857 var list = [ 858 ZmOperation.OPEN_FILE, 859 ZmOperation.SAVE_FILE, 860 ZmOperation.EDIT_FILE 861 ]; 862 863 if (!appCtxt.isExternalAccount()) { 864 list.push(ZmOperation.SEND_FILE); 865 list.push(ZmOperation.SEND_FILE_AS_ATT); 866 } 867 868 list.push(ZmOperation.SEP); 869 list.push(ZmOperation.CHECKOUT, ZmOperation.CHECKIN, ZmOperation.DISCARD_CHECKOUT, ZmOperation.RESTORE_VERSION/*, ZmOperation.DELETE_VERSION*/); 870 871 list.push(ZmOperation.SEP); 872 list = list.concat(this._standardActionMenuOps()); 873 list.push(ZmOperation.RENAME_FILE); 874 return list; 875 }; 876 877 ZmBriefcaseController.prototype._renameFileListener = 878 function(){ 879 880 var view = this._listView[this._currentViewId]; 881 var items = view.getSelection(); 882 if (!items) { return; } 883 884 view.renameFile(items[0]); 885 }; 886 887 ZmBriefcaseController.prototype._newWinListener = 888 function(){ 889 var view = this._listView[this._currentViewId]; 890 var items = view.getSelection(); 891 if (!items) { return; } 892 items = AjxUtil.toArray(items); 893 var item = items[0]; 894 if (item) { 895 this.openFile(item); 896 } 897 }; 898 899 900 ZmBriefcaseController.prototype._editFileListener = 901 function() { 902 var view = this._listView[this._currentViewId]; 903 var items = view.getSelection(); 904 if (!items) { return; } 905 items = AjxUtil.toArray(items); 906 var item = items[0]; 907 if(item){ 908 this.editFile(item); 909 } 910 }; 911 912 ZmBriefcaseController.prototype.editFile = 913 function(items){ 914 items = AjxUtil.toArray(items); 915 for (var i = 0; i < items.length; i++) { 916 var item = items[i]; 917 if (item.isWebDoc()) { 918 var win = appCtxt.getNewWindow(false, null, null, this._getWindowName(item.name)); 919 if (win) { 920 win.command = "documentEdit"; 921 win.params = { 922 restUrl: item.getRestUrl(), 923 id: item.id, 924 name: item.name, 925 folderId: item.folderId 926 }; 927 } 928 } 929 } 930 }; 931 932 ZmBriefcaseController.prototype._getWindowName = 933 function(name){ 934 if(!name){ 935 return ZmMsg.briefcase; 936 } 937 //IE does not like special chars as part of window name. 938 return AjxEnv.isIE ? name.replace(/[^\w]/g,'') : name; 939 }; 940 941 ZmBriefcaseController.prototype._openFileListener = 942 function() { 943 var view = this._listView[this._currentViewId]; 944 var items = view.getSelection(); 945 if (!items) { return; } 946 947 this.openFile(items); 948 }; 949 950 ZmBriefcaseController.prototype.openFile = 951 function(items){ 952 items = AjxUtil.toArray(items); 953 for (var i = 0; i < items.length; i++) { 954 var item = items[i]; 955 var restUrl = item.getRestUrl(false, false, true); 956 if (!restUrl) { 957 continue; 958 } 959 restUrl = AjxStringUtil.fixCrossDomainReference(restUrl); 960 if (item.isWebDoc()) { 961 //added for bug: 45150 962 restUrl += (restUrl.match(/\?/) ? "&" : "?") + "localeId=" + AjxEnv.DEFAULT_LOCALE; 963 } else { 964 // do not try to 965 //ZD doesn't support ConvertD. 966 if (!ZmMimeTable.isRenderable(item.contentType) && !ZmMimeTable.isMultiMedia(item.contentType) && !appCtxt.isOffline) { 967 restUrl += (restUrl.match(/\?/) ? "&" : "?") + "view=html"; 968 } 969 } 970 971 var win = window.open(restUrl, this._getWindowName(item.name), item.isWebDoc() ? "" : ZmBriefcaseApp.getDocWindowFeatures()); 972 appCtxt.handlePopupBlocker(win); 973 974 // avoid losing focus in IE8 and earlier (bug 52206) 975 if (win && AjxEnv.isIE && !AjxEnv.isIE9up) { 976 var ta = new AjxTimedAction(win, win.focus); 977 AjxTimedAction.scheduleAction(ta, 100); 978 } 979 } 980 }; 981 982 ZmBriefcaseController.prototype._saveFileListener = 983 function() { 984 var view = this._listView[this._currentViewId]; 985 var items = view.getSelection(); 986 if (!items) { return; } 987 988 items = AjxUtil.toArray(items); 989 990 // Allow download to only one file. 991 this.downloadFile(items); 992 }; 993 994 ZmBriefcaseController.prototype.downloadFile = 995 function(items){ 996 997 var restUrl, item, length= items.length; 998 if(length > 1){ 999 var params = []; 1000 var organizer = appCtxt.getById(items[0].folderId); 1001 for(var i=0; i< length; i++){ 1002 item = items[i]; 1003 if (!item.isFolder) { 1004 var itemId; 1005 if (appCtxt.isOffline && organizer.isShared()) { 1006 itemId = item.id; 1007 } else { 1008 itemId = item.getNormalizedItemId(); 1009 } 1010 params.push((item.isRevision ? item.parent.id : itemId )+"."+item.version); 1011 } 1012 } 1013 restUrl = [ ((organizer.isShared() && !appCtxt.isOffline ) ? organizer.getOwnerRestUrl() : organizer.getRestUrl()), "?fmt=zip&list=", params.join(',')].join(''); 1014 }else{ 1015 item = AjxUtil.isArray(items) ? items[0] : items; 1016 restUrl = item.getRestUrl(); 1017 restUrl += ( restUrl.indexOf('?') == -1 ) ? "?" : "&"; 1018 restUrl += "disp=a"+(item.version ? "&ver="+item.version : ""); 1019 } 1020 1021 if (!restUrl) { 1022 return false; 1023 } 1024 restUrl = AjxStringUtil.fixCrossDomainReference(restUrl); 1025 if (restUrl) { 1026 this._downloadFile(restUrl) 1027 } 1028 }; 1029 1030 ZmBriefcaseController.prototype._downloadFile = 1031 function(downloadUrl){ 1032 if(downloadUrl){ 1033 ZmZimbraMail.unloadHackCallback(); 1034 location.href = downloadUrl; 1035 } 1036 }; 1037 1038 ZmBriefcaseController.prototype._viewAsHtmlListener = 1039 function() { 1040 var view = this._listView[this._currentViewId]; 1041 var items = view.getSelection(); 1042 if (!items) { return; } 1043 1044 items = AjxUtil.toArray(items); 1045 for (var i = 0; i<items.length; i++) { 1046 var item = items[i]; 1047 var restUrl = item.getRestUrl(); 1048 if (item && restUrl) { 1049 this.viewAsHtml(restUrl); 1050 } 1051 } 1052 }; 1053 1054 ZmBriefcaseController.prototype.viewAsHtml = 1055 function(restUrl) { 1056 if (restUrl.match(/\?/)) { 1057 restUrl+= "&view=html"; 1058 } else { 1059 restUrl+= "?view=html"; 1060 } 1061 window.open(restUrl); 1062 }; 1063 1064 ZmBriefcaseController.prototype._uploadFileListener = 1065 function() { 1066 this.__popupUploadDialog(ZmMsg.uploadFileToBriefcase, new AjxCallback(this, this._handlePostUpload)); 1067 }; 1068 1069 ZmBriefcaseController.prototype.resetSelection = function() { 1070 var view = this._listView[this._currentViewId]; 1071 if (view) { 1072 view.deselectAll(); 1073 } 1074 var lv = this.getCurrentView(); 1075 if (lv) { 1076 lv._selectFirstItem() 1077 } 1078 } 1079 1080 ZmBriefcaseController.prototype._sendFileListener = 1081 function(event) { 1082 var view = this._listView[this._currentViewId]; 1083 var items = view.getSelection(); 1084 items = AjxUtil.toArray(items); 1085 1086 var names = []; 1087 var urls = []; 1088 var inNewWindow = this._app._inNewWindow(event); 1089 1090 var briefcase, shares; 1091 var noprompt = false; 1092 1093 for (var i = 0; i < items.length; i++) { 1094 var item = items[i]; 1095 briefcase = appCtxt.getById(item.folderId); 1096 var url; 1097 if (briefcase.restUrl) { 1098 //present if the briefcase is a share from another user. In this case, keep that URL as the base. 1099 url = [briefcase.restUrl, "/", AjxStringUtil.urlComponentEncode(item.name)].join("") 1100 } 1101 else { 1102 //item is in this user's briefcase, so build the rest url. 1103 url = item.getRestUrl(); 1104 } 1105 if (appCtxt.isOffline) { 1106 var remoteUri = appCtxt.get(ZmSetting.OFFLINE_REMOTE_SERVER_URI); 1107 url = remoteUri + url.substring((url.indexOf("/",7))); 1108 } 1109 1110 urls.push(url); 1111 names.push(item.name); 1112 1113 if (noprompt) { continue; } 1114 1115 shares = briefcase && briefcase.shares; 1116 if (shares) { 1117 for (var j = 0; j < shares.length; j++) { 1118 noprompt = noprompt || shares[j].grantee.type == ZmShare.TYPE_PUBLIC; 1119 } 1120 } 1121 } 1122 1123 if (!shares || !noprompt) { 1124 var args = [names, urls, inNewWindow]; 1125 var callback = new AjxCallback(this, this._sendFileListener2, args); 1126 1127 var dialog = appCtxt.getConfirmationDialog(); 1128 dialog.popup(ZmMsg.errorPermissionRequired, callback); 1129 } else { 1130 this._sendFileListener2(names, urls); 1131 } 1132 }; 1133 1134 ZmBriefcaseController.prototype._sendFileListener2 = 1135 function(names, urls, inNewWindow) { 1136 var action = ZmOperation.NEW_MESSAGE; 1137 var msg = new ZmMailMsg(); 1138 var toOverride = null; 1139 var subjOverride = new AjxListFormat().format(names); 1140 var htmlCompose = appCtxt.get(ZmSetting.COMPOSE_AS_FORMAT) == ZmSetting.COMPOSE_HTML; 1141 var extraBodyText = urls.join(htmlCompose ? "<br>" : "\n"); 1142 AjxDispatcher.run("Compose", {action: action, inNewWindow: inNewWindow, msg: msg, 1143 toOverride: toOverride, subjOverride: subjOverride, 1144 extraBodyText: extraBodyText}); 1145 }; 1146 1147 ZmBriefcaseController.prototype._sendFileAsAttachmentListener = 1148 function(event) { 1149 var view = this._listView[this._currentViewId]; 1150 var items = view.getSelection(); 1151 1152 this.sendFilesAsAttachment(items); 1153 }; 1154 1155 ZmBriefcaseController.prototype.sendFilesAsAttachment = 1156 function(items, callback){ 1157 1158 items = AjxUtil.toArray(items); 1159 var docInfo = []; 1160 for (var i = 0; i < items.length; i++) { 1161 var item = items[i]; 1162 docInfo.push({ 1163 id: ( item.isRevision ? item.parent.id : item.id ), 1164 ver: ( item.isRevision ? item.version : null ), 1165 ct: item.contentType, 1166 s: item.size 1167 }); 1168 } 1169 1170 if (docInfo.length == 0) { return; } 1171 1172 var action = ZmOperation.NEW_MESSAGE; 1173 var msg = new ZmMailMsg(); 1174 var toOverride; 1175 1176 var cc = AjxDispatcher.run("GetComposeController"); 1177 cc._setView({action:action, msg:msg, toOverride:toOverride, inNewWindow:false}); 1178 var draftType = ZmComposeController.DRAFT_TYPE_AUTO; 1179 var sendDocsCallback = new AjxCallback(cc, cc._handleResponseSaveDraftListener, [draftType, callback]); 1180 cc.saveDraft(draftType, null, docInfo, sendDocsCallback); 1181 }; 1182 1183 ZmBriefcaseController.prototype._resetOpForCurrentView = 1184 function(num) { 1185 this._resetOperations(this._toolbar[this._currentViewId], num || 0); 1186 }; 1187 1188 1189 ZmBriefcaseController.prototype._setupViewMenu = 1190 function(view, firstTime) { 1191 1192 var btn, menu; 1193 if (firstTime) { 1194 btn = this._toolbar[view].getButton(ZmOperation.VIEW_MENU); 1195 var menu = btn.getMenu(); 1196 if (!menu) { 1197 menu = new ZmPopupMenu(btn); 1198 btn.setMenu(menu); 1199 1200 this._setupPreviewPaneMenu(menu, btn); 1201 } 1202 } 1203 1204 if(!menu){ 1205 btn = this._toolbar[view].getButton(ZmOperation.VIEW_MENU); 1206 menu = btn && btn.getMenu(); 1207 } 1208 1209 this._resetPreviewPaneMenu(menu, view); 1210 }; 1211 1212 ZmBriefcaseController.prototype._setupPreviewPaneMenu = 1213 function(menu, btn){ 1214 1215 if (menu.getItemCount() > 0) { 1216 new DwtMenuItem({parent:menu, style:DwtMenuItem.SEPARATOR_STYLE, id:"PREVIEW_SEPERATOR"}); 1217 } 1218 1219 var miParams = {text:ZmMsg.readingPaneAtBottom, style:DwtMenuItem.RADIO_STYLE, radioGroupId:"RP"}; 1220 var ids = ZmDoublePaneController.RP_IDS; 1221 var pref = appCtxt.get(ZmSetting.READING_PANE_LOCATION_BRIEFCASE); 1222 for (var i = 0; i < ids.length; i++) { 1223 var id = ids[i]; 1224 if (!menu._menuItems[id]) { 1225 miParams.text = ZmBriefcaseController.PREVIEW_PANE_TEXT[id]; 1226 miParams.image = ZmBriefcaseController.PREVIEW_PANE_ICON[id]; 1227 var mi = menu.createMenuItem(id, miParams); 1228 mi.setData(ZmOperation.MENUITEM_ID, id); 1229 mi.addSelectionListener(new AjxListener(this, this._previewPaneListener, id)); 1230 if (id == pref) { 1231 mi.setChecked(true, true); 1232 btn.setImage(mi.getImage()); 1233 } 1234 } 1235 } 1236 1237 }; 1238 1239 ZmBriefcaseController.prototype._resetPreviewPaneMenu = 1240 function(menu, view){ 1241 view = view || this._currentViewId; 1242 var ids = ZmDoublePaneController.RP_IDS; 1243 for (var i = 0; i < ids.length; i++) { 1244 var id = ids[i]; 1245 if (menu._menuItems[id]) { 1246 menu._menuItems[id].setEnabled(true); 1247 } 1248 } 1249 }; 1250 1251 /** 1252 * Checks if the reading pane is "on". 1253 * 1254 * @return {Boolean} <code>true</code> if the reading pane is "on" 1255 */ 1256 ZmBriefcaseController.prototype.isReadingPaneOn = 1257 function() { 1258 return (this._getReadingPanePref() != ZmSetting.RP_OFF); 1259 }; 1260 1261 /** 1262 * Checks if the reading pane is "on" right. 1263 * 1264 * @return {Boolean} <code>true</code> if the reading pane is "on" right. 1265 */ 1266 ZmBriefcaseController.prototype.isReadingPaneOnRight = 1267 function() { 1268 return (this._getReadingPanePref() == ZmSetting.RP_RIGHT); 1269 }; 1270 1271 ZmBriefcaseController.prototype._getReadingPanePref = 1272 function() { 1273 return (this._readingPaneLoc || appCtxt.get(ZmSetting.READING_PANE_LOCATION_BRIEFCASE)); 1274 }; 1275 1276 ZmBriefcaseController.prototype._setReadingPanePref = 1277 function(value) { 1278 if (this.isSearchResults || appCtxt.isExternalAccount()) { 1279 this._readingPaneLoc = value; 1280 } 1281 else { 1282 appCtxt.set(ZmSetting.READING_PANE_LOCATION_BRIEFCASE, value); 1283 } 1284 }; 1285 1286 ZmBriefcaseController.prototype._previewPaneListener = 1287 function(newPreviewStatus){ 1288 var oldPreviewStatus = appCtxt.get(ZmSetting.READING_PANE_LOCATION_BRIEFCASE); 1289 this._setReadingPanePref(newPreviewStatus); 1290 var lv = this._parentView[this._currentViewId]; 1291 lv.resetPreviewPane(newPreviewStatus, oldPreviewStatus); 1292 //update view button icon to reflect current selection 1293 var btn = this._toolbar[this._currentViewId].getButton(ZmOperation.VIEW_MENU); 1294 if (btn) { 1295 btn.setImage(ZmBriefcaseController.PREVIEW_PANE_ICON[newPreviewStatus]); 1296 } 1297 1298 }; 1299 1300 ZmBriefcaseController.CONVERTABLE = { 1301 doc:/\.doc$/i, 1302 xls:/\.xls$/i, 1303 pdf:/\.pdf$/i, 1304 ppt:/\.ppt$/i, 1305 zip:/\.zip$/i, 1306 txt:/\.txt$/i 1307 }; 1308 1309 ZmBriefcaseController.prototype.isConvertable = 1310 function(item) { 1311 var name = item.name; 1312 for (var type in ZmBriefcaseController.CONVERTABLE) { 1313 var regex = ZmBriefcaseController.CONVERTABLE[type]; 1314 if (name.match(regex)) { 1315 return true; 1316 } 1317 } 1318 return false; 1319 }; 1320 1321 ZmBriefcaseController.prototype._fileListChangeListener = 1322 function(ev) { 1323 if (ev.handled) { return; } 1324 var details = ev._details; 1325 if (!details) { return; } 1326 this._list._notify(ev.event,{items:details.items}); 1327 }; 1328 1329 ZmBriefcaseController.prototype.getCurrentView = 1330 function() { 1331 return this._parentView[this._currentViewId]; 1332 }; 1333 ZmBriefcaseController.prototype.getParentView = ZmBriefcaseController.prototype.getCurrentView; 1334 1335 ZmBriefcaseController.prototype._addListListeners = 1336 function(colView) { 1337 colView.addActionListener(new AjxListener(this, this._listActionListener)); 1338 }; 1339 1340 ZmBriefcaseController.prototype.isMultiColView = 1341 function() { 1342 return (this._currentViewType == ZmId.VIEW_BRIEFCASE_COLUMN); 1343 }; 1344 1345 ZmBriefcaseController.prototype.mapSupported = 1346 function(map) { 1347 return (map == "list" && (this._currentViewType != ZmId.VIEW_BRIEFCASE)); 1348 }; 1349 1350 ZmBriefcaseController.prototype.getItemTooltip = 1351 function(item, listView) { 1352 1353 if (item.isFolder) { return null; } 1354 1355 var prop = [{name:ZmMsg.briefcasePropName, value:item.name}]; 1356 if (item.size) { 1357 prop.push({name:ZmMsg.briefcasePropSize, value:AjxUtil.formatSize(item.size)}); 1358 } 1359 if (item.contentChangeDate) { 1360 var dateFormatter = AjxDateFormat.getDateTimeInstance(AjxDateFormat.FULL, AjxDateFormat.MEDIUM); 1361 var dateStr = dateFormatter.format(item.contentChangeDate); 1362 prop.push({name:ZmMsg.briefcasePropModified, value:dateStr}); 1363 } 1364 1365 var subs = { 1366 fileProperties: prop, 1367 tagTooltip: listView._getTagToolTip(item) 1368 }; 1369 return AjxTemplate.expand("briefcase.Briefcase#Tooltip", subs); 1370 }; 1371 1372 ZmBriefcaseController.prototype._getDateInLocaleFormat = 1373 function(date) { 1374 var dateFormatter = AjxDateFormat.getDateTimeInstance(AjxDateFormat.FULL, AjxDateFormat.MEDIUM); 1375 return dateFormatter.format(date); 1376 }; 1377 1378 ZmBriefcaseController.prototype._resetToolbarOperations = 1379 function() { 1380 if (this._listView[this._currentViewId] != null) { 1381 this._resetOperations(this._toolbar[this._currentViewId], this._listView[this._currentViewId].getSelectionCount()); 1382 } 1383 }; 1384 1385 // item count doesn't include subfolders 1386 ZmBriefcaseController.prototype._getItemCount = 1387 function() { 1388 var lv = this._listView[this._currentViewId]; 1389 var list = lv && lv._list; 1390 if (!list) { return null; } 1391 var a = list.getArray(); 1392 var num = 0; 1393 for (var i = 0, len = a.length; i < len; i++) { 1394 var item = a[i]; 1395 if (item && item.type == ZmItem.BRIEFCASE_ITEM && !item.isFolder) { 1396 num++; 1397 } 1398 } 1399 return num; 1400 }; 1401 1402 1403 ZmBriefcaseController.prototype.handleCreateNotify = 1404 function(create){ 1405 1406 if(this.isMultiColView()){ 1407 var isTrash = (this._folderId == String(ZmOrganizer.ID_TRASH)); 1408 if(!isTrash) 1409 this.getCurrentView().handleNotifyCreate(create); 1410 }else{ 1411 var list = this.getList(); 1412 if (list) { 1413 var item = ZmBriefcaseItem.createFromDom(create, {list:list}); 1414 if (list.search && list.search.matches(item)) { 1415 list.notifyCreate(create); 1416 } 1417 } 1418 } 1419 }; 1420 1421 ZmBriefcaseController.prototype.handleModifyNotify = 1422 function(modifies){ 1423 var view = this._listView[this._currentViewId]; 1424 if (view) { 1425 view.deselectAll(); 1426 } 1427 this._resetToolbarOperations(); 1428 }; 1429 1430 ZmBriefcaseController.prototype._actionErrorCallback = 1431 function(ex){ 1432 1433 var handled = false; 1434 if(ex.code == ZmCsfeException.MAIL_ALREADY_EXISTS){ 1435 handled = true; 1436 var dlg = appCtxt.getMsgDialog(); 1437 dlg.setMessage(ZmMsg.errorFileAlreadyExistsResolution, DwtMessageDialog.WARNING_STYLE); 1438 dlg.popup(); 1439 } 1440 1441 return handled; 1442 }; 1443 1444 1445 //Add to Briefcase 1446 1447 ZmBriefcaseController.prototype.createFromAttachment = 1448 function(msgId, partId, name){ 1449 1450 var dlg = this._saveAttDialog = appCtxt.getChooseFolderDialog(this._app.getName()); 1451 var chooseCb = new AjxCallback(this, this._chooserCallback, [msgId, partId, name]); 1452 ZmController.showDialog(dlg, chooseCb, this._getCopyParams(dlg, msgId, partId)); 1453 1454 }; 1455 1456 ZmBriefcaseController.prototype._getCopyParams = 1457 function(dlg, msgId, partId) { 1458 var params = { 1459 data: {msgId:msgId,partId:partId}, 1460 treeIds: [ZmOrganizer.BRIEFCASE], 1461 overviewId: dlg.getOverviewId(this._app._name), 1462 title: ZmMsg.addToBriefcaseTitle, 1463 description: ZmMsg.targetFolder, 1464 appName: ZmApp.BRIEFCASE, 1465 noRootSelect: true 1466 }; 1467 params.omit = {}; 1468 params.omit[ZmFolder.ID_DRAFTS] = true; 1469 params.omit[ZmFolder.ID_TRASH] = true; 1470 return params; 1471 }; 1472 1473 ZmBriefcaseController.prototype._chooserCallback = 1474 function(msgId, partId, name, folder) { 1475 //TODO: Avoid using search, instead try renaming on failure 1476 var callback = new AjxCallback(this, this._handleDuplicateCheck, [msgId, partId, name, folder]); 1477 this._app.search({query:folder.createQuery(), noRender:true, callback:callback, accountName:(folder && folder.account && folder.account.name) || undefined}); 1478 }; 1479 1480 ZmBriefcaseController.prototype._handleDuplicateCheck = 1481 function(msgId, partId, name, folder, results) { 1482 1483 var msg = appCtxt.getById(msgId); 1484 1485 var briefcase = folder; 1486 if (briefcase.isReadOnly(folder.id)) { 1487 ZmOrganizer._showErrorMsg(ZmMsg.errorPermission); 1488 return; 1489 } 1490 1491 if (msgId.indexOf(":") < 0) { 1492 msgId = msg.getAccount().id + ":" + msg.id; 1493 } 1494 1495 1496 var searchResult = results.getResponse(); 1497 var items = searchResult && searchResult.getResults(ZmItem.BRIEFCASE_ITEM); 1498 if (items instanceof ZmList) { 1499 items = items.getArray(); 1500 } 1501 1502 var itemFound = false; 1503 for (var i = 0, len = items.length; i < len; i++) { 1504 if (items[i].name == name) { 1505 itemFound = items[i]; 1506 break; 1507 } 1508 } 1509 1510 var folderId = (!folder.account || folder.account == appCtxt.getActiveAccount() || (folder.id.indexOf(":") != -1)) ? folder.id : [folder.account.id, folder.id].join(":"); 1511 if(itemFound){ 1512 var dlg = this._conflictDialog = this._getFileConflictDialog(); 1513 dlg.setButtonListener(DwtDialog.OK_BUTTON, this._handleConflictDialog.bind(this, msgId, partId, name, folderId, itemFound)); 1514 dlg.setEnterListener(DwtDialog.OK_BUTTON, this._handleConflictDialog.bind(this, msgId, partId, name, folderId, itemFound)); 1515 this._renameField.value = ""; 1516 dlg.popup(); 1517 }else{ 1518 this._createFromAttachment(msgId, partId, name, folderId); 1519 } 1520 1521 if(this._saveAttDialog.isPoppedUp()) 1522 this._saveAttDialog.popdown(); 1523 }; 1524 1525 ZmBriefcaseController.prototype._popupConflictDialog = 1526 function(dlg) { 1527 if (dlg) { 1528 dlg.popdown(); 1529 } 1530 if (!this._conflictDialog) { 1531 this._conflictDialog = this._getFileConflictDialog(); 1532 } 1533 this._conflictDialog.popup(); 1534 }; 1535 1536 ZmBriefcaseController.prototype._handleConflictDialog = 1537 function(msgId, partId, name, folderId, itemFound){ 1538 1539 var attribs = {}; 1540 if(this._renameRadio.checked){ 1541 var newName = this._renameField.value; 1542 var errorMsg = this.checkInvalidFileName(newName, itemFound && itemFound.name); 1543 if(errorMsg){ 1544 var dialog = appCtxt.getMsgDialog(); 1545 dialog.setMessage(errorMsg, DwtMessageDialog.WARNING_STYLE); 1546 dialog.popup(); 1547 return false; 1548 } 1549 attribs.rename = newName; 1550 }else{ 1551 attribs.id = itemFound.id; 1552 attribs.version = itemFound.version; 1553 } 1554 this._conflictDialog.popdown(); //hide dialog so user doesn't get it into a state that can be hung 1555 this._createFromAttachment(msgId, partId, name, folderId, attribs); 1556 }; 1557 1558 ZmBriefcaseController.prototype.checkInvalidFileName = 1559 function(fileName, itemFound) { 1560 1561 var message; 1562 fileName = fileName.replace(/^\s+/,"").replace(/\s+$/,""); 1563 1564 if(fileName == ""){ 1565 message = ZmMsg.emptyDocName; 1566 } 1567 else if (!ZmOrganizer.VALID_NAME_RE.test(fileName)) { 1568 message = AjxMessageFormat.format(ZmMsg.errorInvalidName, AjxStringUtil.htmlEncode(fileName)); 1569 } 1570 else if (fileName.length > ZmOrganizer.MAX_NAME_LENGTH){ 1571 message = AjxMessageFormat.format(ZmMsg.nameTooLong, ZmOrganizer.MAX_NAME_LENGTH); 1572 } 1573 else if (itemFound === fileName) { 1574 message = AjxMessageFormat.format(ZmMsg.errorFileExistsWarning, AjxStringUtil.htmlEncode(fileName)); 1575 } 1576 1577 return message; 1578 }; 1579 1580 ZmBriefcaseController.prototype._createFromAttachment = 1581 function(msgId, partId, name, folderId, attribs){ 1582 1583 attribs = attribs || {}; 1584 if(attribs.id || attribs.rename) 1585 attribs.callback = new AjxCallback(this, this._handleSuccessCreateFromAttachment, [msgId, partId, name, folderId]); 1586 if(attribs.rename) 1587 attribs.errorCallback = new AjxCallback(this, this._handleErrorCreateFromAttachment, [msgId, partId, attribs.rename, folderId]); 1588 1589 var srcData = new ZmBriefcaseItem(); 1590 srcData.createFromAttachment(msgId, partId, name, folderId, attribs); 1591 }; 1592 1593 ZmBriefcaseController.prototype._handleSuccessCreateFromAttachment = 1594 function(msgId, partId, name, folderId, response){ 1595 if(this._conflictDialog){ 1596 this._renameField.value = ""; 1597 this._conflictDialog.popdown(); 1598 } 1599 }; 1600 1601 ZmBriefcaseController.prototype._handleErrorCreateFromAttachment = 1602 function(msgId, partId, name, folderId, ex){ 1603 1604 var handled = false; 1605 if(ex.code == ZmCsfeException.MAIL_ALREADY_EXISTS){ 1606 handled = true; 1607 var dlg = appCtxt.getMsgDialog(); 1608 dlg.setMessage(AjxMessageFormat.format(ZmMsg.errorFileExistsWarning, name), DwtMessageDialog.WARNING_STYLE); 1609 dlg.setButtonListener(DwtDialog.OK_BUTTON, this._popupConflictDialog.bind(this, dlg)); 1610 dlg.popup(); 1611 } 1612 1613 return handled; 1614 }; 1615 1616 ZmBriefcaseController.prototype._getFileConflictDialog = 1617 function(){ 1618 if(!this._nameConflictDialog){ 1619 1620 var dlg = new DwtMessageDialog({parent:appCtxt.getShell(), buttons:[DwtDialog.OK_BUTTON, DwtDialog.CANCEL_BUTTON], 1621 id: "Briefcase_FileConflictDialog"}); 1622 this._nameConflictDialog = dlg; 1623 var id = this._nameConflictId = Dwt.getNextId(); 1624 dlg.setTitle(ZmMsg.addToBriefcaseTitle); 1625 dlg.setContent(AjxTemplate.expand("briefcase.Briefcase#NameConflictDialog", {id: id})); 1626 1627 this._renameRadio = document.getElementById(id+'_rename'); 1628 this._renameField = document.getElementById(id+'_newname'); 1629 1630 } 1631 return this._nameConflictDialog; 1632 }; 1633 1634 ZmBriefcaseController.prototype.getKeyMapName = 1635 function() { 1636 return ZmKeyMap.MAP_BRIEFCASE; 1637 }; 1638 1639 ZmBriefcaseController.prototype.handleKeyAction = 1640 function(actionCode) { 1641 DBG.println(AjxDebug.DBG3, "ZmBriefcaseController.handleKeyAction"); 1642 1643 switch(actionCode) { 1644 1645 case ZmKeyMap.READING_PANE_BOTTOM: 1646 case ZmKeyMap.READING_PANE_RIGHT: 1647 case ZmKeyMap.READING_PANE_OFF: 1648 var menuId = ZmBriefcaseController.ACTION_CODE_TO_MENU_ID[actionCode]; 1649 this._previewPaneListener(menuId, true); 1650 break; 1651 1652 default: 1653 return ZmListController.prototype.handleKeyAction.call(this, actionCode); 1654 } 1655 return true; 1656 }; 1657 1658 /** 1659 * Tag/untag items 1660 * 1661 * @private 1662 */ 1663 ZmBriefcaseController.prototype._doTag = 1664 function(items, tag, doTag) { 1665 items = AjxUtil.toArray(items); 1666 if (!items.length) { return; } 1667 1668 for (var i=0; i<items.length; i++) { 1669 if (items[i].isRevision) { 1670 items[i] = items[i].parent; 1671 } 1672 } 1673 return ZmListController.prototype._doTag.call(this, items, tag, doTag); 1674 }; 1675 1676 1677 /** 1678 * Moves a list of items to the given folder. Any item already in that folder is excluded. 1679 * 1680 * @param {Array} items a list of items to move 1681 * @param {ZmFolder} folder the destination folder 1682 * @param {Object} attrs the additional attrs for SOAP command 1683 * @param {Boolean} isShiftKey <code>true</code> if forcing a copy action 1684 * @param {Boolean} noUndo <code>true</code> undo not allowed 1685 * @private 1686 */ 1687 ZmBriefcaseController.prototype._doMove = 1688 function(items, folder, attrs, isShiftKey, noUndo) { 1689 items = AjxUtil.toArray(items); 1690 if (!items.length) { return; } 1691 1692 for (var i=0; i<items.length; i++) { 1693 if (items[i].isRevision) { 1694 items[i] = items[i].parent; 1695 } 1696 } 1697 return ZmListController.prototype._doMove.call(this, items, folder, attrs, isShiftKey, noUndo); 1698 }; 1699 1700 /** 1701 * Remove all tags for given items 1702 * 1703 * @private 1704 */ 1705 ZmBriefcaseController.prototype._doRemoveAllTags = 1706 function(items) { 1707 1708 items = AjxUtil.toArray(items); 1709 if (!items.length) { return; } 1710 1711 for (var i=0; i<items.length; i++) { 1712 if (items[i].isRevision) { 1713 items[i] = items[i].parent; 1714 } 1715 } 1716 return ZmListController.prototype._doRemoveAllTags.call(this, items); 1717 }; 1718 1719 /* 1720 ** Using iframe provides a barrier to block any object below it 1721 */ 1722 ZmBriefcaseController._onDeleteDialogPopup = function(dialog) { 1723 var veilOverlay = appCtxt.getShell()._veilOverlay; 1724 if (!veilOverlay) { 1725 return; 1726 } 1727 var iframe = document.createElement("IFRAME"); 1728 iframe.style.cssText = veilOverlay.style.cssText; 1729 iframe.style.zIndex = veilOverlay.style.zIndex - 1; 1730 document.body.appendChild(iframe); 1731 var onDeleteDialogPopdown = function(dialog) { 1732 iframe.parentNode.removeChild(iframe); 1733 dialog.removePopupListener(ZmBriefcaseController._onDeleteDialogPopup); 1734 dialog.removePopdownListener(onDeleteDialogPopdown); 1735 }; 1736 dialog.addPopdownListener(onDeleteDialogPopdown); 1737 }; 1738