1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 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) 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * Drag and Drop Event handler
 26  *
 27  * @author Hem Aravind
 28  *
 29  * @private
 30  */
 31 
 32 ZmDragAndDrop = function(parent) {
 33     this._view = parent;
 34     this._controller = parent._controller;
 35     this._element = parent.getHtmlElement();
 36     this._initialize();
 37 };
 38 
 39 ZmDragAndDrop.prototype.constructor = ZmDragAndDrop;
 40 
 41 /**
 42 * @return	{boolean}	true if drag and drop is supported
 43 */
 44 ZmDragAndDrop.isSupported = function() {
 45 
 46     //Refer https://github.com/Modernizr/Modernizr/issues/57#issuecomment-4187079 Drag and Drop support
 47     var div = document.createElement('div'),
 48         dragSupport = (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)),
 49         isSupported = dragSupport && !!window.FileReader;
 50 
 51     if (AjxEnv.isSafari4up && dragSupport) {
 52         isSupported = true;
 53     }
 54 
 55     ZmDragAndDrop.isSupported = function() {
 56         return isSupported;
 57     };
 58 
 59     if (isSupported) {
 60         ZmDragAndDrop.MESSAGE_SIZE_LIMIT = appCtxt.get(ZmSetting.MESSAGE_SIZE_LIMIT);
 61         ZmDragAndDrop.ATTACHMENT_URL = appCtxt.get(ZmSetting.CSFE_ATTACHMENT_UPLOAD_URI)+"?fmt=extended,raw";
 62     }
 63 
 64     return ZmDragAndDrop.isSupported();
 65 };
 66 
 67 /**
 68  * @return	{boolean} 	true if attachment size exceeded and shows the warning dialog
 69  */
 70 ZmDragAndDrop.isAttachmentSizeExceeded = function(files, showDialog) {
 71     var j,
 72         filesLength,
 73 		size,
 74         file;
 75 
 76     if (!files) {
 77         return false;
 78     }
 79 
 80     for (j = 0 , size = 0, filesLength = files.length; j < filesLength; j++) {
 81         file = files[j];
 82         if (file) {
 83 			//Check the total size of the files we upload this time (we don't know the previously uploaded files total size so we do the best we can).
 84 			//NOTE - we compare to the MTA message size limit since there's no limit on specific attachments.
 85             size += file.size || file.fileSize /*Safari*/ || 0;
 86             //Showing Error dialog if the attachment size is exceeded
 87             if ((-1 /* means unlimited */ != ZmDragAndDrop.MESSAGE_SIZE_LIMIT) &&
 88                 (size > ZmDragAndDrop.MESSAGE_SIZE_LIMIT)) {
 89                 if (showDialog) {
 90                     var msgDlg = appCtxt.getMsgDialog();
 91                     var errorMsg = AjxMessageFormat.format(ZmMsg.attachmentSizeError, AjxUtil.formatSize(ZmDragAndDrop.MESSAGE_SIZE_LIMIT));
 92                     msgDlg.setMessage(errorMsg, DwtMessageDialog.WARNING_STYLE);
 93                     msgDlg.popup();
 94                 }
 95                 return true;
 96             }
 97         }
 98     }
 99     return false;
100 };
101 
102 ZmDragAndDrop.prototype._initialize = function () {
103 	if (!ZmDragAndDrop.isSupported() && this._element && this._element.id) {
104 		var tooltip = document.getElementById(this._element.id + ZmId.CMP_DND_TOOLTIP);
105 		if (tooltip) {
106 			tooltip.style.display = "none";
107 			tooltip.innerHTML = "";
108 		}
109 	}
110     if (!this._view || !this._controller || !this._element || !ZmDragAndDrop.isSupported()) {
111         return;
112     }
113     this._addHandlers(this._element);
114     this._dndTooltipEl = document.getElementById(this._element.id + ZmId.CMP_DND_TOOLTIP);
115     this._setToolTip();
116 };
117 
118 ZmDragAndDrop.prototype._addHandlers = function(el) {
119     Dwt.setHandler(el,"ondragover",this._onDragOver.bind(this));
120     Dwt.setHandler(el,"ondrop", this._onDrop.bind(this));
121 };
122 
123 ZmDragAndDrop.prototype._setToolTip = function(){
124     if (!this._dndTooltipEl) {
125         return;
126     }
127     if (this._view._attachCount > 0 || this._dndFilesLength > 0){
128         this._dndTooltipEl.style.display = "none";
129         this._dndTooltipEl.innerHTML = "";
130     } else {
131         this._dndTooltipEl.innerHTML = ZmMsg.dndTooltip;
132         this._dndTooltipEl.style.display = "block";
133     }
134 };
135 
136 ZmDragAndDrop.prototype._onDragOver = function(ev) {
137     ZmDragAndDrop._stopEvent(ev);
138 };
139 
140 ZmDragAndDrop.prototype._onDrop = function(ev, isEditorDND) {
141     var dt,
142         files,
143         file,
144         j,
145         filesLength;
146 
147     if (!ev || (this._view && this._view._disableAttachments === true) ) {
148         return;
149     }
150 
151     dt = ev.dataTransfer;
152     if (!dt) {
153         return;
154     }
155 
156     files = dt.files;
157     if (!files || !files.length) {
158         return;
159     }
160 
161     ZmDragAndDrop._stopEvent(ev);
162 
163 	//just re-use code from the my computer option as it should be exactly the same case from now on.
164 	this._view._submitMyComputerAttachments(files, null, isEditorDND, ev);
165 };
166 
167 ZmDragAndDrop._stopEvent = function(ev) {
168 	if (!ZmDragAndDrop.containFiles(ev)) {
169 		return;
170 	}
171 	if (ev.preventDefault) {
172 		ev.preventDefault();
173 	}
174 	if (ev.stopPropagation) {
175 		ev.stopPropagation();
176 	}
177 };
178 
179 ZmDragAndDrop.containFiles =
180 function(ev, type) {
181 	var typesArray = ev && ev.dataTransfer && ev.dataTransfer.types;
182     if (!typesArray) {
183 		return false;
184 	}
185 	type = type || "Files";
186 	for (var i = 0; i < typesArray.length; i++) {
187 		if (typesArray[i] === type) {
188 			return true;
189 		}
190 	}
191 	return false;
192 };