index.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. const { Plugin } = require('@uppy/core')
  2. const Translator = require('@uppy/utils/lib/Translator')
  3. const { h } = require('preact')
  4. const { RequestClient } = require('@uppy/companion-client')
  5. const UrlUI = require('./UrlUI.js')
  6. const forEachDroppedOrPastedUrl = require('./utils/forEachDroppedOrPastedUrl')
  7. function UrlIcon () {
  8. return (
  9. <svg aria-hidden="true" focusable="false" width="23" height="23" viewBox="0 0 23 23">
  10. <path d="M20.485 11.236l-2.748 2.737c-.184.182-.367.365-.642.547-1.007.73-2.107 1.095-3.298 1.095-1.65 0-3.298-.73-4.398-2.19-.275-.365-.183-1.003.183-1.277.367-.273 1.008-.182 1.283.183 1.191 1.642 3.482 1.915 5.13.73a.714.714 0 0 0 .367-.365l2.75-2.737c1.373-1.46 1.373-3.74-.093-5.108a3.72 3.72 0 0 0-5.13 0L12.33 6.4a.888.888 0 0 1-1.283 0 .88.88 0 0 1 0-1.277l1.558-1.55a5.38 5.38 0 0 1 7.605 0c2.29 2.006 2.382 5.564.274 7.662zm-8.979 6.294L9.95 19.081a3.72 3.72 0 0 1-5.13 0c-1.467-1.368-1.467-3.74-.093-5.108l2.75-2.737.366-.365c.824-.547 1.74-.82 2.748-.73 1.008.183 1.833.639 2.382 1.46.275.365.917.456 1.283.182.367-.273.458-.912.183-1.277-.916-1.186-2.199-1.915-3.573-2.098-1.374-.273-2.84.091-4.031 1.004l-.55.547-2.749 2.737c-2.107 2.189-2.015 5.655.092 7.753C4.727 21.453 6.101 22 7.475 22c1.374 0 2.749-.547 3.848-1.55l1.558-1.551a.88.88 0 0 0 0-1.278c-.367-.364-1.008-.456-1.375-.09z" fill="#FF814F" fill-rule="nonzero" />
  11. </svg>
  12. )
  13. }
  14. /**
  15. * Url
  16. *
  17. */
  18. module.exports = class Url extends Plugin {
  19. static VERSION = require('../package.json').version
  20. constructor (uppy, opts) {
  21. super(uppy, opts)
  22. this.id = this.opts.id || 'Url'
  23. this.title = this.opts.title || 'Link'
  24. this.type = 'acquirer'
  25. this.icon = () => <UrlIcon />
  26. // Set default options and locale
  27. this.defaultLocale = {
  28. strings: {
  29. import: 'Import',
  30. enterUrlToImport: 'Enter URL to import a file',
  31. failedToFetch: 'Companion failed to fetch this URL, please make sure it’s correct',
  32. enterCorrectUrl: 'Incorrect URL: Please make sure you are entering a direct link to a file'
  33. }
  34. }
  35. const defaultOptions = {}
  36. this.opts = { ...defaultOptions, ...opts }
  37. this.i18nInit()
  38. this.hostname = this.opts.companionUrl
  39. if (!this.hostname) {
  40. throw new Error('Companion hostname is required, please consult https://uppy.io/docs/companion')
  41. }
  42. // Bind all event handlers for referencability
  43. this.getMeta = this.getMeta.bind(this)
  44. this.addFile = this.addFile.bind(this)
  45. this.handleRootDrop = this.handleRootDrop.bind(this)
  46. this.handleRootPaste = this.handleRootPaste.bind(this)
  47. this.client = new RequestClient(uppy, {
  48. companionUrl: this.opts.companionUrl,
  49. companionHeaders: this.opts.companionHeaders || this.opts.serverHeaders
  50. })
  51. }
  52. setOptions (newOpts) {
  53. super.setOptions(newOpts)
  54. this.i18nInit()
  55. }
  56. i18nInit () {
  57. this.translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
  58. this.i18n = this.translator.translate.bind(this.translator)
  59. this.i18nArray = this.translator.translateArray.bind(this.translator)
  60. this.setPluginState() // so that UI re-renders and we see the updated locale
  61. }
  62. getFileNameFromUrl (url) {
  63. return url.substring(url.lastIndexOf('/') + 1)
  64. }
  65. checkIfCorrectURL (url) {
  66. if (!url) return false
  67. const protocol = url.match(/^([a-z0-9]+):\/\//)[1]
  68. if (protocol !== 'http' && protocol !== 'https') {
  69. return false
  70. }
  71. return true
  72. }
  73. addProtocolToURL (url) {
  74. const protocolRegex = /^[a-z0-9]+:\/\//
  75. const defaultProtocol = 'http://'
  76. if (protocolRegex.test(url)) {
  77. return url
  78. }
  79. return defaultProtocol + url
  80. }
  81. getMeta (url) {
  82. return this.client.post('url/meta', { url })
  83. .then((res) => {
  84. if (res.error) {
  85. this.uppy.log('[URL] Error:')
  86. this.uppy.log(res.error)
  87. throw new Error('Failed to fetch the file')
  88. }
  89. return res
  90. })
  91. }
  92. addFile (url) {
  93. url = this.addProtocolToURL(url)
  94. if (!this.checkIfCorrectURL(url)) {
  95. this.uppy.log(`[URL] Incorrect URL entered: ${url}`)
  96. this.uppy.info(this.i18n('enterCorrectUrl'), 'error', 4000)
  97. return
  98. }
  99. return this.getMeta(url)
  100. .then((meta) => {
  101. const tagFile = {
  102. source: this.id,
  103. name: this.getFileNameFromUrl(url),
  104. type: meta.type,
  105. data: {
  106. size: meta.size
  107. },
  108. isRemote: true,
  109. body: {
  110. url: url
  111. },
  112. remote: {
  113. companionUrl: this.opts.companionUrl,
  114. url: `${this.hostname}/url/get`,
  115. body: {
  116. fileId: url,
  117. url: url
  118. },
  119. providerOptions: this.client.opts
  120. }
  121. }
  122. return tagFile
  123. })
  124. .then((tagFile) => {
  125. this.uppy.log('[Url] Adding remote file')
  126. try {
  127. this.uppy.addFile(tagFile)
  128. } catch (err) {
  129. if (!err.isRestriction) {
  130. this.uppy.log(err)
  131. }
  132. }
  133. })
  134. .catch((err) => {
  135. this.uppy.log(err)
  136. this.uppy.info({
  137. message: this.i18n('failedToFetch'),
  138. details: err
  139. }, 'error', 4000)
  140. })
  141. }
  142. handleRootDrop (e) {
  143. forEachDroppedOrPastedUrl(e.dataTransfer, 'drop', (url) => {
  144. this.uppy.log(`[URL] Adding file from dropped url: ${url}`)
  145. this.addFile(url)
  146. })
  147. }
  148. handleRootPaste (e) {
  149. forEachDroppedOrPastedUrl(e.clipboardData, 'paste', (url) => {
  150. this.uppy.log(`[URL] Adding file from pasted url: ${url}`)
  151. this.addFile(url)
  152. })
  153. }
  154. render (state) {
  155. return <UrlUI i18n={this.i18n} addFile={this.addFile} />
  156. }
  157. install () {
  158. const target = this.opts.target
  159. if (target) {
  160. this.mount(target, this)
  161. }
  162. }
  163. uninstall () {
  164. this.unmount()
  165. }
  166. }