1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
|
// Copyright 2010 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Provides a files drag and drop event detector. It works on
* HTML5 browsers.
*
* @see ../demos/filedrophandler.html
*/
goog.provide('goog.events.FileDropHandler');
goog.provide('goog.events.FileDropHandler.EventType');
goog.require('goog.array');
goog.require('goog.dom');
goog.require('goog.events.BrowserEvent');
goog.require('goog.events.EventHandler');
goog.require('goog.events.EventTarget');
goog.require('goog.events.EventType');
goog.require('goog.log');
goog.require('goog.log.Level');
/**
* A files drag and drop event detector. Gets an {@code element} as parameter
* and fires {@code goog.events.FileDropHandler.EventType.DROP} event when files
* are dropped in the {@code element}.
*
* @param {Element|Document} element The element or document to listen on.
* @param {boolean=} opt_preventDropOutside Whether to prevent a drop on the
* area outside the {@code element}. Default false.
* @constructor
* @extends {goog.events.EventTarget}
* @final
*/
goog.events.FileDropHandler = function(element, opt_preventDropOutside) {
goog.events.EventTarget.call(this);
/**
* Handler for drag/drop events.
* @type {!goog.events.EventHandler<!goog.events.FileDropHandler>}
* @private
*/
this.eventHandler_ = new goog.events.EventHandler(this);
var doc = element;
if (opt_preventDropOutside) {
doc = goog.dom.getOwnerDocument(element);
}
// Add dragenter listener to the owner document of the element.
this.eventHandler_.listen(
doc, goog.events.EventType.DRAGENTER, this.onDocDragEnter_);
// Add dragover listener to the owner document of the element only if the
// document is not the element itself.
if (doc != element) {
this.eventHandler_.listen(
doc, goog.events.EventType.DRAGOVER, this.onDocDragOver_);
}
// Add dragover and drop listeners to the element.
this.eventHandler_.listen(
element, goog.events.EventType.DRAGOVER, this.onElemDragOver_);
this.eventHandler_.listen(
element, goog.events.EventType.DROP, this.onElemDrop_);
};
goog.inherits(goog.events.FileDropHandler, goog.events.EventTarget);
/**
* Whether the drag event contains files. It is initialized only in the
* dragenter event. It is used in all the drag events to prevent default actions
* only if the drag contains files. Preventing default actions is necessary to
* go from dragenter to dragover and from dragover to drop. However we do not
* always want to prevent default actions, e.g. when the user drags text or
* links on a text area we should not prevent the browser default action that
* inserts the text in the text area. It is also necessary to stop propagation
* when handling drag events on the element to prevent them from propagating
* to the document.
* @private
* @type {boolean}
*/
goog.events.FileDropHandler.prototype.dndContainsFiles_ = false;
/**
* A logger, used to help us debug the algorithm.
* @type {goog.log.Logger}
* @private
*/
goog.events.FileDropHandler.prototype.logger_ =
goog.log.getLogger('goog.events.FileDropHandler');
/**
* The types of events fired by this class.
* @enum {string}
*/
goog.events.FileDropHandler.EventType = {
DROP: goog.events.EventType.DROP
};
/** @override */
goog.events.FileDropHandler.prototype.disposeInternal = function() {
goog.events.FileDropHandler.superClass_.disposeInternal.call(this);
this.eventHandler_.dispose();
};
/**
* Dispatches the DROP event.
* @param {goog.events.BrowserEvent} e The underlying browser event.
* @private
*/
goog.events.FileDropHandler.prototype.dispatch_ = function(e) {
goog.log.fine(this.logger_, 'Firing DROP event...');
var event = new goog.events.BrowserEvent(e.getBrowserEvent());
event.type = goog.events.FileDropHandler.EventType.DROP;
this.dispatchEvent(event);
};
/**
* Handles dragenter on the document.
* @param {goog.events.BrowserEvent} e The dragenter event.
* @private
*/
goog.events.FileDropHandler.prototype.onDocDragEnter_ = function(e) {
goog.log.log(
this.logger_, goog.log.Level.FINER,
'"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type);
var dt = e.getBrowserEvent().dataTransfer;
// Check whether the drag event contains files.
this.dndContainsFiles_ = !!(
dt && ((dt.types && (goog.array.contains(dt.types, 'Files') ||
goog.array.contains(dt.types, 'public.file-url'))) ||
(dt.files && dt.files.length > 0)));
// If it does
if (this.dndContainsFiles_) {
// Prevent default actions.
e.preventDefault();
}
goog.log.log(
this.logger_, goog.log.Level.FINER,
'dndContainsFiles_: ' + this.dndContainsFiles_);
};
/**
* Handles dragging something over the document.
* @param {goog.events.BrowserEvent} e The dragover event.
* @private
*/
goog.events.FileDropHandler.prototype.onDocDragOver_ = function(e) {
goog.log.log(
this.logger_, goog.log.Level.FINEST,
'"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type);
if (this.dndContainsFiles_) {
// Prevent default actions.
e.preventDefault();
// Disable the drop on the document outside the drop zone.
var dt = e.getBrowserEvent().dataTransfer;
dt.dropEffect = 'none';
}
};
/**
* Handles dragging something over the element (drop zone).
* @param {goog.events.BrowserEvent} e The dragover event.
* @private
*/
goog.events.FileDropHandler.prototype.onElemDragOver_ = function(e) {
goog.log.log(
this.logger_, goog.log.Level.FINEST,
'"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type);
if (this.dndContainsFiles_) {
// Prevent default actions and stop the event from propagating further to
// the document. Both lines are needed! (See comment above).
e.preventDefault();
e.stopPropagation();
// Allow the drop on the drop zone.
var dt = e.getBrowserEvent().dataTransfer;
// IE bug #811625 (https://goo.gl/UWuxX0) will throw error SCRIPT65535
// when attempting to set property effectAllowed on IE10+.
// See more: https://github.com/google/closure-library/issues/485.
try {
dt.effectAllowed = 'all';
} catch (err) {
}
dt.dropEffect = 'copy';
}
};
/**
* Handles dropping something onto the element (drop zone).
* @param {goog.events.BrowserEvent} e The drop event.
* @private
*/
goog.events.FileDropHandler.prototype.onElemDrop_ = function(e) {
goog.log.log(
this.logger_, goog.log.Level.FINER,
'"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type);
// If the drag and drop event contains files.
if (this.dndContainsFiles_) {
// Prevent default actions and stop the event from propagating further to
// the document. Both lines are needed! (See comment above).
e.preventDefault();
e.stopPropagation();
// Dispatch DROP event.
this.dispatch_(e);
}
};
|