UploadDropZone.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /*
  2. * Copyright (C) 2015 - present Instructure, Inc.
  3. *
  4. * This file is part of Canvas.
  5. *
  6. * Canvas is free software: you can redistribute it and/or modify it under
  7. * the terms of the GNU Affero General Public License as published by the Free
  8. * Software Foundation, version 3 of the License.
  9. *
  10. * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
  11. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. * details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License along
  16. * with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. import _ from 'underscore'
  19. import React from 'react'
  20. import PropTypes from 'prop-types'
  21. import ReactDOM from 'react-dom'
  22. import $ from 'jquery'
  23. import I18n from 'i18n!upload_drop_zone'
  24. import FileOptionsCollection from 'compiled/react_files/modules/FileOptionsCollection'
  25. import Folder from 'compiled/models/Folder'
  26. import 'compiled/jquery.rails_flash_notifications'
  27. var UploadDropZone = React.createClass({
  28. displayName: 'UploadDropZone',
  29. propTypes: {
  30. currentFolder: PropTypes.instanceOf(Folder)
  31. },
  32. getInitialState: function () {
  33. return ({active: false});
  34. },
  35. componentDidMount: function() {
  36. this.getParent().addEventListener('dragenter', this.onParentDragEnter);
  37. document.addEventListener('dragenter', this.killWindowDropDisplay);
  38. document.addEventListener('dragover', this.killWindowDropDisplay);
  39. document.addEventListener('drop', this.killWindowDrop);
  40. },
  41. componentWillUnmount: function() {
  42. this.getParent().removeEventListener('dragenter', this.onParentDragEnter);
  43. document.removeEventListener('dragenter', this.killWindowDropDisplay);
  44. document.removeEventListener('dragover', this.killWindowDropDisplay);
  45. document.removeEventListener('drop', this.killWindowDrop);
  46. },
  47. onDragEnter: function (e) {
  48. if (this.shouldAcceptDrop(e.dataTransfer)) {
  49. this.setState({active: true});
  50. e.dataTransfer.dropEffect = 'copy';
  51. e.preventDefault();
  52. e.stopPropagation(); // keep event from getting to document
  53. return false;
  54. } else {
  55. return true;
  56. }
  57. },
  58. onDragLeave: function (e) {
  59. this.setState({active: false});
  60. },
  61. onDrop: function (e) {
  62. this.setState({active: false});
  63. FileOptionsCollection.setFolder(this.props.currentFolder);
  64. FileOptionsCollection.setOptionsFromFiles(e.dataTransfer.files, true);
  65. e.preventDefault();
  66. e.stopPropagation();
  67. return false;
  68. },
  69. /* when you drag a file over the parent, make drop zone active
  70. # remainder of drag-n-drop events happen on dropzone
  71. */
  72. onParentDragEnter: function (e) {
  73. if (this.shouldAcceptDrop(e.dataTransfer)) {
  74. if (!this.state.active) {
  75. this.setState({active: true});
  76. }
  77. }
  78. },
  79. killWindowDropDisplay: function (e) {
  80. if (e.target != this.getParent()) {
  81. e.preventDefault();
  82. }
  83. },
  84. killWindowDrop: function (e) {
  85. e.preventDefault();
  86. },
  87. shouldAcceptDrop: function (dataTransfer) {
  88. if (dataTransfer) {
  89. return (_.indexOf(dataTransfer.types, 'Files') >= 0);
  90. }
  91. },
  92. getParent: function () {
  93. // We are actually returning the parent's parent here because that
  94. // gives a much more consistently sized container to start displaying
  95. // the drop zone overlay with.
  96. return ReactDOM.findDOMNode(this).parentElement.parentElement;
  97. },
  98. buildNonActiveDropZone: function () {
  99. return (<div className='UploadDropZone'></div>);
  100. },
  101. buildInstructions: function () {
  102. return (
  103. <div className='UploadDropZone__instructions'>
  104. <i className='icon-upload UploadDropZone__instructions--icon-upload' />
  105. <div>
  106. <p className='UploadDropZone__instructions--drag'>
  107. { I18n.t('drop_to_upload', 'Drop items to upload') }
  108. </p>
  109. </div>
  110. </div>
  111. );
  112. },
  113. buildDropZone: function () {
  114. return (
  115. <div className='UploadDropZone UploadDropZone__active'
  116. onDrop = { this.onDrop }
  117. onDragLeave = { this.onDragLeave }
  118. onDragOver = { this.onDragEnter }
  119. onDragEnter = { this.onDragEnter }
  120. >
  121. {this.buildInstructions() }
  122. </div>
  123. );
  124. },
  125. render: function () {
  126. if (this.state.active) {
  127. return this.buildDropZone();
  128. } else {
  129. return this.buildNonActiveDropZone();
  130. }
  131. }
  132. });
  133. export default UploadDropZone