PageSourceSearch

https://toutanboa.fr/assets/controllers/image_uploader_controller

js toutanboa.fr collected 2026-09-29 03:40:29 UTC 4,690 bytes, 171 lines download raw bytes

1import { Dropzone } from "dropzone";
2import { Controller } from "@hotwired/stimulus";
3import { DirectUpload } from "@rails/activestorage";
4import { getMetaValue, toArray, findElement, removeElement, insertAfter } from "../helpers/index";
5
6class DirectUploadController {
7  constructor(source, file) {
8    this.directUpload = this.createDirectUpload(file, source.url);
9    this.source = source;
10    this.file = file;
11  }
12
13  start() {
14    this.file.controller = this;
15    this.hiddenInput = this.createHiddenInput();
16    this.directUpload.create((error, attributes) => {
17      if (error) {
18        removeElement(this.hiddenInput);
19        this.emitDropzoneError(error);
20      } else {
21        this.hiddenInput.value = attributes.signed_id;
22        this.emitDropzoneSuccess();
23      }
24    });
25  }
26
27  createHiddenInput() {
28    const input = document.createElement("input");
29    input.type = "hidden";
30    input.name = this.source.inputTarget.name;
31    insertAfter(input, this.source.inputTarget);
32    return input;
33  }
34
35  directUploadWillStoreFileWithXHR(xhr) {
36    this.bindProgressEvent(xhr);
37    this.emitDropzoneUploading();
38  }
39
40  bindProgressEvent(xhr) {
41    this.xhr = xhr;
42    this.xhr.upload.addEventListener("progress", event =>
43      this.uploadRequestDidProgress(event)
44    );
45  }
46
47  uploadRequestDidProgress(event) {
48    const element = this.source.element;
49    const progress = (event.loaded / event.total) * 100;
50    findElement(
51      this.file.previewTemplate,
52      ".dz-upload"
53    ).style.width = `${progress}%`;
54  }
55
56  emitDropzoneUploading() {
57    this.file.status = Dropzone.UPLOADING;
58    this.source.dropZone.emit("processing", this.file);
59  }
60
61  emitDropzoneError(error) {
62    this.file.status = Dropzone.ERROR;
63    this.source.dropZone.emit("error", this.file, error);
64    this.source.dropZone.emit("complete", this.file);
65  }
66
67  emitDropzoneSuccess() {
68    this.file.status = Dropzone.SUCCESS;
69    this.source.dropZone.emit("success", this.file);
70    this.source.dropZone.emit("complete", this.file);
71  }
72
73  createDirectUpload(file, url) {
74    return new DirectUpload(file, url, this);
75  }
76}
77
78export default class extends Controller {
79  static targets = ["input"];
80
81  connect() {
82    // Todo : Find a way to execute this after the translation have been loaded without settimeout
83    setTimeout(() => {
84      this.dropZone = this.createDropZone();
85      this.hideFileInput();
86      this.bindEvents();
87      Dropzone.autoDiscover = false; // necessary quirk for Dropzone error in console
88
89      this.importExistingFiles();
90    }, 500);
91  }
92
93  // Private
94  hideFileInput() {
95    this.inputTarget.disabled = true;
96    this.inputTarget.style.display = "none";
97  }
98
99  bindEvents() {
100    this.dropZone.on("addedfile", file => {
101      setTimeout(() => {
102        file.accepted && this.createDirectUploadController(file).start();
103      }, 500);
104    });
105
106    this.dropZone.on("removedfile", file => {
107      file.controller && removeElement(file.controller.hiddenInput);
108    });
109
110    this.dropZone.on("canceled", file => {
111      file.controller && file.controller.xhr.abort();
112    });
113  }
114
115  get headers() {
116    return { "X-CSRF-Token": getMetaValue("csrf-token") };
117  }
118
119  get url() {
120    return this.inputTarget.getAttribute("data-direct-upload-url");
121  }
122
123  get maxFiles() {
124    return this.data.get("maxFiles") || 1;
125  }
126
127  get maxFileSize() {
128    return this.data.get("maxFileSize") || 256;
129  }
130
131  get acceptedFiles() {
132    return this.data.get("acceptedFiles");
133  }
134
135  get addRemoveLinks() {
136    return this.data.get("addRemoveLinks") || true;
137  }
138
139  createDirectUploadController(file) {
140    return new DirectUploadController(this, file);
141  }
142
143  createDropZone() {
144    return new Dropzone(this.element, {
145      url: this.url,
146      headers: this.headers,
147      maxFiles: this.maxFiles,
148      maxFilesize: this.maxFileSize,
149      acceptedFiles: this.acceptedFiles,
150      addRemoveLinks: this.addRemoveLinks,
151      autoQueue: false,
152      dictFileTooBig: i18n.t("uploader.filetoobig"),
153      dictInvalidFileType: i18n.t("uploader.invalidfiletype"),
154      dictCancelUpload: i18n.t("uploader.cancelupload"),
155      dictRemoveFile: i18n.t("uploader.removefile"),
156      dictMaxFilesExceeded: i18n.t("uploader.maxfilesexceeded"),
157      dictDefaultMessage: i18n.t("uploader.defaultmessage"),
158    });
159  }
160
161  importExistingFiles() {
162    jsonMedia.forEach((image) => {
163      let input = Object.assign(document.createElement("input"), {type: "hidden", name: "room[images][]", value: image.id});
164
165      this.inputTarget.insertAdjacentElement("afterend", input);
166      image.controller = { hiddenInput: input };
167
168      this.dropZone.displayExistingFile(image, image.name);
169    });
170  }
171};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.