index.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. const { UIPlugin } = 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="32" height="32" viewBox="0 0 32 32">
  10. <g fill="none" fillRule="evenodd">
  11. <rect className="uppy-ProviderIconBg" fill="#FF753E" width="32" height="32" rx="16" />
  12. <path d="M22.788 15.389l-2.199 2.19a3.184 3.184 0 0 1-.513.437c-.806.584-1.686.876-2.638.876a4.378 4.378 0 0 1-3.519-1.752c-.22-.292-.146-.802.147-1.021.293-.22.806-.146 1.026.146.953 1.313 2.785 1.532 4.105.583a.571.571 0 0 0 .293-.292l2.199-2.189c1.1-1.167 1.1-2.992-.073-4.086a2.976 2.976 0 0 0-4.105 0l-1.246 1.24a.71.71 0 0 1-1.026 0 .703.703 0 0 1 0-1.022l1.246-1.24a4.305 4.305 0 0 1 6.083 0c1.833 1.605 1.906 4.451.22 6.13zm-7.183 5.035l-1.246 1.24a2.976 2.976 0 0 1-4.105 0c-1.172-1.094-1.172-2.991-.073-4.086l2.2-2.19.292-.291c.66-.438 1.393-.657 2.2-.584.805.146 1.465.51 1.905 1.168.22.292.733.365 1.026.146.293-.22.367-.73.147-1.022-.733-.949-1.76-1.532-2.859-1.678-1.1-.22-2.272.073-3.225.802l-.44.438-2.199 2.19c-1.686 1.75-1.612 4.524.074 6.202.88.803 1.979 1.241 3.078 1.241 1.1 0 2.199-.438 3.079-1.24l1.246-1.241a.703.703 0 0 0 0-1.022c-.294-.292-.807-.365-1.1-.073z" fill="#FFF" fillRule="nonzero" />
  13. </g>
  14. </svg>
  15. )
  16. }
  17. /**
  18. * Url
  19. *
  20. */
  21. module.exports = class Url extends UIPlugin {
  22. static VERSION = require('../package.json').version
  23. constructor (uppy, opts) {
  24. super(uppy, opts)
  25. this.id = this.opts.id || 'Url'
  26. this.title = this.opts.title || 'Link'
  27. this.type = 'acquirer'
  28. this.icon = () => <UrlIcon />
  29. // Set default options and locale
  30. this.defaultLocale = {
  31. strings: {
  32. import: 'Import',
  33. enterUrlToImport: 'Enter URL to import a file',
  34. failedToFetch: 'Companion failed to fetch this URL, please make sure it’s correct',
  35. enterCorrectUrl: 'Incorrect URL: Please make sure you are entering a direct link to a file',
  36. },
  37. }
  38. const defaultOptions = {}
  39. this.opts = { ...defaultOptions, ...opts }
  40. this.i18nInit()
  41. this.hostname = this.opts.companionUrl
  42. if (!this.hostname) {
  43. throw new Error('Companion hostname is required, please consult https://uppy.io/docs/companion')
  44. }
  45. // Bind all event handlers for referencability
  46. this.getMeta = this.getMeta.bind(this)
  47. this.addFile = this.addFile.bind(this)
  48. this.handleRootDrop = this.handleRootDrop.bind(this)
  49. this.handleRootPaste = this.handleRootPaste.bind(this)
  50. this.client = new RequestClient(uppy, {
  51. companionUrl: this.opts.companionUrl,
  52. companionHeaders: this.opts.companionHeaders,
  53. companionCookiesRule: this.opts.companionCookiesRule,
  54. })
  55. }
  56. setOptions (newOpts) {
  57. super.setOptions(newOpts)
  58. this.i18nInit()
  59. }
  60. i18nInit () {
  61. this.translator = new Translator([this.defaultLocale, this.uppy.locale, this.opts.locale])
  62. this.i18n = this.translator.translate.bind(this.translator)
  63. this.i18nArray = this.translator.translateArray.bind(this.translator)
  64. this.setPluginState() // so that UI re-renders and we see the updated locale
  65. }
  66. getFileNameFromUrl (url) {
  67. return url.substring(url.lastIndexOf('/') + 1)
  68. }
  69. checkIfCorrectURL (url) {
  70. if (!url) return false
  71. const protocol = url.match(/^([a-z0-9]+):\/\//)[1]
  72. if (protocol !== 'http' && protocol !== 'https') {
  73. return false
  74. }
  75. return true
  76. }
  77. addProtocolToURL (url) {
  78. const protocolRegex = /^[a-z0-9]+:\/\//
  79. const defaultProtocol = 'http://'
  80. if (protocolRegex.test(url)) {
  81. return url
  82. }
  83. return defaultProtocol + url
  84. }
  85. getMeta (url) {
  86. return this.client.post('url/meta', { url })
  87. .then((res) => {
  88. if (res.error) {
  89. this.uppy.log('[URL] Error:')
  90. this.uppy.log(res.error)
  91. throw new Error('Failed to fetch the file')
  92. }
  93. return res
  94. })
  95. }
  96. addFile (url) {
  97. url = this.addProtocolToURL(url)
  98. if (!this.checkIfCorrectURL(url)) {
  99. this.uppy.log(`[URL] Incorrect URL entered: ${url}`)
  100. this.uppy.info(this.i18n('enterCorrectUrl'), 'error', 4000)
  101. return
  102. }
  103. return this.getMeta(url)
  104. .then((meta) => {
  105. const tagFile = {
  106. source: this.id,
  107. name: this.getFileNameFromUrl(url),
  108. type: meta.type,
  109. data: {
  110. size: meta.size,
  111. },
  112. isRemote: true,
  113. body: {
  114. url,
  115. },
  116. remote: {
  117. companionUrl: this.opts.companionUrl,
  118. url: `${this.hostname}/url/get`,
  119. body: {
  120. fileId: url,
  121. url,
  122. },
  123. providerOptions: this.client.opts,
  124. },
  125. }
  126. return tagFile
  127. })
  128. .then((tagFile) => {
  129. this.uppy.log('[Url] Adding remote file')
  130. try {
  131. return this.uppy.addFile(tagFile)
  132. } catch (err) {
  133. if (!err.isRestriction) {
  134. this.uppy.log(err)
  135. }
  136. return err
  137. }
  138. })
  139. .catch((err) => {
  140. this.uppy.log(err)
  141. this.uppy.info({
  142. message: this.i18n('failedToFetch'),
  143. details: err,
  144. }, 'error', 4000)
  145. return err
  146. })
  147. }
  148. handleRootDrop (e) {
  149. forEachDroppedOrPastedUrl(e.dataTransfer, 'drop', (url) => {
  150. this.uppy.log(`[URL] Adding file from dropped url: ${url}`)
  151. this.addFile(url)
  152. })
  153. }
  154. handleRootPaste (e) {
  155. forEachDroppedOrPastedUrl(e.clipboardData, 'paste', (url) => {
  156. this.uppy.log(`[URL] Adding file from pasted url: ${url}`)
  157. this.addFile(url)
  158. })
  159. }
  160. render (state) {
  161. return <UrlUI i18n={this.i18n} addFile={this.addFile} />
  162. }
  163. install () {
  164. const { target } = this.opts
  165. if (target) {
  166. this.mount(target, this)
  167. }
  168. }
  169. uninstall () {
  170. this.unmount()
  171. }
  172. }