[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/webroot/rsrc/js/core/ -> DragAndDropFileUpload.js (source)

   1  /**
   2   * @requires javelin-install
   3   *           javelin-util
   4   *           javelin-request
   5   *           javelin-dom
   6   *           javelin-uri
   7   *           phabricator-file-upload
   8   * @provides phabricator-drag-and-drop-file-upload
   9   * @javelin
  10   */
  11  
  12  JX.install('PhabricatorDragAndDropFileUpload', {
  13  
  14    construct : function(node) {
  15      this._node = node;
  16    },
  17  
  18    events : [
  19      'didBeginDrag',
  20      'didEndDrag',
  21      'willUpload',
  22      'progress',
  23      'didUpload',
  24      'didError'],
  25  
  26    statics : {
  27      isSupported : function() {
  28        // TODO: Is there a better capability test for this? This seems okay in
  29        // Safari, Firefox and Chrome.
  30  
  31        return !!window.FileList;
  32      },
  33      isPasteSupported : function() {
  34        // TODO: Needs to check if event.clipboardData is available.
  35        // Works in Chrome, doesn't work in Firefox 10.
  36        return !!window.FileList;
  37      }
  38    },
  39  
  40    members : {
  41      _node : null,
  42      _depth : 0,
  43      _updateDepth : function(delta) {
  44        if (this._depth === 0 && delta > 0) {
  45          this.invoke('didBeginDrag');
  46        }
  47  
  48        this._depth += delta;
  49  
  50        if (this._depth === 0 && delta < 0) {
  51          this.invoke('didEndDrag');
  52        }
  53      },
  54  
  55      start : function() {
  56  
  57        // TODO: move this to JX.DOM.contains()?
  58        function contains(container, child) {
  59          do {
  60            if (child === container) {
  61              return true;
  62            }
  63            child = child.parentNode;
  64          } while (child);
  65  
  66          return false;
  67        }
  68  
  69        // Firefox has some issues sometimes; implement this click handler so
  70        // the user can recover. See T5188.
  71        JX.DOM.listen(
  72          this._node,
  73          'click',
  74          null,
  75          JX.bind(this, function (e) {
  76            if (this._depth) {
  77              e.kill();
  78              // Force depth to 0.
  79              this._updateDepth(-this._depth);
  80            }
  81          }));
  82  
  83        // We track depth so that the _node may have children inside of it and
  84        // not become unselected when they are dragged over.
  85        JX.DOM.listen(
  86          this._node,
  87          'dragenter',
  88          null,
  89          JX.bind(this, function(e) {
  90            if (contains(this._node, e.getTarget())) {
  91              this._updateDepth(1);
  92            }
  93          }));
  94  
  95        JX.DOM.listen(
  96          this._node,
  97          'dragleave',
  98          null,
  99          JX.bind(this, function(e) {
 100            if (contains(this._node, e.getTarget())) {
 101              this._updateDepth(-1);
 102            }
 103          }));
 104  
 105        JX.DOM.listen(
 106          this._node,
 107          'dragover',
 108          null,
 109          function(e) {
 110            // NOTE: We must set this, or Chrome refuses to drop files from the
 111            // download shelf.
 112            e.getRawEvent().dataTransfer.dropEffect = 'copy';
 113            e.kill();
 114          });
 115  
 116        JX.DOM.listen(
 117          this._node,
 118          'drop',
 119          null,
 120          JX.bind(this, function(e) {
 121            e.kill();
 122  
 123            var files = e.getRawEvent().dataTransfer.files;
 124            for (var ii = 0; ii < files.length; ii++) {
 125              this._sendRequest(files[ii]);
 126            }
 127  
 128            // Force depth to 0.
 129            this._updateDepth(-this._depth);
 130          }));
 131  
 132        if (JX.PhabricatorDragAndDropFileUpload.isPasteSupported()) {
 133          JX.DOM.listen(
 134            this._node,
 135            'paste',
 136            null,
 137            JX.bind(this, function(e) {
 138              var clipboard = e.getRawEvent().clipboardData;
 139              if (!clipboard) {
 140                return;
 141              }
 142  
 143              // If there's any text on the clipboard, just let the event fire
 144              // normally, choosing the text over any images. See T5437 / D9647.
 145              var text = clipboard.getData('text/plain').toString();
 146              if (text.length) {
 147                return;
 148              }
 149  
 150              // Safari and Firefox have clipboardData, but no items. They
 151              // don't seem to provide a way to get image data directly yet.
 152              if (!clipboard.items) {
 153                return;
 154              }
 155  
 156              for (var ii = 0; ii < clipboard.items.length; ii++) {
 157                var item = clipboard.items[ii];
 158                if (!/^image\//.test(item.type)) {
 159                  continue;
 160                }
 161                var spec = item.getAsFile();
 162                // pasted files don't have a name; see
 163                // https://code.google.com/p/chromium/issues/detail?id=361145
 164                if (!spec.name) {
 165                  spec.name = 'pasted_file';
 166                }
 167                this._sendRequest(spec);
 168              }
 169            }));
 170        }
 171      },
 172      _sendRequest : function(spec) {
 173        var file = new JX.PhabricatorFileUpload()
 174          .setName(spec.name)
 175          .setTotalBytes(spec.size)
 176          .setStatus('uploading')
 177          .update();
 178  
 179        this.invoke('willUpload', file);
 180  
 181        var up_uri = JX.$U(this.getURI())
 182          .setQueryParam('name', file.getName())
 183          .setQueryParam('__upload__', 1);
 184  
 185        if (this.getViewPolicy()) {
 186          up_uri.setQueryParam('viewPolicy', this.getViewPolicy());
 187        }
 188  
 189        up_uri = up_uri.toString();
 190  
 191        var onupload = JX.bind(this, function(r) {
 192          if (r.error) {
 193            file
 194              .setStatus('error')
 195              .setError(r.error)
 196              .update();
 197  
 198            this.invoke('didError', file);
 199          } else {
 200            file
 201              .setID(r.id)
 202              .setPHID(r.phid)
 203              .setURI(r.uri)
 204              .setMarkup(r.html)
 205              .setStatus('done')
 206              .update();
 207  
 208            this.invoke('didUpload', file);
 209          }
 210        });
 211  
 212        var req = new JX.Request(up_uri, onupload);
 213  
 214        var onerror = JX.bind(this, function(error) {
 215          file.setStatus('error');
 216  
 217          if (error) {
 218            file.setError(error.code + ': ' + error.info);
 219          } else {
 220            var xhr = req.getTransport();
 221            if (xhr.responseText) {
 222              file.setError('Server responded: ' + xhr.responseText);
 223            }
 224          }
 225  
 226          file.update();
 227          this.invoke('didError', file);
 228        });
 229  
 230        var onprogress = JX.bind(this, function(progress) {
 231          file
 232            .setTotalBytes(progress.total)
 233            .setUploadedBytes(progress.loaded)
 234            .update();
 235  
 236          this.invoke('progress', file);
 237        });
 238  
 239        req.listen('error', onerror);
 240        req.listen('uploadprogress', onprogress);
 241  
 242        req
 243          .setRawData(spec)
 244          .send();
 245      }
 246    },
 247    properties: {
 248      URI : null,
 249      activatedClass : null,
 250      viewPolicy : null
 251    }
 252  });


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1