summaryrefslogtreecommitdiffstats
path: root/chromium/chrome/browser/resources/extensions/drag_and_drop_handler.js
blob: 15324adb0ef892433ccd67bb031f1f040f513a34 (plain)
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
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('extensions', function() {
  'use strict';

  /** @implements cr.ui.DragWrapperDelegate */
  class DragAndDropHandler {
    /**
     * @param {boolean} dragEnabled
     * @param {!EventTarget} target
     */
    constructor(dragEnabled, target) {
      this.dragEnabled = dragEnabled;

      /** @private {!EventTarget} */
      this.eventTarget_ = target;
    }

    /** @override */
    shouldAcceptDrag(e) {
      // External Extension installation can be disabled globally, e.g. while a
      // different overlay is already showing.
      if (!this.dragEnabled) {
        return false;
      }

      // We can't access filenames during the 'dragenter' event, so we have to
      // wait until 'drop' to decide whether to do something with the file or
      // not.
      // See: http://www.w3.org/TR/2011/WD-html5-20110113/dnd.html#concept-dnd-p
      return !!e.dataTransfer.types &&
          e.dataTransfer.types.indexOf('Files') > -1;
    }

    /** @override */
    doDragEnter() {
      extensions.Service.getInstance().notifyDragInstallInProgress();
      this.eventTarget_.dispatchEvent(
          new CustomEvent('extension-drag-started'));
    }

    /** @override */
    doDragLeave() {
      this.fireDragEnded_();
    }

    /** @override */
    doDragOver(e) {
      e.preventDefault();
    }

    /** @override */
    doDrop(e) {
      this.fireDragEnded_();
      if (e.dataTransfer.files.length != 1) {
        return;
      }

      let handled = false;

      // Files lack a check if they're a directory, but we can find out through
      // its item entry.
      const item = e.dataTransfer.items[0];
      if (item.kind === 'file' && item.webkitGetAsEntry().isDirectory) {
        handled = true;
        this.handleDirectoryDrop_();
      } else if (/\.(crx|user\.js|zip)$/i.test(e.dataTransfer.files[0].name)) {
        // Only process files that look like extensions. Other files should
        // navigate the browser normally.
        handled = true;
        this.handleFileDrop_();
      }

      if (handled) {
        e.preventDefault();
      }
    }

    /**
     * Handles a dropped file.
     * @private
     */
    handleFileDrop_() {
      extensions.Service.getInstance().installDroppedFile();
    }

    /**
     * Handles a dropped directory.
     * @private
     */
    handleDirectoryDrop_() {
      extensions.Service.getInstance().loadUnpackedFromDrag().catch(
          loadError => {
            this.eventTarget_.dispatchEvent(new CustomEvent(
                'drag-and-drop-load-error', {detail: loadError}));
          });
    }

    /** @private */
    fireDragEnded_() {
      this.eventTarget_.dispatchEvent(new CustomEvent('extension-drag-ended'));
    }
  }

  return {
    DragAndDropHandler: DragAndDropHandler,
  };
});