1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2005, 2006, 2007, 2009, 2010, 2013, 2014, 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) 2005, 2006, 2007, 2009, 2010, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 /** 25 * @constructor 26 * @class 27 * A drop target is registered with a control to indicate that the control is 28 * a drop target. The drop target is the mechanism by which the DnD framework provides 29 * the binding between the UI components and the application. 30 * <p> 31 * Application developers instantiate {@link DwtDropTarget} and register it with the control 32 * which is to be a drop target (via {@link DwtControl.setDropTarget}). The 33 * application should then register a listener with the {@link DwtDropTarget}. This way 34 * when drop events occur the application will be notified and may act on them 35 * accordingly 36 * </p> 37 * 38 * @author Ross Dargahi 39 * 40 * @param {array} transferType a list of supported object types that may be dropped onto 41 * this drop target. Typically the items represent classes (i.e. functions) whose 42 * instances may be dropped on this drop target e.g. 43 * <code>new DwtDropTarget(MailItem, AppointmentItme)</code> 44 * 45 * @see DwtDropEvent 46 * @see DwtControl 47 * @see DwtControl#setDropTarget 48 */ 49 DwtDropTarget = function(types) { 50 /** @private */ 51 this._evtMgr = new AjxEventMgr(); 52 53 /** @private */ 54 this.__hasMultiple = false; 55 56 this._types = {}; 57 if (typeof types == "string") { 58 types = [types]; 59 } 60 if (types && types.length) { 61 for (var i = 0; i < types.length; i++) { 62 this.addTransferType(types[i]); 63 } 64 } 65 } 66 67 /** @private */ 68 DwtDropTarget.__DROP_LISTENER = "DwtDropTarget.__DROP_LISTENER"; 69 70 /** @private */ 71 DwtDropTarget.__dropEvent = new DwtDropEvent(); 72 73 /** 74 * Returns a string representation of this object. 75 * 76 * @return {string} a string representation of this object 77 */ 78 DwtDropTarget.prototype.toString = 79 function() { 80 return "DwtDropTarget"; 81 } 82 83 /** 84 * Registers a listener for {@link DwtDragEvent} events. 85 * 86 * @param {AjxListener} dropTargetListener Listener to be registered 87 * 88 * @see DwtDropEvent 89 * @see AjxListener 90 * @see #removeDropListener 91 */ 92 DwtDropTarget.prototype.addDropListener = 93 function(dropTargetListener) { 94 this._evtMgr.addListener(DwtDropTarget.__DROP_LISTENER, dropTargetListener); 95 } 96 97 /** 98 * Removes a registered event listener. 99 * 100 * @param {AjxListener} dropTargetListener Listener to be removed 101 * 102 * @see AjxListener 103 * @see #addDropListener 104 */ 105 DwtDropTarget.prototype.removeDropListener = 106 function(dropTargetListener) { 107 this._evtMgr.removeListener(DwtDropTarget.__DROP_LISTENER, dropTargetListener); 108 } 109 110 /** 111 * Check to see if the types in <code>items</code> can be dropped on this drop target 112 * 113 * @param {object|array} items an array of objects or single object whose types are 114 * to be checked against the set of transfer types supported by this drop target 115 * 116 * @return true if all of the objects in <code>items</code> may legally be dropped on 117 * this drop target 118 * @type boolean 119 */ 120 DwtDropTarget.prototype.isValidTarget = 121 function(items) { 122 if (items instanceof Array) { 123 var len = items.length; 124 for (var i = 0; i < len; i++) { 125 if (!this.__checkTarget(items[i])) { 126 return false; 127 } 128 } 129 return true; 130 } else { 131 return this.__checkTarget(items); 132 } 133 } 134 135 /** 136 * Calling this method indicates that the UI component backing this drop target has multiple 137 * sub-components 138 */ 139 DwtDropTarget.prototype.markAsMultiple = 140 function() { 141 this.__hasMultiple = true; 142 }; 143 144 /** 145 * Checks if the UI component backing this drop target has multiple sub-components. 146 * 147 * @return {boolean} <code>true</code> if the UI component has multiple sub-components 148 */ 149 DwtDropTarget.prototype.hasMultipleTargets = 150 function () { 151 return this.__hasMultiple; 152 }; 153 154 /** 155 * Gets the transfer types. 156 * 157 * @return {array} the list of transfer types supported by this drop target 158 * 159 * @see #setTransferTypes 160 */ 161 DwtDropTarget.prototype.getTransferTypes = 162 function() { 163 return this._types; 164 } 165 166 /** 167 * Declares a type of object as valid for being dropped onto this target. The type is provided 168 * as a string, since the corresponding class may not yet be defined. The type is eval'ed before 169 * it is used for any validation, since the check is done with <code>instanceof</code>. 170 * 171 * @param {string} type the name of class 172 */ 173 DwtDropTarget.prototype.addTransferType = 174 function(type) { 175 this._types[type] = null; 176 }; 177 178 // The following methods are called by DwtControl during the Drag lifecycle 179 180 /** @private */ 181 DwtDropTarget.prototype._dragEnter = 182 function(operation, targetControl, srcData, ev, dndProxy) { 183 DwtDropTarget.__dropEvent.operation = operation; 184 DwtDropTarget.__dropEvent.targetControl = targetControl; 185 DwtDropTarget.__dropEvent.action = DwtDropEvent.DRAG_ENTER; 186 DwtDropTarget.__dropEvent.srcData = srcData; 187 DwtDropTarget.__dropEvent.uiEvent = ev; 188 DwtDropTarget.__dropEvent.doIt = true; 189 DwtDropTarget.__dropEvent.dndProxy = dndProxy; 190 this._evtMgr.notifyListeners(DwtDropTarget.__DROP_LISTENER, DwtDropTarget.__dropEvent); 191 return DwtDropTarget.__dropEvent.doIt; 192 } 193 194 /** @private */ 195 DwtDropTarget.prototype._dragLeave = 196 function() { 197 DwtDropTarget.__dropEvent.action = DwtDropEvent.DRAG_LEAVE; 198 this._evtMgr.notifyListeners(DwtDropTarget.__DROP_LISTENER, DwtDropTarget.__dropEvent); 199 } 200 201 /** @private */ 202 DwtDropTarget.prototype._dragOpChanged = 203 function(newOperation) { 204 DwtDropTarget.__dropEvent.operation = newOperation; 205 DwtDropTarget.__dropEvent.action = DwtDropEvent.DRAG_OP_CHANGED; 206 this._evtMgr.notifyListeners(DwtDropTarget.__DROP_LISTENER, DwtDropTarget.__dropEvent); 207 return DwtDropTarget.__dropEvent.doIt; 208 }; 209 210 /** @private */ 211 DwtDropTarget.prototype._drop = 212 function(srcData, ev) { 213 DwtDropTarget.__dropEvent.action = DwtDropEvent.DRAG_DROP; 214 DwtDropTarget.__dropEvent.srcData = srcData; 215 DwtDropTarget.__dropEvent.uiEvent = ev; 216 this._evtMgr.notifyListeners(DwtDropTarget.__DROP_LISTENER, DwtDropTarget.__dropEvent); 217 return DwtDropTarget.__dropEvent.doIt; 218 }; 219 220 221 // Private methods 222 223 /**@private*/ 224 DwtDropTarget.prototype.__checkTarget = 225 function(item) { 226 if (this._types) { 227 for (var i in this._types) { 228 var ctor; 229 if (this._types[i]) { 230 ctor = this._types[i]; 231 } else { 232 ctor = this._types[i] = eval(i); 233 } 234 if (ctor && (typeof ctor == "function") && (item instanceof ctor)) { 235 return true; 236 } 237 } 238 return false; 239 } 240 }; 241