commit
432d58f0d0
5 changed files with 180 additions and 2 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
// Include runtime-polyfills for older browsers.
|
||||||
|
// Due to .babelrc's 'useBuiltIns', only polyfills actually
|
||||||
|
// required by the browsers we support will be included.
|
||||||
|
import 'babel-polyfill';
|
||||||
|
|
||||||
// This file is copied from mailjet. We serve here a copy of it ourselves
|
// This file is copied from mailjet. We serve here a copy of it ourselves
|
||||||
// to avoid loading javascript files from other domains on the frontpage.
|
// to avoid loading javascript files from other domains on the frontpage.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
import { DirectUpload } from 'activestorage';
|
||||||
|
import { dispatchEvent } from './helpers';
|
||||||
|
|
||||||
|
export class DirectUploadController {
|
||||||
|
constructor(input, file) {
|
||||||
|
this.input = input;
|
||||||
|
this.file = file;
|
||||||
|
this.directUpload = new DirectUpload(this.file, this.url, this);
|
||||||
|
this.dispatch('initialize');
|
||||||
|
}
|
||||||
|
|
||||||
|
start(callback) {
|
||||||
|
const hiddenInput = document.createElement('input');
|
||||||
|
hiddenInput.type = 'hidden';
|
||||||
|
hiddenInput.name = this.input.name;
|
||||||
|
this.input.insertAdjacentElement('beforebegin', hiddenInput);
|
||||||
|
|
||||||
|
this.dispatch('start');
|
||||||
|
|
||||||
|
this.directUpload.create((error, attributes) => {
|
||||||
|
if (error) {
|
||||||
|
hiddenInput.parentNode.removeChild(hiddenInput);
|
||||||
|
this.dispatchError(error);
|
||||||
|
} else {
|
||||||
|
hiddenInput.value = attributes.signed_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dispatch('end');
|
||||||
|
callback(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadRequestDidProgress(event) {
|
||||||
|
const progress = (event.loaded / event.total) * 100;
|
||||||
|
if (progress) {
|
||||||
|
this.dispatch('progress', { progress });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get url() {
|
||||||
|
return this.input.getAttribute('data-direct-upload-url');
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(name, detail = {}) {
|
||||||
|
detail.file = this.file;
|
||||||
|
detail.id = this.directUpload.id;
|
||||||
|
return dispatchEvent(this.input, `direct-upload:${name}`, { detail });
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchError(error) {
|
||||||
|
const event = this.dispatch('error', { error });
|
||||||
|
if (!event.defaultPrevented) {
|
||||||
|
alert(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DirectUpload delegate
|
||||||
|
|
||||||
|
directUploadWillCreateBlobWithXHR(xhr) {
|
||||||
|
this.dispatch('before-blob-request', { xhr });
|
||||||
|
}
|
||||||
|
|
||||||
|
directUploadWillStoreFileWithXHR(xhr) {
|
||||||
|
this.dispatch('before-storage-request', { xhr });
|
||||||
|
xhr.upload.addEventListener('progress', event =>
|
||||||
|
this.uploadRequestDidProgress(event)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
import { DirectUploadController } from './direct_upload_controller';
|
||||||
|
import { findElements, dispatchEvent, toArray } from './helpers';
|
||||||
|
|
||||||
|
const inputSelector =
|
||||||
|
'input[type=file][data-direct-upload-url]:not([disabled])';
|
||||||
|
|
||||||
|
export class DirectUploadsController {
|
||||||
|
constructor(form) {
|
||||||
|
this.form = form;
|
||||||
|
this.inputs = findElements(form, inputSelector).filter(
|
||||||
|
input => input.files.length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
start(callback) {
|
||||||
|
const controllers = this.createDirectUploadControllers();
|
||||||
|
|
||||||
|
const startNextController = () => {
|
||||||
|
const controller = controllers.shift();
|
||||||
|
if (controller) {
|
||||||
|
controller.start(error => {
|
||||||
|
if (error) {
|
||||||
|
callback(error);
|
||||||
|
this.dispatch('end');
|
||||||
|
} else {
|
||||||
|
startNextController();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
this.dispatch('end');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.dispatch('start');
|
||||||
|
startNextController();
|
||||||
|
}
|
||||||
|
|
||||||
|
createDirectUploadControllers() {
|
||||||
|
const controllers = [];
|
||||||
|
this.inputs.forEach(input => {
|
||||||
|
toArray(input.files).forEach(file => {
|
||||||
|
const controller = new DirectUploadController(input, file);
|
||||||
|
controllers.push(controller);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return controllers;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(name, detail = {}) {
|
||||||
|
return dispatchEvent(this.form, `direct-uploads:${name}`, { detail });
|
||||||
|
}
|
||||||
|
}
|
51
app/javascript/shared/activestorage/helpers.js
Normal file
51
app/javascript/shared/activestorage/helpers.js
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
export function getMetaValue(name) {
|
||||||
|
const element = findElement(document.head, `meta[name="${name}"]`);
|
||||||
|
if (element) {
|
||||||
|
return element.getAttribute('content');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findElements(root, selector) {
|
||||||
|
if (typeof root == 'string') {
|
||||||
|
selector = root;
|
||||||
|
root = document;
|
||||||
|
}
|
||||||
|
const elements = root.querySelectorAll(selector);
|
||||||
|
return toArray(elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findElement(root, selector) {
|
||||||
|
if (typeof root == 'string') {
|
||||||
|
selector = root;
|
||||||
|
root = document;
|
||||||
|
}
|
||||||
|
return root.querySelector(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dispatchEvent(element, type, eventInit = {}) {
|
||||||
|
const { disabled } = element;
|
||||||
|
const { bubbles, cancelable, detail } = eventInit;
|
||||||
|
const event = document.createEvent('Event');
|
||||||
|
|
||||||
|
event.initEvent(type, bubbles || true, cancelable || true);
|
||||||
|
event.detail = detail || {};
|
||||||
|
|
||||||
|
try {
|
||||||
|
element.disabled = false;
|
||||||
|
element.dispatchEvent(event);
|
||||||
|
} finally {
|
||||||
|
element.disabled = disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toArray(value) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value;
|
||||||
|
} else if (Array.from) {
|
||||||
|
return Array.from(value);
|
||||||
|
} else {
|
||||||
|
return [].slice.call(value);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import { DirectUploadsController } from 'activestorage/src/direct_uploads_controller';
|
import { DirectUploadsController } from './direct_uploads_controller';
|
||||||
import { findElement } from 'activestorage/src/helpers';
|
import { findElement } from './helpers';
|
||||||
import './progress';
|
import './progress';
|
||||||
|
|
||||||
// This is a patched copy of https://github.com/rails/rails/blob/master/activestorage/app/javascript/activestorage/ujs.js
|
// This is a patched copy of https://github.com/rails/rails/blob/master/activestorage/app/javascript/activestorage/ujs.js
|
||||||
|
|
Loading…
Add table
Reference in a new issue