aboutsummaryrefslogtreecommitdiffstats
path: root/web_src/js/features/dropzone.js
blob: b3acaf5e6f09eb7c9d1b8178157e6e812ba10ea3 (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
import $ from 'jquery';
import {svg} from '../svg.js';
import {htmlEscape} from 'escape-goat';
import {clippie} from 'clippie';
import {showTemporaryTooltip} from '../modules/tippy.js';
import {POST} from '../modules/fetch.js';
import {showErrorToast} from '../modules/toast.js';

const {csrfToken, i18n} = window.config;

export async function createDropzone(el, opts) {
  const [{Dropzone}] = await Promise.all([
    import(/* webpackChunkName: "dropzone" */'dropzone'),
    import(/* webpackChunkName: "dropzone" */'dropzone/dist/dropzone.css'),
  ]);
  return new Dropzone(el, opts);
}

export function initGlobalDropzone() {
  for (const el of document.querySelectorAll('.dropzone')) {
    initDropzone(el);
  }
}

export function initDropzone(el) {
  const $dropzone = $(el);
  const _promise = createDropzone(el, {
    url: $dropzone.data('upload-url'),
    headers: {'X-Csrf-Token': csrfToken},
    maxFiles: $dropzone.data('max-file'),
    maxFilesize: $dropzone.data('max-size'),
    acceptedFiles: (['*/*', ''].includes($dropzone.data('accepts'))) ? null : $dropzone.data('accepts'),
    addRemoveLinks: true,
    dictDefaultMessage: $dropzone.data('default-message'),
    dictInvalidFileType: $dropzone.data('invalid-input-type'),
    dictFileTooBig: $dropzone.data('file-too-big'),
    dictRemoveFile: $dropzone.data('remove-file'),
    timeout: 0,
    thumbnailMethod: 'contain',
    thumbnailWidth: 480,
    thumbnailHeight: 480,
    init() {
      this.on('success', (file, data) => {
        file.uuid = data.uuid;
        const $input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid);
        $dropzone.find('.files').append($input);
        // Create a "Copy Link" element, to conveniently copy the image
        // or file link as Markdown to the clipboard
        const copyLinkElement = document.createElement('div');
        copyLinkElement.className = 'tw-text-center';
        // The a element has a hardcoded cursor: pointer because the default is overridden by .dropzone
        copyLinkElement.innerHTML = `<a href="#" style="cursor: pointer;">${svg('octicon-copy', 14, 'copy link')} Copy link</a>`;
        copyLinkElement.addEventListener('click', async (e) => {
          e.preventDefault();
          let fileMarkdown = `[${file.name}](/attachments/${file.uuid})`;
          if (file.type.startsWith('image/')) {
            fileMarkdown = `!${fileMarkdown}`;
          } else if (file.type.startsWith('video/')) {
            fileMarkdown = `<video src="/attachments/${file.uuid}" title="${htmlEscape(file.name)}" controls></video>`;
          }
          const success = await clippie(fileMarkdown);
          showTemporaryTooltip(e.target, success ? i18n.copy_success : i18n.copy_error);
        });
        file.previewTemplate.append(copyLinkElement);
      });
      this.on('removedfile', (file) => {
        $(`#${file.uuid}`).remove();
        if ($dropzone.data('remove-url')) {
          POST($dropzone.data('remove-url'), {
            data: new URLSearchParams({file: file.uuid}),
          });
        }
      });
      this.on('error', function (file, message) {
        showErrorToast(message);
        this.removeFile(file);
      });
    },
  });
}