diff --git a/actiontext/app/assets/javascripts/action_text.js b/actiontext/app/assets/javascripts/action_text.js index 0e1ad6fa57..792a2c1fc3 100644 --- a/actiontext/app/assets/javascripts/action_text.js +++ b/actiontext/app/assets/javascripts/action_text.js @@ -5,18 +5,16 @@ var activestorage = {exports: {}}; (function (module, exports) { (function(global, factory) { factory(exports) ; -})(commonjsGlobal, function(exports) { - function createCommonjsModule(fn, module) { - return module = { - exports: {} - }, fn(module, module.exports), module.exports; - } - var sparkMd5 = createCommonjsModule(function(module, exports) { +})(commonjsGlobal, (function(exports) { + var sparkMd5 = { + exports: {} + }; + (function(module, exports) { (function(factory) { { module.exports = factory(); } - })(function(undefined$1) { + })((function(undefined$1) { var hex_chr = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" ]; function md5cycle(x, k) { var a = x[0], b = x[1], c = x[2], d = x[3]; @@ -331,7 +329,7 @@ var activestorage = {exports: {}}; return { buff: this._buff, length: this._length, - hash: this._hash + hash: this._hash.slice() }; }; SparkMD5.prototype.setState = function(state) { @@ -416,94 +414,55 @@ var activestorage = {exports: {}}; return raw ? hexToBinaryString(ret) : ret; }; return SparkMD5; - }); - }); - var classCallCheck = function(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); + })); + })(sparkMd5); + var SparkMD5 = sparkMd5.exports; + const fileSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice; + class FileChecksum { + static create(file, callback) { + const instance = new FileChecksum(file); + instance.create(callback); } - }; - var createClass = function() { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - return function(Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; - }(); - var fileSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice; - var FileChecksum = function() { - createClass(FileChecksum, null, [ { - key: "create", - value: function create(file, callback) { - var instance = new FileChecksum(file); - instance.create(callback); - } - } ]); - function FileChecksum(file) { - classCallCheck(this, FileChecksum); + constructor(file) { this.file = file; this.chunkSize = 2097152; this.chunkCount = Math.ceil(this.file.size / this.chunkSize); this.chunkIndex = 0; } - createClass(FileChecksum, [ { - key: "create", - value: function create(callback) { - var _this = this; - this.callback = callback; - this.md5Buffer = new sparkMd5.ArrayBuffer(); - this.fileReader = new FileReader(); - this.fileReader.addEventListener("load", function(event) { - return _this.fileReaderDidLoad(event); - }); - this.fileReader.addEventListener("error", function(event) { - return _this.fileReaderDidError(event); - }); - this.readNextChunk(); + create(callback) { + this.callback = callback; + this.md5Buffer = new SparkMD5.ArrayBuffer; + this.fileReader = new FileReader; + this.fileReader.addEventListener("load", (event => this.fileReaderDidLoad(event))); + this.fileReader.addEventListener("error", (event => this.fileReaderDidError(event))); + this.readNextChunk(); + } + fileReaderDidLoad(event) { + this.md5Buffer.append(event.target.result); + if (!this.readNextChunk()) { + const binaryDigest = this.md5Buffer.end(true); + const base64digest = btoa(binaryDigest); + this.callback(null, base64digest); } - }, { - key: "fileReaderDidLoad", - value: function fileReaderDidLoad(event) { - this.md5Buffer.append(event.target.result); - if (!this.readNextChunk()) { - var binaryDigest = this.md5Buffer.end(true); - var base64digest = btoa(binaryDigest); - this.callback(null, base64digest); - } + } + fileReaderDidError(event) { + this.callback(`Error reading ${this.file.name}`); + } + readNextChunk() { + if (this.chunkIndex < this.chunkCount || this.chunkIndex == 0 && this.chunkCount == 0) { + const start = this.chunkIndex * this.chunkSize; + const end = Math.min(start + this.chunkSize, this.file.size); + const bytes = fileSlice.call(this.file, start, end); + this.fileReader.readAsArrayBuffer(bytes); + this.chunkIndex++; + return true; + } else { + return false; } - }, { - key: "fileReaderDidError", - value: function fileReaderDidError(event) { - this.callback("Error reading " + this.file.name); - } - }, { - key: "readNextChunk", - value: function readNextChunk() { - if (this.chunkIndex < this.chunkCount || this.chunkIndex == 0 && this.chunkCount == 0) { - var start = this.chunkIndex * this.chunkSize; - var end = Math.min(start + this.chunkSize, this.file.size); - var bytes = fileSlice.call(this.file, start, end); - this.fileReader.readAsArrayBuffer(bytes); - this.chunkIndex++; - return true; - } else { - return false; - } - } - } ]); - return FileChecksum; - }(); + } + } function getMetaValue(name) { - var element = findElement(document.head, 'meta[name="' + name + '"]'); + const element = findElement(document.head, `meta[name="${name}"]`); if (element) { return element.getAttribute("content"); } @@ -513,8 +472,8 @@ var activestorage = {exports: {}}; selector = root; root = document; } - var elements = root.querySelectorAll(selector); - return toArray$1(elements); + const elements = root.querySelectorAll(selector); + return toArray(elements); } function findElement(root, selector) { if (typeof root == "string") { @@ -523,11 +482,10 @@ var activestorage = {exports: {}}; } return root.querySelector(selector); } - function dispatchEvent(element, type) { - var eventInit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - var disabled = element.disabled; - var bubbles = eventInit.bubbles, cancelable = eventInit.cancelable, detail = eventInit.detail; - var event = document.createEvent("Event"); + function dispatchEvent(element, type, eventInit = {}) { + const {disabled: disabled} = element; + const {bubbles: bubbles, cancelable: cancelable, detail: detail} = eventInit; + const event = document.createEvent("Event"); event.initEvent(type, bubbles || true, cancelable || true); event.detail = detail || {}; try { @@ -538,7 +496,7 @@ var activestorage = {exports: {}}; } return event; } - function toArray$1(value) { + function toArray(value) { if (Array.isArray(value)) { return value; } else if (Array.from) { @@ -547,10 +505,8 @@ var activestorage = {exports: {}}; return [].slice.call(value); } } - var BlobRecord = function() { - function BlobRecord(file, checksum, url) { - var _this = this; - classCallCheck(this, BlobRecord); + class BlobRecord { + constructor(file, checksum, url) { this.file = file; this.attributes = { filename: file.name, @@ -558,312 +514,236 @@ var activestorage = {exports: {}}; byte_size: file.size, checksum: checksum }; - this.xhr = new XMLHttpRequest(); + this.xhr = new XMLHttpRequest; this.xhr.open("POST", url, true); this.xhr.responseType = "json"; this.xhr.setRequestHeader("Content-Type", "application/json"); this.xhr.setRequestHeader("Accept", "application/json"); this.xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); - var csrfToken = getMetaValue("csrf-token"); + const csrfToken = getMetaValue("csrf-token"); if (csrfToken != undefined) { this.xhr.setRequestHeader("X-CSRF-Token", csrfToken); } - this.xhr.addEventListener("load", function(event) { - return _this.requestDidLoad(event); - }); - this.xhr.addEventListener("error", function(event) { - return _this.requestDidError(event); - }); + this.xhr.addEventListener("load", (event => this.requestDidLoad(event))); + this.xhr.addEventListener("error", (event => this.requestDidError(event))); } - createClass(BlobRecord, [ { - key: "create", - value: function create(callback) { - this.callback = callback; - this.xhr.send(JSON.stringify({ - blob: this.attributes - })); + get status() { + return this.xhr.status; + } + get response() { + const {responseType: responseType, response: response} = this.xhr; + if (responseType == "json") { + return response; + } else { + return JSON.parse(response); } - }, { - key: "requestDidLoad", - value: function requestDidLoad(event) { - if (this.status >= 200 && this.status < 300) { - var response = this.response; - var direct_upload = response.direct_upload; - delete response.direct_upload; - this.attributes = response; - this.directUploadData = direct_upload; - this.callback(null, this.toJSON()); - } else { - this.requestDidError(event); - } + } + create(callback) { + this.callback = callback; + this.xhr.send(JSON.stringify({ + blob: this.attributes + })); + } + requestDidLoad(event) { + if (this.status >= 200 && this.status < 300) { + const {response: response} = this; + const {direct_upload: direct_upload} = response; + delete response.direct_upload; + this.attributes = response; + this.directUploadData = direct_upload; + this.callback(null, this.toJSON()); + } else { + this.requestDidError(event); } - }, { - key: "requestDidError", - value: function requestDidError(event) { - this.callback('Error creating Blob for "' + this.file.name + '". Status: ' + this.status); + } + requestDidError(event) { + this.callback(`Error creating Blob for "${this.file.name}". Status: ${this.status}`); + } + toJSON() { + const result = {}; + for (const key in this.attributes) { + result[key] = this.attributes[key]; } - }, { - key: "toJSON", - value: function toJSON() { - var result = {}; - for (var key in this.attributes) { - result[key] = this.attributes[key]; - } - return result; - } - }, { - key: "status", - get: function get$$1() { - return this.xhr.status; - } - }, { - key: "response", - get: function get$$1() { - var _xhr = this.xhr, responseType = _xhr.responseType, response = _xhr.response; - if (responseType == "json") { - return response; - } else { - return JSON.parse(response); - } - } - } ]); - return BlobRecord; - }(); - var BlobUpload = function() { - function BlobUpload(blob) { - var _this = this; - classCallCheck(this, BlobUpload); + return result; + } + } + class BlobUpload { + constructor(blob) { this.blob = blob; this.file = blob.file; - var _blob$directUploadDat = blob.directUploadData, url = _blob$directUploadDat.url, headers = _blob$directUploadDat.headers; - this.xhr = new XMLHttpRequest(); + const {url: url, headers: headers} = blob.directUploadData; + this.xhr = new XMLHttpRequest; this.xhr.open("PUT", url, true); this.xhr.responseType = "text"; - for (var key in headers) { + for (const key in headers) { this.xhr.setRequestHeader(key, headers[key]); } - this.xhr.addEventListener("load", function(event) { - return _this.requestDidLoad(event); - }); - this.xhr.addEventListener("error", function(event) { - return _this.requestDidError(event); - }); + this.xhr.addEventListener("load", (event => this.requestDidLoad(event))); + this.xhr.addEventListener("error", (event => this.requestDidError(event))); } - createClass(BlobUpload, [ { - key: "create", - value: function create(callback) { - this.callback = callback; - this.xhr.send(this.file.slice()); + create(callback) { + this.callback = callback; + this.xhr.send(this.file.slice()); + } + requestDidLoad(event) { + const {status: status, response: response} = this.xhr; + if (status >= 200 && status < 300) { + this.callback(null, response); + } else { + this.requestDidError(event); } - }, { - key: "requestDidLoad", - value: function requestDidLoad(event) { - var _xhr = this.xhr, status = _xhr.status, response = _xhr.response; - if (status >= 200 && status < 300) { - this.callback(null, response); - } else { - this.requestDidError(event); - } - } - }, { - key: "requestDidError", - value: function requestDidError(event) { - this.callback('Error storing "' + this.file.name + '". Status: ' + this.xhr.status); - } - } ]); - return BlobUpload; - }(); - var id = 0; - var DirectUpload = function() { - function DirectUpload(file, url, delegate) { - classCallCheck(this, DirectUpload); + } + requestDidError(event) { + this.callback(`Error storing "${this.file.name}". Status: ${this.xhr.status}`); + } + } + let id = 0; + class DirectUpload { + constructor(file, url, delegate) { this.id = ++id; this.file = file; this.url = url; this.delegate = delegate; } - createClass(DirectUpload, [ { - key: "create", - value: function create(callback) { - var _this = this; - FileChecksum.create(this.file, function(error, checksum) { + create(callback) { + FileChecksum.create(this.file, ((error, checksum) => { + if (error) { + callback(error); + return; + } + const blob = new BlobRecord(this.file, checksum, this.url); + notify(this.delegate, "directUploadWillCreateBlobWithXHR", blob.xhr); + blob.create((error => { if (error) { callback(error); - return; + } else { + const upload = new BlobUpload(blob); + notify(this.delegate, "directUploadWillStoreFileWithXHR", upload.xhr); + upload.create((error => { + if (error) { + callback(error); + } else { + callback(null, blob.toJSON()); + } + })); } - var blob = new BlobRecord(_this.file, checksum, _this.url); - notify(_this.delegate, "directUploadWillCreateBlobWithXHR", blob.xhr); - blob.create(function(error) { - if (error) { - callback(error); - } else { - var upload = new BlobUpload(blob); - notify(_this.delegate, "directUploadWillStoreFileWithXHR", upload.xhr); - upload.create(function(error) { - if (error) { - callback(error); - } else { - callback(null, blob.toJSON()); - } - }); - } - }); - }); - } - } ]); - return DirectUpload; - }(); - function notify(object, methodName) { - if (object && typeof object[methodName] == "function") { - for (var _len = arguments.length, messages = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { - messages[_key - 2] = arguments[_key]; - } - return object[methodName].apply(object, messages); + })); + })); } } - var DirectUploadController = function() { - function DirectUploadController(input, file) { - classCallCheck(this, DirectUploadController); + function notify(object, methodName, ...messages) { + if (object && typeof object[methodName] == "function") { + return object[methodName](...messages); + } + } + class DirectUploadController { + constructor(input, file) { this.input = input; this.file = file; this.directUpload = new DirectUpload(this.file, this.url, this); this.dispatch("initialize"); } - createClass(DirectUploadController, [ { - key: "start", - value: function start(callback) { - var _this = this; - var hiddenInput = document.createElement("input"); - hiddenInput.type = "hidden"; - hiddenInput.name = this.input.name; - this.input.insertAdjacentElement("beforebegin", hiddenInput); - this.dispatch("start"); - this.directUpload.create(function(error, attributes) { - if (error) { - hiddenInput.parentNode.removeChild(hiddenInput); - _this.dispatchError(error); - } else { - hiddenInput.value = attributes.signed_id; - } - _this.dispatch("end"); - callback(error); - }); - } - }, { - key: "uploadRequestDidProgress", - value: function uploadRequestDidProgress(event) { - var progress = event.loaded / event.total * 100; - if (progress) { - this.dispatch("progress", { - progress: progress - }); + 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; } - } - }, { - key: "dispatch", - value: function dispatch(name) { - var detail = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - detail.file = this.file; - detail.id = this.directUpload.id; - return dispatchEvent(this.input, "direct-upload:" + name, { - detail: detail + this.dispatch("end"); + callback(error); + })); + } + uploadRequestDidProgress(event) { + const progress = event.loaded / event.total * 100; + if (progress) { + this.dispatch("progress", { + progress: progress }); } - }, { - key: "dispatchError", - value: function dispatchError(error) { - var event = this.dispatch("error", { - error: error - }); - if (!event.defaultPrevented) { - alert(error); - } - } - }, { - key: "directUploadWillCreateBlobWithXHR", - value: function directUploadWillCreateBlobWithXHR(xhr) { - this.dispatch("before-blob-request", { - xhr: xhr - }); - } - }, { - key: "directUploadWillStoreFileWithXHR", - value: function directUploadWillStoreFileWithXHR(xhr) { - var _this2 = this; - this.dispatch("before-storage-request", { - xhr: xhr - }); - xhr.upload.addEventListener("progress", function(event) { - return _this2.uploadRequestDidProgress(event); - }); - } - }, { - key: "url", - get: function get$$1() { - return this.input.getAttribute("data-direct-upload-url"); - } - } ]); - return DirectUploadController; - }(); - var inputSelector = "input[type=file][data-direct-upload-url]:not([disabled])"; - var DirectUploadsController = function() { - function DirectUploadsController(form) { - classCallCheck(this, DirectUploadsController); - this.form = form; - this.inputs = findElements(form, inputSelector).filter(function(input) { - return input.files.length; + } + 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: detail }); } - createClass(DirectUploadsController, [ { - key: "start", - value: function start(callback) { - var _this = this; - var controllers = this.createDirectUploadControllers(); - var startNextController = function startNextController() { - var controller = controllers.shift(); - if (controller) { - controller.start(function(error) { - if (error) { - callback(error); - _this.dispatch("end"); - } else { - startNextController(); - } - }); - } else { - callback(); - _this.dispatch("end"); - } - }; - this.dispatch("start"); - startNextController(); + dispatchError(error) { + const event = this.dispatch("error", { + error: error + }); + if (!event.defaultPrevented) { + alert(error); } - }, { - key: "createDirectUploadControllers", - value: function createDirectUploadControllers() { - var controllers = []; - this.inputs.forEach(function(input) { - toArray$1(input.files).forEach(function(file) { - var controller = new DirectUploadController(input, file); - controllers.push(controller); - }); - }); - return controllers; - } - }, { - key: "dispatch", - value: function dispatch(name) { - var detail = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - return dispatchEvent(this.form, "direct-uploads:" + name, { - detail: detail - }); - } - } ]); - return DirectUploadsController; - }(); - var processingAttribute = "data-direct-uploads-processing"; - var submitButtonsByForm = new WeakMap(); - var started = false; + } + directUploadWillCreateBlobWithXHR(xhr) { + this.dispatch("before-blob-request", { + xhr: xhr + }); + } + directUploadWillStoreFileWithXHR(xhr) { + this.dispatch("before-storage-request", { + xhr: xhr + }); + xhr.upload.addEventListener("progress", (event => this.uploadRequestDidProgress(event))); + } + } + const inputSelector = "input[type=file][data-direct-upload-url]:not([disabled])"; + 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: detail + }); + } + } + const processingAttribute = "data-direct-uploads-processing"; + const submitButtonsByForm = new WeakMap; + let started = false; function start() { if (!started) { started = true; @@ -873,7 +753,7 @@ var activestorage = {exports: {}}; } } function didClick(event) { - var target = event.target; + const {target: target} = event; if ((target.tagName == "INPUT" || target.tagName == "BUTTON") && target.type == "submit" && target.form) { submitButtonsByForm.set(target.form, target); } @@ -887,31 +767,31 @@ var activestorage = {exports: {}}; } } function handleFormSubmissionEvent(event) { - var form = event.target; + const form = event.target; if (form.hasAttribute(processingAttribute)) { event.preventDefault(); return; } - var controller = new DirectUploadsController(form); - var inputs = controller.inputs; + const controller = new DirectUploadsController(form); + const {inputs: inputs} = controller; if (inputs.length) { event.preventDefault(); form.setAttribute(processingAttribute, ""); inputs.forEach(disable); - controller.start(function(error) { + controller.start((error => { form.removeAttribute(processingAttribute); if (error) { inputs.forEach(enable); } else { submitForm(form); } - }); + })); } } function submitForm(form) { - var button = submitButtonsByForm.get(form) || findElement(form, "input[type=submit], button[type=submit]"); + let button = submitButtonsByForm.get(form) || findElement(form, "input[type=submit], button[type=submit]"); if (button) { - var _button = button, disabled = _button.disabled; + const {disabled: disabled} = button; button.disabled = false; button.focus(); button.click(); @@ -938,12 +818,12 @@ var activestorage = {exports: {}}; } } setTimeout(autostart, 1); - exports.start = start; exports.DirectUpload = DirectUpload; + exports.start = start; Object.defineProperty(exports, "__esModule", { value: true }); -}); +})); }(activestorage, activestorage.exports)); class AttachmentUpload { diff --git a/activestorage/README.md b/activestorage/README.md index 9ee0c92b5f..0ded69c368 100644 --- a/activestorage/README.md +++ b/activestorage/README.md @@ -88,8 +88,7 @@ class MessagesController < ApplicationController end def create - message = Message.create! params.require(:message).permit(:title, :content) - message.images.attach(params[:message][:images]) + message = Message.create! params.require(:message).permit(:title, :content, images: []) redirect_to message end @@ -143,8 +142,26 @@ Active Storage, with its included JavaScript library, supports uploading directl ### Direct upload installation -1. Include `activestorage.js` in your application's JavaScript bundle. +1. Include the Active Storage JavaScript in your application's JavaScript bundle or reference it directly. + Requiring directly without bundling through the asset pipeline in the application html with autostart: + ```html + <%= javascript_include_tag "activestorage" %> + ``` + Requiring via importmap (as used by Stimulus) without bundling through the asset pipeline in the application html without autostart as ESM: + ```js + { + "imports": { + "@rails/activestorage": "<%= asset_path "activestorage.esm" %>" + } + } + ``` + ```html + + ``` Using the asset pipeline: ```js //= require activestorage diff --git a/activestorage/app/assets/javascripts/activestorage.esm.js b/activestorage/app/assets/javascripts/activestorage.esm.js new file mode 100644 index 0000000000..87ac2553f9 --- /dev/null +++ b/activestorage/app/assets/javascripts/activestorage.esm.js @@ -0,0 +1,844 @@ +var sparkMd5 = { + exports: {} +}; + +(function(module, exports) { + (function(factory) { + { + module.exports = factory(); + } + })((function(undefined$1) { + var hex_chr = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" ]; + function md5cycle(x, k) { + var a = x[0], b = x[1], c = x[2], d = x[3]; + a += (b & c | ~b & d) + k[0] - 680876936 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[1] - 389564586 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[2] + 606105819 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[3] - 1044525330 | 0; + b = (b << 22 | b >>> 10) + c | 0; + a += (b & c | ~b & d) + k[4] - 176418897 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[5] + 1200080426 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[6] - 1473231341 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[7] - 45705983 | 0; + b = (b << 22 | b >>> 10) + c | 0; + a += (b & c | ~b & d) + k[8] + 1770035416 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[9] - 1958414417 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[10] - 42063 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[11] - 1990404162 | 0; + b = (b << 22 | b >>> 10) + c | 0; + a += (b & c | ~b & d) + k[12] + 1804603682 | 0; + a = (a << 7 | a >>> 25) + b | 0; + d += (a & b | ~a & c) + k[13] - 40341101 | 0; + d = (d << 12 | d >>> 20) + a | 0; + c += (d & a | ~d & b) + k[14] - 1502002290 | 0; + c = (c << 17 | c >>> 15) + d | 0; + b += (c & d | ~c & a) + k[15] + 1236535329 | 0; + b = (b << 22 | b >>> 10) + c | 0; + a += (b & d | c & ~d) + k[1] - 165796510 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[6] - 1069501632 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[11] + 643717713 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[0] - 373897302 | 0; + b = (b << 20 | b >>> 12) + c | 0; + a += (b & d | c & ~d) + k[5] - 701558691 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[10] + 38016083 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[15] - 660478335 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[4] - 405537848 | 0; + b = (b << 20 | b >>> 12) + c | 0; + a += (b & d | c & ~d) + k[9] + 568446438 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[14] - 1019803690 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[3] - 187363961 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[8] + 1163531501 | 0; + b = (b << 20 | b >>> 12) + c | 0; + a += (b & d | c & ~d) + k[13] - 1444681467 | 0; + a = (a << 5 | a >>> 27) + b | 0; + d += (a & c | b & ~c) + k[2] - 51403784 | 0; + d = (d << 9 | d >>> 23) + a | 0; + c += (d & b | a & ~b) + k[7] + 1735328473 | 0; + c = (c << 14 | c >>> 18) + d | 0; + b += (c & a | d & ~a) + k[12] - 1926607734 | 0; + b = (b << 20 | b >>> 12) + c | 0; + a += (b ^ c ^ d) + k[5] - 378558 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[8] - 2022574463 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[11] + 1839030562 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[14] - 35309556 | 0; + b = (b << 23 | b >>> 9) + c | 0; + a += (b ^ c ^ d) + k[1] - 1530992060 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[4] + 1272893353 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[7] - 155497632 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[10] - 1094730640 | 0; + b = (b << 23 | b >>> 9) + c | 0; + a += (b ^ c ^ d) + k[13] + 681279174 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[0] - 358537222 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[3] - 722521979 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[6] + 76029189 | 0; + b = (b << 23 | b >>> 9) + c | 0; + a += (b ^ c ^ d) + k[9] - 640364487 | 0; + a = (a << 4 | a >>> 28) + b | 0; + d += (a ^ b ^ c) + k[12] - 421815835 | 0; + d = (d << 11 | d >>> 21) + a | 0; + c += (d ^ a ^ b) + k[15] + 530742520 | 0; + c = (c << 16 | c >>> 16) + d | 0; + b += (c ^ d ^ a) + k[2] - 995338651 | 0; + b = (b << 23 | b >>> 9) + c | 0; + a += (c ^ (b | ~d)) + k[0] - 198630844 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[5] - 57434055 | 0; + b = (b << 21 | b >>> 11) + c | 0; + a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[10] - 1051523 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0; + b = (b << 21 | b >>> 11) + c | 0; + a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[15] - 30611744 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0; + b = (b << 21 | b >>> 11) + c | 0; + a += (c ^ (b | ~d)) + k[4] - 145523070 | 0; + a = (a << 6 | a >>> 26) + b | 0; + d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0; + d = (d << 10 | d >>> 22) + a | 0; + c += (a ^ (d | ~b)) + k[2] + 718787259 | 0; + c = (c << 15 | c >>> 17) + d | 0; + b += (d ^ (c | ~a)) + k[9] - 343485551 | 0; + b = (b << 21 | b >>> 11) + c | 0; + x[0] = a + x[0] | 0; + x[1] = b + x[1] | 0; + x[2] = c + x[2] | 0; + x[3] = d + x[3] | 0; + } + function md5blk(s) { + var md5blks = [], i; + for (i = 0; i < 64; i += 4) { + md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24); + } + return md5blks; + } + function md5blk_array(a) { + var md5blks = [], i; + for (i = 0; i < 64; i += 4) { + md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24); + } + return md5blks; + } + function md51(s) { + var n = s.length, state = [ 1732584193, -271733879, -1732584194, 271733878 ], i, length, tail, tmp, lo, hi; + for (i = 64; i <= n; i += 64) { + md5cycle(state, md5blk(s.substring(i - 64, i))); + } + s = s.substring(i - 64); + length = s.length; + tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; + for (i = 0; i < length; i += 1) { + tail[i >> 2] |= s.charCodeAt(i) << (i % 4 << 3); + } + tail[i >> 2] |= 128 << (i % 4 << 3); + if (i > 55) { + md5cycle(state, tail); + for (i = 0; i < 16; i += 1) { + tail[i] = 0; + } + } + tmp = n * 8; + tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/); + lo = parseInt(tmp[2], 16); + hi = parseInt(tmp[1], 16) || 0; + tail[14] = lo; + tail[15] = hi; + md5cycle(state, tail); + return state; + } + function md51_array(a) { + var n = a.length, state = [ 1732584193, -271733879, -1732584194, 271733878 ], i, length, tail, tmp, lo, hi; + for (i = 64; i <= n; i += 64) { + md5cycle(state, md5blk_array(a.subarray(i - 64, i))); + } + a = i - 64 < n ? a.subarray(i - 64) : new Uint8Array(0); + length = a.length; + tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; + for (i = 0; i < length; i += 1) { + tail[i >> 2] |= a[i] << (i % 4 << 3); + } + tail[i >> 2] |= 128 << (i % 4 << 3); + if (i > 55) { + md5cycle(state, tail); + for (i = 0; i < 16; i += 1) { + tail[i] = 0; + } + } + tmp = n * 8; + tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/); + lo = parseInt(tmp[2], 16); + hi = parseInt(tmp[1], 16) || 0; + tail[14] = lo; + tail[15] = hi; + md5cycle(state, tail); + return state; + } + function rhex(n) { + var s = "", j; + for (j = 0; j < 4; j += 1) { + s += hex_chr[n >> j * 8 + 4 & 15] + hex_chr[n >> j * 8 & 15]; + } + return s; + } + function hex(x) { + var i; + for (i = 0; i < x.length; i += 1) { + x[i] = rhex(x[i]); + } + return x.join(""); + } + if (hex(md51("hello")) !== "5d41402abc4b2a76b9719d911017c592") ; + if (typeof ArrayBuffer !== "undefined" && !ArrayBuffer.prototype.slice) { + (function() { + function clamp(val, length) { + val = val | 0 || 0; + if (val < 0) { + return Math.max(val + length, 0); + } + return Math.min(val, length); + } + ArrayBuffer.prototype.slice = function(from, to) { + var length = this.byteLength, begin = clamp(from, length), end = length, num, target, targetArray, sourceArray; + if (to !== undefined$1) { + end = clamp(to, length); + } + if (begin > end) { + return new ArrayBuffer(0); + } + num = end - begin; + target = new ArrayBuffer(num); + targetArray = new Uint8Array(target); + sourceArray = new Uint8Array(this, begin, num); + targetArray.set(sourceArray); + return target; + }; + })(); + } + function toUtf8(str) { + if (/[\u0080-\uFFFF]/.test(str)) { + str = unescape(encodeURIComponent(str)); + } + return str; + } + function utf8Str2ArrayBuffer(str, returnUInt8Array) { + var length = str.length, buff = new ArrayBuffer(length), arr = new Uint8Array(buff), i; + for (i = 0; i < length; i += 1) { + arr[i] = str.charCodeAt(i); + } + return returnUInt8Array ? arr : buff; + } + function arrayBuffer2Utf8Str(buff) { + return String.fromCharCode.apply(null, new Uint8Array(buff)); + } + function concatenateArrayBuffers(first, second, returnUInt8Array) { + var result = new Uint8Array(first.byteLength + second.byteLength); + result.set(new Uint8Array(first)); + result.set(new Uint8Array(second), first.byteLength); + return returnUInt8Array ? result : result.buffer; + } + function hexToBinaryString(hex) { + var bytes = [], length = hex.length, x; + for (x = 0; x < length - 1; x += 2) { + bytes.push(parseInt(hex.substr(x, 2), 16)); + } + return String.fromCharCode.apply(String, bytes); + } + function SparkMD5() { + this.reset(); + } + SparkMD5.prototype.append = function(str) { + this.appendBinary(toUtf8(str)); + return this; + }; + SparkMD5.prototype.appendBinary = function(contents) { + this._buff += contents; + this._length += contents.length; + var length = this._buff.length, i; + for (i = 64; i <= length; i += 64) { + md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i))); + } + this._buff = this._buff.substring(i - 64); + return this; + }; + SparkMD5.prototype.end = function(raw) { + var buff = this._buff, length = buff.length, i, tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], ret; + for (i = 0; i < length; i += 1) { + tail[i >> 2] |= buff.charCodeAt(i) << (i % 4 << 3); + } + this._finish(tail, length); + ret = hex(this._hash); + if (raw) { + ret = hexToBinaryString(ret); + } + this.reset(); + return ret; + }; + SparkMD5.prototype.reset = function() { + this._buff = ""; + this._length = 0; + this._hash = [ 1732584193, -271733879, -1732584194, 271733878 ]; + return this; + }; + SparkMD5.prototype.getState = function() { + return { + buff: this._buff, + length: this._length, + hash: this._hash.slice() + }; + }; + SparkMD5.prototype.setState = function(state) { + this._buff = state.buff; + this._length = state.length; + this._hash = state.hash; + return this; + }; + SparkMD5.prototype.destroy = function() { + delete this._hash; + delete this._buff; + delete this._length; + }; + SparkMD5.prototype._finish = function(tail, length) { + var i = length, tmp, lo, hi; + tail[i >> 2] |= 128 << (i % 4 << 3); + if (i > 55) { + md5cycle(this._hash, tail); + for (i = 0; i < 16; i += 1) { + tail[i] = 0; + } + } + tmp = this._length * 8; + tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/); + lo = parseInt(tmp[2], 16); + hi = parseInt(tmp[1], 16) || 0; + tail[14] = lo; + tail[15] = hi; + md5cycle(this._hash, tail); + }; + SparkMD5.hash = function(str, raw) { + return SparkMD5.hashBinary(toUtf8(str), raw); + }; + SparkMD5.hashBinary = function(content, raw) { + var hash = md51(content), ret = hex(hash); + return raw ? hexToBinaryString(ret) : ret; + }; + SparkMD5.ArrayBuffer = function() { + this.reset(); + }; + SparkMD5.ArrayBuffer.prototype.append = function(arr) { + var buff = concatenateArrayBuffers(this._buff.buffer, arr, true), length = buff.length, i; + this._length += arr.byteLength; + for (i = 64; i <= length; i += 64) { + md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i))); + } + this._buff = i - 64 < length ? new Uint8Array(buff.buffer.slice(i - 64)) : new Uint8Array(0); + return this; + }; + SparkMD5.ArrayBuffer.prototype.end = function(raw) { + var buff = this._buff, length = buff.length, tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], i, ret; + for (i = 0; i < length; i += 1) { + tail[i >> 2] |= buff[i] << (i % 4 << 3); + } + this._finish(tail, length); + ret = hex(this._hash); + if (raw) { + ret = hexToBinaryString(ret); + } + this.reset(); + return ret; + }; + SparkMD5.ArrayBuffer.prototype.reset = function() { + this._buff = new Uint8Array(0); + this._length = 0; + this._hash = [ 1732584193, -271733879, -1732584194, 271733878 ]; + return this; + }; + SparkMD5.ArrayBuffer.prototype.getState = function() { + var state = SparkMD5.prototype.getState.call(this); + state.buff = arrayBuffer2Utf8Str(state.buff); + return state; + }; + SparkMD5.ArrayBuffer.prototype.setState = function(state) { + state.buff = utf8Str2ArrayBuffer(state.buff, true); + return SparkMD5.prototype.setState.call(this, state); + }; + SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy; + SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish; + SparkMD5.ArrayBuffer.hash = function(arr, raw) { + var hash = md51_array(new Uint8Array(arr)), ret = hex(hash); + return raw ? hexToBinaryString(ret) : ret; + }; + return SparkMD5; + })); +})(sparkMd5); + +var SparkMD5 = sparkMd5.exports; + +const fileSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice; + +class FileChecksum { + static create(file, callback) { + const instance = new FileChecksum(file); + instance.create(callback); + } + constructor(file) { + this.file = file; + this.chunkSize = 2097152; + this.chunkCount = Math.ceil(this.file.size / this.chunkSize); + this.chunkIndex = 0; + } + create(callback) { + this.callback = callback; + this.md5Buffer = new SparkMD5.ArrayBuffer; + this.fileReader = new FileReader; + this.fileReader.addEventListener("load", (event => this.fileReaderDidLoad(event))); + this.fileReader.addEventListener("error", (event => this.fileReaderDidError(event))); + this.readNextChunk(); + } + fileReaderDidLoad(event) { + this.md5Buffer.append(event.target.result); + if (!this.readNextChunk()) { + const binaryDigest = this.md5Buffer.end(true); + const base64digest = btoa(binaryDigest); + this.callback(null, base64digest); + } + } + fileReaderDidError(event) { + this.callback(`Error reading ${this.file.name}`); + } + readNextChunk() { + if (this.chunkIndex < this.chunkCount || this.chunkIndex == 0 && this.chunkCount == 0) { + const start = this.chunkIndex * this.chunkSize; + const end = Math.min(start + this.chunkSize, this.file.size); + const bytes = fileSlice.call(this.file, start, end); + this.fileReader.readAsArrayBuffer(bytes); + this.chunkIndex++; + return true; + } else { + return false; + } + } +} + +function getMetaValue(name) { + const element = findElement(document.head, `meta[name="${name}"]`); + if (element) { + return element.getAttribute("content"); + } +} + +function findElements(root, selector) { + if (typeof root == "string") { + selector = root; + root = document; + } + const elements = root.querySelectorAll(selector); + return toArray(elements); +} + +function findElement(root, selector) { + if (typeof root == "string") { + selector = root; + root = document; + } + return root.querySelector(selector); +} + +function dispatchEvent(element, type, eventInit = {}) { + const {disabled: disabled} = element; + const {bubbles: bubbles, cancelable: cancelable, detail: 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; +} + +function toArray(value) { + if (Array.isArray(value)) { + return value; + } else if (Array.from) { + return Array.from(value); + } else { + return [].slice.call(value); + } +} + +class BlobRecord { + constructor(file, checksum, url) { + this.file = file; + this.attributes = { + filename: file.name, + content_type: file.type || "application/octet-stream", + byte_size: file.size, + checksum: checksum + }; + this.xhr = new XMLHttpRequest; + this.xhr.open("POST", url, true); + this.xhr.responseType = "json"; + this.xhr.setRequestHeader("Content-Type", "application/json"); + this.xhr.setRequestHeader("Accept", "application/json"); + this.xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + const csrfToken = getMetaValue("csrf-token"); + if (csrfToken != undefined) { + this.xhr.setRequestHeader("X-CSRF-Token", csrfToken); + } + this.xhr.addEventListener("load", (event => this.requestDidLoad(event))); + this.xhr.addEventListener("error", (event => this.requestDidError(event))); + } + get status() { + return this.xhr.status; + } + get response() { + const {responseType: responseType, response: response} = this.xhr; + if (responseType == "json") { + return response; + } else { + return JSON.parse(response); + } + } + create(callback) { + this.callback = callback; + this.xhr.send(JSON.stringify({ + blob: this.attributes + })); + } + requestDidLoad(event) { + if (this.status >= 200 && this.status < 300) { + const {response: response} = this; + const {direct_upload: direct_upload} = response; + delete response.direct_upload; + this.attributes = response; + this.directUploadData = direct_upload; + this.callback(null, this.toJSON()); + } else { + this.requestDidError(event); + } + } + requestDidError(event) { + this.callback(`Error creating Blob for "${this.file.name}". Status: ${this.status}`); + } + toJSON() { + const result = {}; + for (const key in this.attributes) { + result[key] = this.attributes[key]; + } + return result; + } +} + +class BlobUpload { + constructor(blob) { + this.blob = blob; + this.file = blob.file; + const {url: url, headers: headers} = blob.directUploadData; + this.xhr = new XMLHttpRequest; + this.xhr.open("PUT", url, true); + this.xhr.responseType = "text"; + for (const key in headers) { + this.xhr.setRequestHeader(key, headers[key]); + } + this.xhr.addEventListener("load", (event => this.requestDidLoad(event))); + this.xhr.addEventListener("error", (event => this.requestDidError(event))); + } + create(callback) { + this.callback = callback; + this.xhr.send(this.file.slice()); + } + requestDidLoad(event) { + const {status: status, response: response} = this.xhr; + if (status >= 200 && status < 300) { + this.callback(null, response); + } else { + this.requestDidError(event); + } + } + requestDidError(event) { + this.callback(`Error storing "${this.file.name}". Status: ${this.xhr.status}`); + } +} + +let id = 0; + +class DirectUpload { + constructor(file, url, delegate) { + this.id = ++id; + this.file = file; + this.url = url; + this.delegate = delegate; + } + create(callback) { + FileChecksum.create(this.file, ((error, checksum) => { + if (error) { + callback(error); + return; + } + const blob = new BlobRecord(this.file, checksum, this.url); + notify(this.delegate, "directUploadWillCreateBlobWithXHR", blob.xhr); + blob.create((error => { + if (error) { + callback(error); + } else { + const upload = new BlobUpload(blob); + notify(this.delegate, "directUploadWillStoreFileWithXHR", upload.xhr); + upload.create((error => { + if (error) { + callback(error); + } else { + callback(null, blob.toJSON()); + } + })); + } + })); + })); + } +} + +function notify(object, methodName, ...messages) { + if (object && typeof object[methodName] == "function") { + return object[methodName](...messages); + } +} + +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: 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: detail + }); + } + dispatchError(error) { + const event = this.dispatch("error", { + error: error + }); + if (!event.defaultPrevented) { + alert(error); + } + } + directUploadWillCreateBlobWithXHR(xhr) { + this.dispatch("before-blob-request", { + xhr: xhr + }); + } + directUploadWillStoreFileWithXHR(xhr) { + this.dispatch("before-storage-request", { + xhr: xhr + }); + xhr.upload.addEventListener("progress", (event => this.uploadRequestDidProgress(event))); + } +} + +const inputSelector = "input[type=file][data-direct-upload-url]:not([disabled])"; + +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: detail + }); + } +} + +const processingAttribute = "data-direct-uploads-processing"; + +const submitButtonsByForm = new WeakMap; + +let started = false; + +function start() { + if (!started) { + started = true; + document.addEventListener("click", didClick, true); + document.addEventListener("submit", didSubmitForm, true); + document.addEventListener("ajax:before", didSubmitRemoteElement); + } +} + +function didClick(event) { + const {target: target} = event; + if ((target.tagName == "INPUT" || target.tagName == "BUTTON") && target.type == "submit" && target.form) { + submitButtonsByForm.set(target.form, target); + } +} + +function didSubmitForm(event) { + handleFormSubmissionEvent(event); +} + +function didSubmitRemoteElement(event) { + if (event.target.tagName == "FORM") { + handleFormSubmissionEvent(event); + } +} + +function handleFormSubmissionEvent(event) { + const form = event.target; + if (form.hasAttribute(processingAttribute)) { + event.preventDefault(); + return; + } + const controller = new DirectUploadsController(form); + const {inputs: inputs} = controller; + if (inputs.length) { + event.preventDefault(); + form.setAttribute(processingAttribute, ""); + inputs.forEach(disable); + controller.start((error => { + form.removeAttribute(processingAttribute); + if (error) { + inputs.forEach(enable); + } else { + submitForm(form); + } + })); + } +} + +function submitForm(form) { + let button = submitButtonsByForm.get(form) || findElement(form, "input[type=submit], button[type=submit]"); + if (button) { + const {disabled: disabled} = button; + button.disabled = false; + button.focus(); + button.click(); + button.disabled = disabled; + } else { + button = document.createElement("input"); + button.type = "submit"; + button.style.display = "none"; + form.appendChild(button); + button.click(); + form.removeChild(button); + } + submitButtonsByForm.delete(form); +} + +function disable(input) { + input.disabled = true; +} + +function enable(input) { + input.disabled = false; +} + +function autostart() { + if (window.ActiveStorage) { + start(); + } +} + +setTimeout(autostart, 1); + +export { DirectUpload, start }; diff --git a/activestorage/app/assets/javascripts/activestorage.js b/activestorage/app/assets/javascripts/activestorage.js index 621c5b23c7..646f21949d 100644 --- a/activestorage/app/assets/javascripts/activestorage.js +++ b/activestorage/app/assets/javascripts/activestorage.js @@ -1,18 +1,17 @@ (function(global, factory) { - typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define([ "exports" ], factory) : factory(global.ActiveStorage = {}); -})(this, function(exports) { + typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define([ "exports" ], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, + factory(global.ActiveStorage = {})); +})(this, (function(exports) { "use strict"; - function createCommonjsModule(fn, module) { - return module = { - exports: {} - }, fn(module, module.exports), module.exports; - } - var sparkMd5 = createCommonjsModule(function(module, exports) { + var sparkMd5 = { + exports: {} + }; + (function(module, exports) { (function(factory) { { module.exports = factory(); } - })(function(undefined) { + })((function(undefined$1) { var hex_chr = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" ]; function md5cycle(x, k) { var a = x[0], b = x[1], c = x[2], d = x[3]; @@ -243,7 +242,7 @@ } ArrayBuffer.prototype.slice = function(from, to) { var length = this.byteLength, begin = clamp(from, length), end = length, num, target, targetArray, sourceArray; - if (to !== undefined) { + if (to !== undefined$1) { end = clamp(to, length); } if (begin > end) { @@ -327,7 +326,7 @@ return { buff: this._buff, length: this._length, - hash: this._hash + hash: this._hash.slice() }; }; SparkMD5.prototype.setState = function(state) { @@ -412,94 +411,55 @@ return raw ? hexToBinaryString(ret) : ret; }; return SparkMD5; - }); - }); - var classCallCheck = function(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); + })); + })(sparkMd5); + var SparkMD5 = sparkMd5.exports; + const fileSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice; + class FileChecksum { + static create(file, callback) { + const instance = new FileChecksum(file); + instance.create(callback); } - }; - var createClass = function() { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - return function(Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; - }(); - var fileSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice; - var FileChecksum = function() { - createClass(FileChecksum, null, [ { - key: "create", - value: function create(file, callback) { - var instance = new FileChecksum(file); - instance.create(callback); - } - } ]); - function FileChecksum(file) { - classCallCheck(this, FileChecksum); + constructor(file) { this.file = file; this.chunkSize = 2097152; this.chunkCount = Math.ceil(this.file.size / this.chunkSize); this.chunkIndex = 0; } - createClass(FileChecksum, [ { - key: "create", - value: function create(callback) { - var _this = this; - this.callback = callback; - this.md5Buffer = new sparkMd5.ArrayBuffer(); - this.fileReader = new FileReader(); - this.fileReader.addEventListener("load", function(event) { - return _this.fileReaderDidLoad(event); - }); - this.fileReader.addEventListener("error", function(event) { - return _this.fileReaderDidError(event); - }); - this.readNextChunk(); + create(callback) { + this.callback = callback; + this.md5Buffer = new SparkMD5.ArrayBuffer; + this.fileReader = new FileReader; + this.fileReader.addEventListener("load", (event => this.fileReaderDidLoad(event))); + this.fileReader.addEventListener("error", (event => this.fileReaderDidError(event))); + this.readNextChunk(); + } + fileReaderDidLoad(event) { + this.md5Buffer.append(event.target.result); + if (!this.readNextChunk()) { + const binaryDigest = this.md5Buffer.end(true); + const base64digest = btoa(binaryDigest); + this.callback(null, base64digest); } - }, { - key: "fileReaderDidLoad", - value: function fileReaderDidLoad(event) { - this.md5Buffer.append(event.target.result); - if (!this.readNextChunk()) { - var binaryDigest = this.md5Buffer.end(true); - var base64digest = btoa(binaryDigest); - this.callback(null, base64digest); - } + } + fileReaderDidError(event) { + this.callback(`Error reading ${this.file.name}`); + } + readNextChunk() { + if (this.chunkIndex < this.chunkCount || this.chunkIndex == 0 && this.chunkCount == 0) { + const start = this.chunkIndex * this.chunkSize; + const end = Math.min(start + this.chunkSize, this.file.size); + const bytes = fileSlice.call(this.file, start, end); + this.fileReader.readAsArrayBuffer(bytes); + this.chunkIndex++; + return true; + } else { + return false; } - }, { - key: "fileReaderDidError", - value: function fileReaderDidError(event) { - this.callback("Error reading " + this.file.name); - } - }, { - key: "readNextChunk", - value: function readNextChunk() { - if (this.chunkIndex < this.chunkCount || this.chunkIndex == 0 && this.chunkCount == 0) { - var start = this.chunkIndex * this.chunkSize; - var end = Math.min(start + this.chunkSize, this.file.size); - var bytes = fileSlice.call(this.file, start, end); - this.fileReader.readAsArrayBuffer(bytes); - this.chunkIndex++; - return true; - } else { - return false; - } - } - } ]); - return FileChecksum; - }(); + } + } function getMetaValue(name) { - var element = findElement(document.head, 'meta[name="' + name + '"]'); + const element = findElement(document.head, `meta[name="${name}"]`); if (element) { return element.getAttribute("content"); } @@ -509,8 +469,8 @@ selector = root; root = document; } - var elements = root.querySelectorAll(selector); - return toArray$1(elements); + const elements = root.querySelectorAll(selector); + return toArray(elements); } function findElement(root, selector) { if (typeof root == "string") { @@ -519,11 +479,10 @@ } return root.querySelector(selector); } - function dispatchEvent(element, type) { - var eventInit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - var disabled = element.disabled; - var bubbles = eventInit.bubbles, cancelable = eventInit.cancelable, detail = eventInit.detail; - var event = document.createEvent("Event"); + function dispatchEvent(element, type, eventInit = {}) { + const {disabled: disabled} = element; + const {bubbles: bubbles, cancelable: cancelable, detail: detail} = eventInit; + const event = document.createEvent("Event"); event.initEvent(type, bubbles || true, cancelable || true); event.detail = detail || {}; try { @@ -534,7 +493,7 @@ } return event; } - function toArray$1(value) { + function toArray(value) { if (Array.isArray(value)) { return value; } else if (Array.from) { @@ -543,10 +502,8 @@ return [].slice.call(value); } } - var BlobRecord = function() { - function BlobRecord(file, checksum, url) { - var _this = this; - classCallCheck(this, BlobRecord); + class BlobRecord { + constructor(file, checksum, url) { this.file = file; this.attributes = { filename: file.name, @@ -554,312 +511,236 @@ byte_size: file.size, checksum: checksum }; - this.xhr = new XMLHttpRequest(); + this.xhr = new XMLHttpRequest; this.xhr.open("POST", url, true); this.xhr.responseType = "json"; this.xhr.setRequestHeader("Content-Type", "application/json"); this.xhr.setRequestHeader("Accept", "application/json"); this.xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); - var csrfToken = getMetaValue("csrf-token"); + const csrfToken = getMetaValue("csrf-token"); if (csrfToken != undefined) { this.xhr.setRequestHeader("X-CSRF-Token", csrfToken); } - this.xhr.addEventListener("load", function(event) { - return _this.requestDidLoad(event); - }); - this.xhr.addEventListener("error", function(event) { - return _this.requestDidError(event); - }); + this.xhr.addEventListener("load", (event => this.requestDidLoad(event))); + this.xhr.addEventListener("error", (event => this.requestDidError(event))); } - createClass(BlobRecord, [ { - key: "create", - value: function create(callback) { - this.callback = callback; - this.xhr.send(JSON.stringify({ - blob: this.attributes - })); + get status() { + return this.xhr.status; + } + get response() { + const {responseType: responseType, response: response} = this.xhr; + if (responseType == "json") { + return response; + } else { + return JSON.parse(response); } - }, { - key: "requestDidLoad", - value: function requestDidLoad(event) { - if (this.status >= 200 && this.status < 300) { - var response = this.response; - var direct_upload = response.direct_upload; - delete response.direct_upload; - this.attributes = response; - this.directUploadData = direct_upload; - this.callback(null, this.toJSON()); - } else { - this.requestDidError(event); - } + } + create(callback) { + this.callback = callback; + this.xhr.send(JSON.stringify({ + blob: this.attributes + })); + } + requestDidLoad(event) { + if (this.status >= 200 && this.status < 300) { + const {response: response} = this; + const {direct_upload: direct_upload} = response; + delete response.direct_upload; + this.attributes = response; + this.directUploadData = direct_upload; + this.callback(null, this.toJSON()); + } else { + this.requestDidError(event); } - }, { - key: "requestDidError", - value: function requestDidError(event) { - this.callback('Error creating Blob for "' + this.file.name + '". Status: ' + this.status); + } + requestDidError(event) { + this.callback(`Error creating Blob for "${this.file.name}". Status: ${this.status}`); + } + toJSON() { + const result = {}; + for (const key in this.attributes) { + result[key] = this.attributes[key]; } - }, { - key: "toJSON", - value: function toJSON() { - var result = {}; - for (var key in this.attributes) { - result[key] = this.attributes[key]; - } - return result; - } - }, { - key: "status", - get: function get$$1() { - return this.xhr.status; - } - }, { - key: "response", - get: function get$$1() { - var _xhr = this.xhr, responseType = _xhr.responseType, response = _xhr.response; - if (responseType == "json") { - return response; - } else { - return JSON.parse(response); - } - } - } ]); - return BlobRecord; - }(); - var BlobUpload = function() { - function BlobUpload(blob) { - var _this = this; - classCallCheck(this, BlobUpload); + return result; + } + } + class BlobUpload { + constructor(blob) { this.blob = blob; this.file = blob.file; - var _blob$directUploadDat = blob.directUploadData, url = _blob$directUploadDat.url, headers = _blob$directUploadDat.headers; - this.xhr = new XMLHttpRequest(); + const {url: url, headers: headers} = blob.directUploadData; + this.xhr = new XMLHttpRequest; this.xhr.open("PUT", url, true); this.xhr.responseType = "text"; - for (var key in headers) { + for (const key in headers) { this.xhr.setRequestHeader(key, headers[key]); } - this.xhr.addEventListener("load", function(event) { - return _this.requestDidLoad(event); - }); - this.xhr.addEventListener("error", function(event) { - return _this.requestDidError(event); - }); + this.xhr.addEventListener("load", (event => this.requestDidLoad(event))); + this.xhr.addEventListener("error", (event => this.requestDidError(event))); } - createClass(BlobUpload, [ { - key: "create", - value: function create(callback) { - this.callback = callback; - this.xhr.send(this.file.slice()); + create(callback) { + this.callback = callback; + this.xhr.send(this.file.slice()); + } + requestDidLoad(event) { + const {status: status, response: response} = this.xhr; + if (status >= 200 && status < 300) { + this.callback(null, response); + } else { + this.requestDidError(event); } - }, { - key: "requestDidLoad", - value: function requestDidLoad(event) { - var _xhr = this.xhr, status = _xhr.status, response = _xhr.response; - if (status >= 200 && status < 300) { - this.callback(null, response); - } else { - this.requestDidError(event); - } - } - }, { - key: "requestDidError", - value: function requestDidError(event) { - this.callback('Error storing "' + this.file.name + '". Status: ' + this.xhr.status); - } - } ]); - return BlobUpload; - }(); - var id = 0; - var DirectUpload = function() { - function DirectUpload(file, url, delegate) { - classCallCheck(this, DirectUpload); + } + requestDidError(event) { + this.callback(`Error storing "${this.file.name}". Status: ${this.xhr.status}`); + } + } + let id = 0; + class DirectUpload { + constructor(file, url, delegate) { this.id = ++id; this.file = file; this.url = url; this.delegate = delegate; } - createClass(DirectUpload, [ { - key: "create", - value: function create(callback) { - var _this = this; - FileChecksum.create(this.file, function(error, checksum) { + create(callback) { + FileChecksum.create(this.file, ((error, checksum) => { + if (error) { + callback(error); + return; + } + const blob = new BlobRecord(this.file, checksum, this.url); + notify(this.delegate, "directUploadWillCreateBlobWithXHR", blob.xhr); + blob.create((error => { if (error) { callback(error); - return; + } else { + const upload = new BlobUpload(blob); + notify(this.delegate, "directUploadWillStoreFileWithXHR", upload.xhr); + upload.create((error => { + if (error) { + callback(error); + } else { + callback(null, blob.toJSON()); + } + })); } - var blob = new BlobRecord(_this.file, checksum, _this.url); - notify(_this.delegate, "directUploadWillCreateBlobWithXHR", blob.xhr); - blob.create(function(error) { - if (error) { - callback(error); - } else { - var upload = new BlobUpload(blob); - notify(_this.delegate, "directUploadWillStoreFileWithXHR", upload.xhr); - upload.create(function(error) { - if (error) { - callback(error); - } else { - callback(null, blob.toJSON()); - } - }); - } - }); - }); - } - } ]); - return DirectUpload; - }(); - function notify(object, methodName) { - if (object && typeof object[methodName] == "function") { - for (var _len = arguments.length, messages = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { - messages[_key - 2] = arguments[_key]; - } - return object[methodName].apply(object, messages); + })); + })); } } - var DirectUploadController = function() { - function DirectUploadController(input, file) { - classCallCheck(this, DirectUploadController); + function notify(object, methodName, ...messages) { + if (object && typeof object[methodName] == "function") { + return object[methodName](...messages); + } + } + class DirectUploadController { + constructor(input, file) { this.input = input; this.file = file; this.directUpload = new DirectUpload(this.file, this.url, this); this.dispatch("initialize"); } - createClass(DirectUploadController, [ { - key: "start", - value: function start(callback) { - var _this = this; - var hiddenInput = document.createElement("input"); - hiddenInput.type = "hidden"; - hiddenInput.name = this.input.name; - this.input.insertAdjacentElement("beforebegin", hiddenInput); - this.dispatch("start"); - this.directUpload.create(function(error, attributes) { - if (error) { - hiddenInput.parentNode.removeChild(hiddenInput); - _this.dispatchError(error); - } else { - hiddenInput.value = attributes.signed_id; - } - _this.dispatch("end"); - callback(error); - }); - } - }, { - key: "uploadRequestDidProgress", - value: function uploadRequestDidProgress(event) { - var progress = event.loaded / event.total * 100; - if (progress) { - this.dispatch("progress", { - progress: progress - }); + 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; } - } - }, { - key: "dispatch", - value: function dispatch(name) { - var detail = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - detail.file = this.file; - detail.id = this.directUpload.id; - return dispatchEvent(this.input, "direct-upload:" + name, { - detail: detail + this.dispatch("end"); + callback(error); + })); + } + uploadRequestDidProgress(event) { + const progress = event.loaded / event.total * 100; + if (progress) { + this.dispatch("progress", { + progress: progress }); } - }, { - key: "dispatchError", - value: function dispatchError(error) { - var event = this.dispatch("error", { - error: error - }); - if (!event.defaultPrevented) { - alert(error); - } - } - }, { - key: "directUploadWillCreateBlobWithXHR", - value: function directUploadWillCreateBlobWithXHR(xhr) { - this.dispatch("before-blob-request", { - xhr: xhr - }); - } - }, { - key: "directUploadWillStoreFileWithXHR", - value: function directUploadWillStoreFileWithXHR(xhr) { - var _this2 = this; - this.dispatch("before-storage-request", { - xhr: xhr - }); - xhr.upload.addEventListener("progress", function(event) { - return _this2.uploadRequestDidProgress(event); - }); - } - }, { - key: "url", - get: function get$$1() { - return this.input.getAttribute("data-direct-upload-url"); - } - } ]); - return DirectUploadController; - }(); - var inputSelector = "input[type=file][data-direct-upload-url]:not([disabled])"; - var DirectUploadsController = function() { - function DirectUploadsController(form) { - classCallCheck(this, DirectUploadsController); - this.form = form; - this.inputs = findElements(form, inputSelector).filter(function(input) { - return input.files.length; + } + 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: detail }); } - createClass(DirectUploadsController, [ { - key: "start", - value: function start(callback) { - var _this = this; - var controllers = this.createDirectUploadControllers(); - var startNextController = function startNextController() { - var controller = controllers.shift(); - if (controller) { - controller.start(function(error) { - if (error) { - callback(error); - _this.dispatch("end"); - } else { - startNextController(); - } - }); - } else { - callback(); - _this.dispatch("end"); - } - }; - this.dispatch("start"); - startNextController(); + dispatchError(error) { + const event = this.dispatch("error", { + error: error + }); + if (!event.defaultPrevented) { + alert(error); } - }, { - key: "createDirectUploadControllers", - value: function createDirectUploadControllers() { - var controllers = []; - this.inputs.forEach(function(input) { - toArray$1(input.files).forEach(function(file) { - var controller = new DirectUploadController(input, file); - controllers.push(controller); - }); - }); - return controllers; - } - }, { - key: "dispatch", - value: function dispatch(name) { - var detail = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - return dispatchEvent(this.form, "direct-uploads:" + name, { - detail: detail - }); - } - } ]); - return DirectUploadsController; - }(); - var processingAttribute = "data-direct-uploads-processing"; - var submitButtonsByForm = new WeakMap(); - var started = false; + } + directUploadWillCreateBlobWithXHR(xhr) { + this.dispatch("before-blob-request", { + xhr: xhr + }); + } + directUploadWillStoreFileWithXHR(xhr) { + this.dispatch("before-storage-request", { + xhr: xhr + }); + xhr.upload.addEventListener("progress", (event => this.uploadRequestDidProgress(event))); + } + } + const inputSelector = "input[type=file][data-direct-upload-url]:not([disabled])"; + 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: detail + }); + } + } + const processingAttribute = "data-direct-uploads-processing"; + const submitButtonsByForm = new WeakMap; + let started = false; function start() { if (!started) { started = true; @@ -869,7 +750,7 @@ } } function didClick(event) { - var target = event.target; + const {target: target} = event; if ((target.tagName == "INPUT" || target.tagName == "BUTTON") && target.type == "submit" && target.form) { submitButtonsByForm.set(target.form, target); } @@ -883,31 +764,31 @@ } } function handleFormSubmissionEvent(event) { - var form = event.target; + const form = event.target; if (form.hasAttribute(processingAttribute)) { event.preventDefault(); return; } - var controller = new DirectUploadsController(form); - var inputs = controller.inputs; + const controller = new DirectUploadsController(form); + const {inputs: inputs} = controller; if (inputs.length) { event.preventDefault(); form.setAttribute(processingAttribute, ""); inputs.forEach(disable); - controller.start(function(error) { + controller.start((error => { form.removeAttribute(processingAttribute); if (error) { inputs.forEach(enable); } else { submitForm(form); } - }); + })); } } function submitForm(form) { - var button = submitButtonsByForm.get(form) || findElement(form, "input[type=submit], button[type=submit]"); + let button = submitButtonsByForm.get(form) || findElement(form, "input[type=submit], button[type=submit]"); if (button) { - var _button = button, disabled = _button.disabled; + const {disabled: disabled} = button; button.disabled = false; button.focus(); button.click(); @@ -934,9 +815,9 @@ } } setTimeout(autostart, 1); - exports.start = start; exports.DirectUpload = DirectUpload; + exports.start = start; Object.defineProperty(exports, "__esModule", { value: true }); -}); +})); diff --git a/activestorage/lib/active_storage/engine.rb b/activestorage/lib/active_storage/engine.rb index b3c6aa21ec..54a4210fa1 100644 --- a/activestorage/lib/active_storage/engine.rb +++ b/activestorage/lib/active_storage/engine.rb @@ -149,6 +149,12 @@ module ActiveStorage end end + initializer "active_storage.asset" do + if Rails.application.config.respond_to?(:assets) + Rails.application.config.assets.precompile += %w( activestorage activestorage.esm ) + end + end + initializer "active_storage.fixture_set" do ActiveSupport.on_load(:active_record_fixture_set) do ActiveStorage::FixtureSet.file_fixture_path ||= Rails.root.join(*[ diff --git a/activestorage/package.json b/activestorage/package.json index daf7fbe657..bd072e762c 100644 --- a/activestorage/package.json +++ b/activestorage/package.json @@ -3,6 +3,7 @@ "version": "7.0.0-alpha", "description": "Attach cloud and local files in Rails applications", "main": "app/assets/javascripts/activestorage.js", + "type": "module", "files": [ "app/assets/javascripts/*.js", "src/*.js" @@ -18,19 +19,15 @@ "author": "Javan Makhmali ", "license": "MIT", "dependencies": { - "spark-md5": "^3.0.0" + "spark-md5": "^3.0.1" }, "devDependencies": { - "babel-core": "^6.25.0", - "babel-plugin-external-helpers": "^6.22.0", - "babel-preset-env": "^1.6.0", + "@rollup/plugin-node-resolve": "^11.0.1", + "@rollup/plugin-commonjs": "^19.0.1", "eslint": "^4.3.0", - "eslint-plugin-import": "^2.7.0", - "rollup": "^0.58.2", - "rollup-plugin-babel": "^3.0.4", - "rollup-plugin-commonjs": "^9.1.0", - "rollup-plugin-node-resolve": "^3.3.0", - "rollup-plugin-uglify": "^3.0.0" + "eslint-plugin-import": "^2.23.4", + "rollup": "^2.35.1", + "rollup-plugin-terser": "^7.0.2" }, "scripts": { "prebuild": "yarn lint", diff --git a/activestorage/rollup.config.js b/activestorage/rollup.config.js index 1b4f9477ab..599ff987d9 100644 --- a/activestorage/rollup.config.js +++ b/activestorage/rollup.config.js @@ -1,28 +1,41 @@ -import resolve from "rollup-plugin-node-resolve" -import commonjs from "rollup-plugin-commonjs" -import babel from "rollup-plugin-babel" -import uglify from "rollup-plugin-uglify" +import resolve from "@rollup/plugin-node-resolve" +import commonjs from "@rollup/plugin-commonjs" +import { terser } from "rollup-plugin-terser" -const uglifyOptions = { - mangle: false, - compress: false, - output: { - beautify: true, - indent_level: 2 - } +const terserOptions = { + mangle: false, + compress: false, + format: { + beautify: true, + indent_level: 2 + } } -export default { - input: "app/javascript/activestorage/index.js", - output: { - file: "app/assets/javascripts/activestorage.js", - format: "umd", - name: "ActiveStorage" +export default [ + { + input: "app/javascript/activestorage/index.js", + output: { + file: "app/assets/javascripts/activestorage.js", + format: "umd", + name: "ActiveStorage" + }, + plugins: [ + resolve(), + commonjs(), + terser(terserOptions) + ] }, - plugins: [ - resolve(), - commonjs(), - babel(), - uglify(uglifyOptions) - ] -} + + { + input: "app/javascript/activestorage/index.js", + output: { + file: "app/assets/javascripts/activestorage.esm.js", + format: "es" + }, + plugins: [ + resolve(), + commonjs(), + terser(terserOptions) + ] + } +]