toolkit/content/nsDragAndDrop.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 // -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 ////////////////////////////////////////////////////////////////////////
michael@0 8 //
michael@0 9 // USE OF THIS API FOR DRAG AND DROP IS DEPRECATED!
michael@0 10 // Do not use this file for new code.
michael@0 11 //
michael@0 12 // For documentation about what to use instead, see:
michael@0 13 // http://developer.mozilla.org/En/DragDrop/Drag_and_Drop
michael@0 14 //
michael@0 15 ////////////////////////////////////////////////////////////////////////
michael@0 16
michael@0 17
michael@0 18 /**
michael@0 19 * nsTransferable - a wrapper for nsITransferable that simplifies
michael@0 20 * javascript clipboard and drag&drop. for use in
michael@0 21 * these situations you should use the nsClipboard
michael@0 22 * and nsDragAndDrop wrappers for more convenience
michael@0 23 **/
michael@0 24
michael@0 25 var nsTransferable = {
michael@0 26 /**
michael@0 27 * nsITransferable set (TransferData aTransferData) ;
michael@0 28 *
michael@0 29 * Creates a transferable with data for a list of supported types ("flavours")
michael@0 30 *
michael@0 31 * @param TransferData aTransferData
michael@0 32 * a javascript object in the format described above
michael@0 33 **/
michael@0 34 set: function (aTransferDataSet)
michael@0 35 {
michael@0 36 var trans = this.createTransferable();
michael@0 37 for (var i = 0; i < aTransferDataSet.dataList.length; ++i)
michael@0 38 {
michael@0 39 var currData = aTransferDataSet.dataList[i];
michael@0 40 var currFlavour = currData.flavour.contentType;
michael@0 41 trans.addDataFlavor(currFlavour);
michael@0 42 var supports = null; // nsISupports data
michael@0 43 var length = 0;
michael@0 44 if (currData.flavour.dataIIDKey == "nsISupportsString")
michael@0 45 {
michael@0 46 supports = Components.classes["@mozilla.org/supports-string;1"]
michael@0 47 .createInstance(Components.interfaces.nsISupportsString);
michael@0 48
michael@0 49 supports.data = currData.supports;
michael@0 50 length = supports.data.length;
michael@0 51 }
michael@0 52 else
michael@0 53 {
michael@0 54 // non-string data.
michael@0 55 supports = currData.supports;
michael@0 56 length = 0; // kFlavorHasDataProvider
michael@0 57 }
michael@0 58 trans.setTransferData(currFlavour, supports, length * 2);
michael@0 59 }
michael@0 60 return trans;
michael@0 61 },
michael@0 62
michael@0 63 /**
michael@0 64 * TransferData/TransferDataSet get (FlavourSet aFlavourSet,
michael@0 65 * Function aRetrievalFunc, Boolean aAnyFlag) ;
michael@0 66 *
michael@0 67 * Retrieves data from the transferable provided in aRetrievalFunc, formatted
michael@0 68 * for more convenient access.
michael@0 69 *
michael@0 70 * @param FlavourSet aFlavourSet
michael@0 71 * a FlavourSet object that contains a list of supported flavours.
michael@0 72 * @param Function aRetrievalFunc
michael@0 73 * a reference to a function that returns a nsISupportsArray of nsITransferables
michael@0 74 * for each item from the specified source (clipboard/drag&drop etc)
michael@0 75 * @param Boolean aAnyFlag
michael@0 76 * a flag specifying whether or not a specific flavour is requested. If false,
michael@0 77 * data of the type of the first flavour in the flavourlist parameter is returned,
michael@0 78 * otherwise the best flavour supported will be returned.
michael@0 79 **/
michael@0 80 get: function (aFlavourSet, aRetrievalFunc, aAnyFlag)
michael@0 81 {
michael@0 82 if (!aRetrievalFunc)
michael@0 83 throw "No data retrieval handler provided!";
michael@0 84
michael@0 85 var supportsArray = aRetrievalFunc(aFlavourSet);
michael@0 86 var dataArray = [];
michael@0 87 var count = supportsArray.Count();
michael@0 88
michael@0 89 // Iterate over the number of items returned from aRetrievalFunc. For
michael@0 90 // clipboard operations, this is 1, for drag and drop (where multiple
michael@0 91 // items may have been dragged) this could be >1.
michael@0 92 for (var i = 0; i < count; i++)
michael@0 93 {
michael@0 94 var trans = supportsArray.GetElementAt(i);
michael@0 95 if (!trans) continue;
michael@0 96 trans = trans.QueryInterface(Components.interfaces.nsITransferable);
michael@0 97
michael@0 98 var data = { };
michael@0 99 var length = { };
michael@0 100
michael@0 101 var currData = null;
michael@0 102 if (aAnyFlag)
michael@0 103 {
michael@0 104 var flavour = { };
michael@0 105 trans.getAnyTransferData(flavour, data, length);
michael@0 106 if (data && flavour)
michael@0 107 {
michael@0 108 var selectedFlavour = aFlavourSet.flavourTable[flavour.value];
michael@0 109 if (selectedFlavour)
michael@0 110 dataArray[i] = FlavourToXfer(data.value, length.value, selectedFlavour);
michael@0 111 }
michael@0 112 }
michael@0 113 else
michael@0 114 {
michael@0 115 var firstFlavour = aFlavourSet.flavours[0];
michael@0 116 trans.getTransferData(firstFlavour, data, length);
michael@0 117 if (data && firstFlavour)
michael@0 118 dataArray[i] = FlavourToXfer(data.value, length.value, firstFlavour);
michael@0 119 }
michael@0 120 }
michael@0 121 return new TransferDataSet(dataArray);
michael@0 122 },
michael@0 123
michael@0 124 /**
michael@0 125 * nsITransferable createTransferable (void) ;
michael@0 126 *
michael@0 127 * Creates and returns a transferable object.
michael@0 128 **/
michael@0 129 createTransferable: function ()
michael@0 130 {
michael@0 131 const kXferableContractID = "@mozilla.org/widget/transferable;1";
michael@0 132 const kXferableIID = Components.interfaces.nsITransferable;
michael@0 133 var trans = Components.classes[kXferableContractID].createInstance(kXferableIID);
michael@0 134 trans.init(null);
michael@0 135 return trans;
michael@0 136 }
michael@0 137 };
michael@0 138
michael@0 139 /**
michael@0 140 * A FlavourSet is a simple type that represents a collection of Flavour objects.
michael@0 141 * FlavourSet is constructed from an array of Flavours, and stores this list as
michael@0 142 * an array and a hashtable. The rationale for the dual storage is as follows:
michael@0 143 *
michael@0 144 * Array: Ordering is important when adding data flavours to a transferable.
michael@0 145 * Flavours added first are deemed to be 'preferred' by the client.
michael@0 146 * Hash: Convenient lookup of flavour data using the content type (MIME type)
michael@0 147 * of data as a key.
michael@0 148 */
michael@0 149 function FlavourSet(aFlavourList)
michael@0 150 {
michael@0 151 this.flavours = aFlavourList || [];
michael@0 152 this.flavourTable = { };
michael@0 153
michael@0 154 this._XferID = "FlavourSet";
michael@0 155
michael@0 156 for (var i = 0; i < this.flavours.length; ++i)
michael@0 157 this.flavourTable[this.flavours[i].contentType] = this.flavours[i];
michael@0 158 }
michael@0 159
michael@0 160 FlavourSet.prototype = {
michael@0 161 appendFlavour: function (aFlavour, aFlavourIIDKey)
michael@0 162 {
michael@0 163 var flavour = new Flavour (aFlavour, aFlavourIIDKey);
michael@0 164 this.flavours.push(flavour);
michael@0 165 this.flavourTable[flavour.contentType] = flavour;
michael@0 166 }
michael@0 167 };
michael@0 168
michael@0 169 /**
michael@0 170 * A Flavour is a simple type that represents a data type that can be handled.
michael@0 171 * It takes a content type (MIME type) which is used when storing data on the
michael@0 172 * system clipboard/drag and drop, and an IIDKey (string interface name
michael@0 173 * which is used to QI data to an appropriate form. The default interface is
michael@0 174 * assumed to be wide-string.
michael@0 175 */
michael@0 176 function Flavour(aContentType, aDataIIDKey)
michael@0 177 {
michael@0 178 this.contentType = aContentType;
michael@0 179 this.dataIIDKey = aDataIIDKey || "nsISupportsString";
michael@0 180
michael@0 181 this._XferID = "Flavour";
michael@0 182 }
michael@0 183
michael@0 184 function TransferDataBase() {}
michael@0 185 TransferDataBase.prototype = {
michael@0 186 push: function (aItems)
michael@0 187 {
michael@0 188 this.dataList.push(aItems);
michael@0 189 },
michael@0 190
michael@0 191 get first ()
michael@0 192 {
michael@0 193 return "dataList" in this && this.dataList.length ? this.dataList[0] : null;
michael@0 194 }
michael@0 195 };
michael@0 196
michael@0 197 /**
michael@0 198 * TransferDataSet is a list (array) of TransferData objects, which represents
michael@0 199 * data dragged from one or more elements.
michael@0 200 */
michael@0 201 function TransferDataSet(aTransferDataList)
michael@0 202 {
michael@0 203 this.dataList = aTransferDataList || [];
michael@0 204
michael@0 205 this._XferID = "TransferDataSet";
michael@0 206 }
michael@0 207 TransferDataSet.prototype = TransferDataBase.prototype;
michael@0 208
michael@0 209 /**
michael@0 210 * TransferData is a list (array) of FlavourData for all the applicable content
michael@0 211 * types associated with a drag from a single item.
michael@0 212 */
michael@0 213 function TransferData(aFlavourDataList)
michael@0 214 {
michael@0 215 this.dataList = aFlavourDataList || [];
michael@0 216
michael@0 217 this._XferID = "TransferData";
michael@0 218 }
michael@0 219 TransferData.prototype = {
michael@0 220 __proto__: TransferDataBase.prototype,
michael@0 221
michael@0 222 addDataForFlavour: function (aFlavourString, aData, aLength, aDataIIDKey)
michael@0 223 {
michael@0 224 this.dataList.push(new FlavourData(aData, aLength,
michael@0 225 new Flavour(aFlavourString, aDataIIDKey)));
michael@0 226 }
michael@0 227 };
michael@0 228
michael@0 229 /**
michael@0 230 * FlavourData is a type that represents data retrieved from the system
michael@0 231 * clipboard or drag and drop. It is constructed internally by the Transferable
michael@0 232 * using the raw (nsISupports) data from the clipboard, the length of the data,
michael@0 233 * and an object of type Flavour representing the type. Clients implementing
michael@0 234 * IDragDropObserver receive an object of this type in their implementation of
michael@0 235 * onDrop. They access the 'data' property to retrieve data, which is either data
michael@0 236 * QI'ed to a usable form, or unicode string.
michael@0 237 */
michael@0 238 function FlavourData(aData, aLength, aFlavour)
michael@0 239 {
michael@0 240 this.supports = aData;
michael@0 241 this.contentLength = aLength;
michael@0 242 this.flavour = aFlavour || null;
michael@0 243
michael@0 244 this._XferID = "FlavourData";
michael@0 245 }
michael@0 246
michael@0 247 FlavourData.prototype = {
michael@0 248 get data ()
michael@0 249 {
michael@0 250 if (this.flavour &&
michael@0 251 this.flavour.dataIIDKey != "nsISupportsString")
michael@0 252 return this.supports.QueryInterface(Components.interfaces[this.flavour.dataIIDKey]);
michael@0 253
michael@0 254 var supports = this.supports;
michael@0 255 if (supports instanceof Components.interfaces.nsISupportsString)
michael@0 256 return supports.data.substring(0, this.contentLength/2);
michael@0 257
michael@0 258 return supports;
michael@0 259 }
michael@0 260 }
michael@0 261
michael@0 262 /**
michael@0 263 * Create a TransferData object with a single FlavourData entry. Used when
michael@0 264 * unwrapping data of a specific flavour from the drag service.
michael@0 265 */
michael@0 266 function FlavourToXfer(aData, aLength, aFlavour)
michael@0 267 {
michael@0 268 return new TransferData([new FlavourData(aData, aLength, aFlavour)]);
michael@0 269 }
michael@0 270
michael@0 271 var transferUtils = {
michael@0 272
michael@0 273 retrieveURLFromData: function (aData, flavour)
michael@0 274 {
michael@0 275 switch (flavour) {
michael@0 276 case "text/unicode":
michael@0 277 case "text/plain":
michael@0 278 case "text/x-moz-text-internal":
michael@0 279 return aData.replace(/^\s+|\s+$/g, "");
michael@0 280 case "text/x-moz-url":
michael@0 281 return ((aData instanceof Components.interfaces.nsISupportsString) ? aData.toString() : aData).split("\n")[0];
michael@0 282 case "application/x-moz-file":
michael@0 283 var ioService = Components.classes["@mozilla.org/network/io-service;1"]
michael@0 284 .getService(Components.interfaces.nsIIOService);
michael@0 285 var fileHandler = ioService.getProtocolHandler("file")
michael@0 286 .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
michael@0 287 return fileHandler.getURLSpecFromFile(aData);
michael@0 288 }
michael@0 289 return null;
michael@0 290 }
michael@0 291
michael@0 292 }
michael@0 293
michael@0 294 /**
michael@0 295 * nsDragAndDrop - a convenience wrapper for nsTransferable, nsITransferable
michael@0 296 * and nsIDragService/nsIDragSession.
michael@0 297 *
michael@0 298 * Use: map the handler functions to the 'ondraggesture', 'ondragover' and
michael@0 299 * 'ondragdrop' event handlers on your XML element, e.g.
michael@0 300 * <xmlelement ondraggesture="nsDragAndDrop.startDrag(event, observer);"
michael@0 301 * ondragover="nsDragAndDrop.dragOver(event, observer);"
michael@0 302 * ondragdrop="nsDragAndDrop.drop(event, observer);"/>
michael@0 303 *
michael@0 304 * You need to create an observer js object with the following member
michael@0 305 * functions:
michael@0 306 * Object onDragStart (event) // called when drag initiated,
michael@0 307 * // returns flavour list with data
michael@0 308 * // to stuff into transferable
michael@0 309 * void onDragOver (Object flavour) // called when element is dragged
michael@0 310 * // over, so that it can perform
michael@0 311 * // any drag-over feedback for provided
michael@0 312 * // flavour
michael@0 313 * void onDrop (Object data) // formatted data object dropped.
michael@0 314 * Object getSupportedFlavours () // returns a flavour list so that
michael@0 315 * // nsTransferable can determine
michael@0 316 * // whether or not to accept drop.
michael@0 317 **/
michael@0 318
michael@0 319 var nsDragAndDrop = {
michael@0 320
michael@0 321 _mDS: null,
michael@0 322 get mDragService()
michael@0 323 {
michael@0 324 if (!this._mDS)
michael@0 325 {
michael@0 326 const kDSContractID = "@mozilla.org/widget/dragservice;1";
michael@0 327 const kDSIID = Components.interfaces.nsIDragService;
michael@0 328 this._mDS = Components.classes[kDSContractID].getService(kDSIID);
michael@0 329 }
michael@0 330 return this._mDS;
michael@0 331 },
michael@0 332
michael@0 333 /**
michael@0 334 * void startDrag (DOMEvent aEvent, Object aDragDropObserver) ;
michael@0 335 *
michael@0 336 * called when a drag on an element is started.
michael@0 337 *
michael@0 338 * @param DOMEvent aEvent
michael@0 339 * the DOM event fired by the drag init
michael@0 340 * @param Object aDragDropObserver
michael@0 341 * javascript object of format described above that specifies
michael@0 342 * the way in which the element responds to drag events.
michael@0 343 **/
michael@0 344 startDrag: function (aEvent, aDragDropObserver)
michael@0 345 {
michael@0 346 if (!("onDragStart" in aDragDropObserver))
michael@0 347 return;
michael@0 348
michael@0 349 const kDSIID = Components.interfaces.nsIDragService;
michael@0 350 var dragAction = { action: kDSIID.DRAGDROP_ACTION_COPY + kDSIID.DRAGDROP_ACTION_MOVE + kDSIID.DRAGDROP_ACTION_LINK };
michael@0 351
michael@0 352 var transferData = { data: null };
michael@0 353 try
michael@0 354 {
michael@0 355 aDragDropObserver.onDragStart(aEvent, transferData, dragAction);
michael@0 356 }
michael@0 357 catch (e)
michael@0 358 {
michael@0 359 return; // not a draggable item, bail!
michael@0 360 }
michael@0 361
michael@0 362 if (!transferData.data) return;
michael@0 363 transferData = transferData.data;
michael@0 364
michael@0 365 var dt = aEvent.dataTransfer;
michael@0 366 var count = 0;
michael@0 367 do {
michael@0 368 var tds = transferData._XferID == "TransferData"
michael@0 369 ? transferData
michael@0 370 : transferData.dataList[count]
michael@0 371 for (var i = 0; i < tds.dataList.length; ++i)
michael@0 372 {
michael@0 373 var currData = tds.dataList[i];
michael@0 374 var currFlavour = currData.flavour.contentType;
michael@0 375 var value = currData.supports;
michael@0 376 if (value instanceof Components.interfaces.nsISupportsString)
michael@0 377 value = value.toString();
michael@0 378 dt.mozSetDataAt(currFlavour, value, count);
michael@0 379 }
michael@0 380
michael@0 381 count++;
michael@0 382 }
michael@0 383 while (transferData._XferID == "TransferDataSet" &&
michael@0 384 count < transferData.dataList.length);
michael@0 385
michael@0 386 dt.effectAllowed = "all";
michael@0 387 // a drag targeted at a tree should instead use the treechildren so that
michael@0 388 // the current selection is used as the drag feedback
michael@0 389 dt.addElement(aEvent.originalTarget.localName == "treechildren" ?
michael@0 390 aEvent.originalTarget : aEvent.target);
michael@0 391 aEvent.stopPropagation();
michael@0 392 },
michael@0 393
michael@0 394 /**
michael@0 395 * void dragOver (DOMEvent aEvent, Object aDragDropObserver) ;
michael@0 396 *
michael@0 397 * called when a drag passes over this element
michael@0 398 *
michael@0 399 * @param DOMEvent aEvent
michael@0 400 * the DOM event fired by passing over the element
michael@0 401 * @param Object aDragDropObserver
michael@0 402 * javascript object of format described above that specifies
michael@0 403 * the way in which the element responds to drag events.
michael@0 404 **/
michael@0 405 dragOver: function (aEvent, aDragDropObserver)
michael@0 406 {
michael@0 407 if (!("onDragOver" in aDragDropObserver))
michael@0 408 return;
michael@0 409 if (!this.checkCanDrop(aEvent, aDragDropObserver))
michael@0 410 return;
michael@0 411 var flavourSet = aDragDropObserver.getSupportedFlavours();
michael@0 412 for (var flavour in flavourSet.flavourTable)
michael@0 413 {
michael@0 414 if (this.mDragSession.isDataFlavorSupported(flavour))
michael@0 415 {
michael@0 416 aDragDropObserver.onDragOver(aEvent,
michael@0 417 flavourSet.flavourTable[flavour],
michael@0 418 this.mDragSession);
michael@0 419 aEvent.stopPropagation();
michael@0 420 aEvent.preventDefault();
michael@0 421 break;
michael@0 422 }
michael@0 423 }
michael@0 424 },
michael@0 425
michael@0 426 mDragSession: null,
michael@0 427
michael@0 428 /**
michael@0 429 * void drop (DOMEvent aEvent, Object aDragDropObserver) ;
michael@0 430 *
michael@0 431 * called when the user drops on the element
michael@0 432 *
michael@0 433 * @param DOMEvent aEvent
michael@0 434 * the DOM event fired by the drop
michael@0 435 * @param Object aDragDropObserver
michael@0 436 * javascript object of format described above that specifies
michael@0 437 * the way in which the element responds to drag events.
michael@0 438 **/
michael@0 439 drop: function (aEvent, aDragDropObserver)
michael@0 440 {
michael@0 441 if (!("onDrop" in aDragDropObserver))
michael@0 442 return;
michael@0 443 if (!this.checkCanDrop(aEvent, aDragDropObserver))
michael@0 444 return;
michael@0 445
michael@0 446 var flavourSet = aDragDropObserver.getSupportedFlavours();
michael@0 447
michael@0 448 var dt = aEvent.dataTransfer;
michael@0 449 var dataArray = [];
michael@0 450 var count = dt.mozItemCount;
michael@0 451 for (var i = 0; i < count; ++i) {
michael@0 452 var types = dt.mozTypesAt(i);
michael@0 453 for (var j = 0; j < flavourSet.flavours.length; j++) {
michael@0 454 var type = flavourSet.flavours[j].contentType;
michael@0 455 // dataTransfer uses text/plain but older code used text/unicode, so
michael@0 456 // switch this for compatibility
michael@0 457 var modtype = (type == "text/unicode") ? "text/plain" : type;
michael@0 458 if (Array.indexOf(types, modtype) >= 0) {
michael@0 459 var data = dt.mozGetDataAt(modtype, i);
michael@0 460 if (data) {
michael@0 461 // Non-strings need some non-zero value used for their data length.
michael@0 462 const kNonStringDataLength = 4;
michael@0 463
michael@0 464 var length = (typeof data == "string") ? data.length : kNonStringDataLength;
michael@0 465 dataArray[i] = FlavourToXfer(data, length, flavourSet.flavourTable[type]);
michael@0 466 break;
michael@0 467 }
michael@0 468 }
michael@0 469 }
michael@0 470 }
michael@0 471
michael@0 472 var transferData = new TransferDataSet(dataArray)
michael@0 473
michael@0 474 // hand over to the client to respond to dropped data
michael@0 475 var multiple = "canHandleMultipleItems" in aDragDropObserver && aDragDropObserver.canHandleMultipleItems;
michael@0 476 var dropData = multiple ? transferData : transferData.first.first;
michael@0 477 aDragDropObserver.onDrop(aEvent, dropData, this.mDragSession);
michael@0 478 aEvent.stopPropagation();
michael@0 479 },
michael@0 480
michael@0 481 /**
michael@0 482 * void dragExit (DOMEvent aEvent, Object aDragDropObserver) ;
michael@0 483 *
michael@0 484 * called when a drag leaves this element
michael@0 485 *
michael@0 486 * @param DOMEvent aEvent
michael@0 487 * the DOM event fired by leaving the element
michael@0 488 * @param Object aDragDropObserver
michael@0 489 * javascript object of format described above that specifies
michael@0 490 * the way in which the element responds to drag events.
michael@0 491 **/
michael@0 492 dragExit: function (aEvent, aDragDropObserver)
michael@0 493 {
michael@0 494 if (!this.checkCanDrop(aEvent, aDragDropObserver))
michael@0 495 return;
michael@0 496 if ("onDragExit" in aDragDropObserver)
michael@0 497 aDragDropObserver.onDragExit(aEvent, this.mDragSession);
michael@0 498 },
michael@0 499
michael@0 500 /**
michael@0 501 * void dragEnter (DOMEvent aEvent, Object aDragDropObserver) ;
michael@0 502 *
michael@0 503 * called when a drag enters in this element
michael@0 504 *
michael@0 505 * @param DOMEvent aEvent
michael@0 506 * the DOM event fired by entering in the element
michael@0 507 * @param Object aDragDropObserver
michael@0 508 * javascript object of format described above that specifies
michael@0 509 * the way in which the element responds to drag events.
michael@0 510 **/
michael@0 511 dragEnter: function (aEvent, aDragDropObserver)
michael@0 512 {
michael@0 513 if (!this.checkCanDrop(aEvent, aDragDropObserver))
michael@0 514 return;
michael@0 515 if ("onDragEnter" in aDragDropObserver)
michael@0 516 aDragDropObserver.onDragEnter(aEvent, this.mDragSession);
michael@0 517 },
michael@0 518
michael@0 519 /**
michael@0 520 * Boolean checkCanDrop (DOMEvent aEvent, Object aDragDropObserver) ;
michael@0 521 *
michael@0 522 * Sets the canDrop attribute for the drag session.
michael@0 523 * returns false if there is no current drag session.
michael@0 524 *
michael@0 525 * @param DOMEvent aEvent
michael@0 526 * the DOM event fired by the drop
michael@0 527 * @param Object aDragDropObserver
michael@0 528 * javascript object of format described above that specifies
michael@0 529 * the way in which the element responds to drag events.
michael@0 530 **/
michael@0 531 checkCanDrop: function (aEvent, aDragDropObserver)
michael@0 532 {
michael@0 533 if (!this.mDragSession)
michael@0 534 this.mDragSession = this.mDragService.getCurrentSession();
michael@0 535 if (!this.mDragSession)
michael@0 536 return false;
michael@0 537 this.mDragSession.canDrop = this.mDragSession.sourceNode != aEvent.target;
michael@0 538 if ("canDrop" in aDragDropObserver)
michael@0 539 this.mDragSession.canDrop &= aDragDropObserver.canDrop(aEvent, this.mDragSession);
michael@0 540 return true;
michael@0 541 },
michael@0 542
michael@0 543 /**
michael@0 544 * Do a security check for drag n' drop. Make sure the source document
michael@0 545 * can load the dragged link.
michael@0 546 *
michael@0 547 * @param DOMEvent aEvent
michael@0 548 * the DOM event fired by leaving the element
michael@0 549 * @param Object aDragDropObserver
michael@0 550 * javascript object of format described above that specifies
michael@0 551 * the way in which the element responds to drag events.
michael@0 552 * @param String aDraggedText
michael@0 553 * the text being dragged
michael@0 554 **/
michael@0 555 dragDropSecurityCheck: function (aEvent, aDragSession, aDraggedText)
michael@0 556 {
michael@0 557 // Strip leading and trailing whitespace, then try to create a
michael@0 558 // URI from the dropped string. If that succeeds, we're
michael@0 559 // dropping a URI and we need to do a security check to make
michael@0 560 // sure the source document can load the dropped URI. We don't
michael@0 561 // so much care about creating the real URI here
michael@0 562 // (i.e. encoding differences etc don't matter), we just want
michael@0 563 // to know if aDraggedText really is a URI.
michael@0 564
michael@0 565 aDraggedText = aDraggedText.replace(/^\s*|\s*$/g, '');
michael@0 566
michael@0 567 var uri;
michael@0 568 var ioService = Components.classes["@mozilla.org/network/io-service;1"]
michael@0 569 .getService(Components.interfaces.nsIIOService);
michael@0 570 try {
michael@0 571 uri = ioService.newURI(aDraggedText, null, null);
michael@0 572 } catch (e) {
michael@0 573 }
michael@0 574
michael@0 575 if (!uri)
michael@0 576 return;
michael@0 577
michael@0 578 // aDraggedText is a URI, do the security check.
michael@0 579 const nsIScriptSecurityManager = Components.interfaces
michael@0 580 .nsIScriptSecurityManager;
michael@0 581 var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
michael@0 582 .getService(nsIScriptSecurityManager);
michael@0 583
michael@0 584 if (!aDragSession)
michael@0 585 aDragSession = this.mDragService.getCurrentSession();
michael@0 586
michael@0 587 var sourceDoc = aDragSession.sourceDocument;
michael@0 588 // Use "file:///" as the default sourceURI so that drops of file:// URIs
michael@0 589 // are always allowed.
michael@0 590 var principal = sourceDoc ? sourceDoc.nodePrincipal
michael@0 591 : secMan.getSimpleCodebasePrincipal(ioService.newURI("file:///", null, null));
michael@0 592
michael@0 593 try {
michael@0 594 secMan.checkLoadURIStrWithPrincipal(principal, aDraggedText,
michael@0 595 nsIScriptSecurityManager.STANDARD);
michael@0 596 } catch (e) {
michael@0 597 // Stop event propagation right here.
michael@0 598 aEvent.stopPropagation();
michael@0 599
michael@0 600 throw "Drop of " + aDraggedText + " denied.";
michael@0 601 }
michael@0 602 }
michael@0 603 };
michael@0 604

mercurial