mirror of
https://github.com/CodeforLeipzig/stadtratmonitor.git
synced 2024-12-22 23:53:15 +01:00
move to public
This commit is contained in:
parent
bb975c8453
commit
2a1630a844
27 changed files with 35163 additions and 1 deletions
|
@ -14,6 +14,6 @@
|
||||||
//= require jquery_ujs
|
//= require jquery_ujs
|
||||||
//= require foundation
|
//= require foundation
|
||||||
//= require turbolinks
|
//= require turbolinks
|
||||||
//= require_tree ./public
|
//=require_tree ../../../app/assets/stylesheets/public
|
||||||
|
|
||||||
$(function(){ $(document).foundation(); });
|
$(function(){ $(document).foundation(); });
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,489 @@
|
||||||
|
(function(global, factory) {
|
||||||
|
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.ActionCable = {}));
|
||||||
|
})(this, (function(exports) {
|
||||||
|
"use strict";
|
||||||
|
var adapters = {
|
||||||
|
logger: self.console,
|
||||||
|
WebSocket: self.WebSocket
|
||||||
|
};
|
||||||
|
var logger = {
|
||||||
|
log(...messages) {
|
||||||
|
if (this.enabled) {
|
||||||
|
messages.push(Date.now());
|
||||||
|
adapters.logger.log("[ActionCable]", ...messages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const now = () => (new Date).getTime();
|
||||||
|
const secondsSince = time => (now() - time) / 1e3;
|
||||||
|
class ConnectionMonitor {
|
||||||
|
constructor(connection) {
|
||||||
|
this.visibilityDidChange = this.visibilityDidChange.bind(this);
|
||||||
|
this.connection = connection;
|
||||||
|
this.reconnectAttempts = 0;
|
||||||
|
}
|
||||||
|
start() {
|
||||||
|
if (!this.isRunning()) {
|
||||||
|
this.startedAt = now();
|
||||||
|
delete this.stoppedAt;
|
||||||
|
this.startPolling();
|
||||||
|
addEventListener("visibilitychange", this.visibilityDidChange);
|
||||||
|
logger.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stop() {
|
||||||
|
if (this.isRunning()) {
|
||||||
|
this.stoppedAt = now();
|
||||||
|
this.stopPolling();
|
||||||
|
removeEventListener("visibilitychange", this.visibilityDidChange);
|
||||||
|
logger.log("ConnectionMonitor stopped");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isRunning() {
|
||||||
|
return this.startedAt && !this.stoppedAt;
|
||||||
|
}
|
||||||
|
recordPing() {
|
||||||
|
this.pingedAt = now();
|
||||||
|
}
|
||||||
|
recordConnect() {
|
||||||
|
this.reconnectAttempts = 0;
|
||||||
|
this.recordPing();
|
||||||
|
delete this.disconnectedAt;
|
||||||
|
logger.log("ConnectionMonitor recorded connect");
|
||||||
|
}
|
||||||
|
recordDisconnect() {
|
||||||
|
this.disconnectedAt = now();
|
||||||
|
logger.log("ConnectionMonitor recorded disconnect");
|
||||||
|
}
|
||||||
|
startPolling() {
|
||||||
|
this.stopPolling();
|
||||||
|
this.poll();
|
||||||
|
}
|
||||||
|
stopPolling() {
|
||||||
|
clearTimeout(this.pollTimeout);
|
||||||
|
}
|
||||||
|
poll() {
|
||||||
|
this.pollTimeout = setTimeout((() => {
|
||||||
|
this.reconnectIfStale();
|
||||||
|
this.poll();
|
||||||
|
}), this.getPollInterval());
|
||||||
|
}
|
||||||
|
getPollInterval() {
|
||||||
|
const {staleThreshold: staleThreshold, reconnectionBackoffRate: reconnectionBackoffRate} = this.constructor;
|
||||||
|
const backoff = Math.pow(1 + reconnectionBackoffRate, Math.min(this.reconnectAttempts, 10));
|
||||||
|
const jitterMax = this.reconnectAttempts === 0 ? 1 : reconnectionBackoffRate;
|
||||||
|
const jitter = jitterMax * Math.random();
|
||||||
|
return staleThreshold * 1e3 * backoff * (1 + jitter);
|
||||||
|
}
|
||||||
|
reconnectIfStale() {
|
||||||
|
if (this.connectionIsStale()) {
|
||||||
|
logger.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${secondsSince(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`);
|
||||||
|
this.reconnectAttempts++;
|
||||||
|
if (this.disconnectedRecently()) {
|
||||||
|
logger.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${secondsSince(this.disconnectedAt)} s`);
|
||||||
|
} else {
|
||||||
|
logger.log("ConnectionMonitor reopening");
|
||||||
|
this.connection.reopen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get refreshedAt() {
|
||||||
|
return this.pingedAt ? this.pingedAt : this.startedAt;
|
||||||
|
}
|
||||||
|
connectionIsStale() {
|
||||||
|
return secondsSince(this.refreshedAt) > this.constructor.staleThreshold;
|
||||||
|
}
|
||||||
|
disconnectedRecently() {
|
||||||
|
return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold;
|
||||||
|
}
|
||||||
|
visibilityDidChange() {
|
||||||
|
if (document.visibilityState === "visible") {
|
||||||
|
setTimeout((() => {
|
||||||
|
if (this.connectionIsStale() || !this.connection.isOpen()) {
|
||||||
|
logger.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`);
|
||||||
|
this.connection.reopen();
|
||||||
|
}
|
||||||
|
}), 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConnectionMonitor.staleThreshold = 6;
|
||||||
|
ConnectionMonitor.reconnectionBackoffRate = .15;
|
||||||
|
var INTERNAL = {
|
||||||
|
message_types: {
|
||||||
|
welcome: "welcome",
|
||||||
|
disconnect: "disconnect",
|
||||||
|
ping: "ping",
|
||||||
|
confirmation: "confirm_subscription",
|
||||||
|
rejection: "reject_subscription"
|
||||||
|
},
|
||||||
|
disconnect_reasons: {
|
||||||
|
unauthorized: "unauthorized",
|
||||||
|
invalid_request: "invalid_request",
|
||||||
|
server_restart: "server_restart"
|
||||||
|
},
|
||||||
|
default_mount_path: "/cable",
|
||||||
|
protocols: [ "actioncable-v1-json", "actioncable-unsupported" ]
|
||||||
|
};
|
||||||
|
const {message_types: message_types, protocols: protocols} = INTERNAL;
|
||||||
|
const supportedProtocols = protocols.slice(0, protocols.length - 1);
|
||||||
|
const indexOf = [].indexOf;
|
||||||
|
class Connection {
|
||||||
|
constructor(consumer) {
|
||||||
|
this.open = this.open.bind(this);
|
||||||
|
this.consumer = consumer;
|
||||||
|
this.subscriptions = this.consumer.subscriptions;
|
||||||
|
this.monitor = new ConnectionMonitor(this);
|
||||||
|
this.disconnected = true;
|
||||||
|
}
|
||||||
|
send(data) {
|
||||||
|
if (this.isOpen()) {
|
||||||
|
this.webSocket.send(JSON.stringify(data));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
open() {
|
||||||
|
if (this.isActive()) {
|
||||||
|
logger.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${protocols}`);
|
||||||
|
if (this.webSocket) {
|
||||||
|
this.uninstallEventHandlers();
|
||||||
|
}
|
||||||
|
this.webSocket = new adapters.WebSocket(this.consumer.url, protocols);
|
||||||
|
this.installEventHandlers();
|
||||||
|
this.monitor.start();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close({allowReconnect: allowReconnect} = {
|
||||||
|
allowReconnect: true
|
||||||
|
}) {
|
||||||
|
if (!allowReconnect) {
|
||||||
|
this.monitor.stop();
|
||||||
|
}
|
||||||
|
if (this.isOpen()) {
|
||||||
|
return this.webSocket.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reopen() {
|
||||||
|
logger.log(`Reopening WebSocket, current state is ${this.getState()}`);
|
||||||
|
if (this.isActive()) {
|
||||||
|
try {
|
||||||
|
return this.close();
|
||||||
|
} catch (error) {
|
||||||
|
logger.log("Failed to reopen WebSocket", error);
|
||||||
|
} finally {
|
||||||
|
logger.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`);
|
||||||
|
setTimeout(this.open, this.constructor.reopenDelay);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return this.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getProtocol() {
|
||||||
|
if (this.webSocket) {
|
||||||
|
return this.webSocket.protocol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isOpen() {
|
||||||
|
return this.isState("open");
|
||||||
|
}
|
||||||
|
isActive() {
|
||||||
|
return this.isState("open", "connecting");
|
||||||
|
}
|
||||||
|
isProtocolSupported() {
|
||||||
|
return indexOf.call(supportedProtocols, this.getProtocol()) >= 0;
|
||||||
|
}
|
||||||
|
isState(...states) {
|
||||||
|
return indexOf.call(states, this.getState()) >= 0;
|
||||||
|
}
|
||||||
|
getState() {
|
||||||
|
if (this.webSocket) {
|
||||||
|
for (let state in adapters.WebSocket) {
|
||||||
|
if (adapters.WebSocket[state] === this.webSocket.readyState) {
|
||||||
|
return state.toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
installEventHandlers() {
|
||||||
|
for (let eventName in this.events) {
|
||||||
|
const handler = this.events[eventName].bind(this);
|
||||||
|
this.webSocket[`on${eventName}`] = handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uninstallEventHandlers() {
|
||||||
|
for (let eventName in this.events) {
|
||||||
|
this.webSocket[`on${eventName}`] = function() {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Connection.reopenDelay = 500;
|
||||||
|
Connection.prototype.events = {
|
||||||
|
message(event) {
|
||||||
|
if (!this.isProtocolSupported()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const {identifier: identifier, message: message, reason: reason, reconnect: reconnect, type: type} = JSON.parse(event.data);
|
||||||
|
switch (type) {
|
||||||
|
case message_types.welcome:
|
||||||
|
this.monitor.recordConnect();
|
||||||
|
return this.subscriptions.reload();
|
||||||
|
|
||||||
|
case message_types.disconnect:
|
||||||
|
logger.log(`Disconnecting. Reason: ${reason}`);
|
||||||
|
return this.close({
|
||||||
|
allowReconnect: reconnect
|
||||||
|
});
|
||||||
|
|
||||||
|
case message_types.ping:
|
||||||
|
return this.monitor.recordPing();
|
||||||
|
|
||||||
|
case message_types.confirmation:
|
||||||
|
this.subscriptions.confirmSubscription(identifier);
|
||||||
|
return this.subscriptions.notify(identifier, "connected");
|
||||||
|
|
||||||
|
case message_types.rejection:
|
||||||
|
return this.subscriptions.reject(identifier);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return this.subscriptions.notify(identifier, "received", message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
open() {
|
||||||
|
logger.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`);
|
||||||
|
this.disconnected = false;
|
||||||
|
if (!this.isProtocolSupported()) {
|
||||||
|
logger.log("Protocol is unsupported. Stopping monitor and disconnecting.");
|
||||||
|
return this.close({
|
||||||
|
allowReconnect: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
close(event) {
|
||||||
|
logger.log("WebSocket onclose event");
|
||||||
|
if (this.disconnected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.disconnected = true;
|
||||||
|
this.monitor.recordDisconnect();
|
||||||
|
return this.subscriptions.notifyAll("disconnected", {
|
||||||
|
willAttemptReconnect: this.monitor.isRunning()
|
||||||
|
});
|
||||||
|
},
|
||||||
|
error() {
|
||||||
|
logger.log("WebSocket onerror event");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const extend = function(object, properties) {
|
||||||
|
if (properties != null) {
|
||||||
|
for (let key in properties) {
|
||||||
|
const value = properties[key];
|
||||||
|
object[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
};
|
||||||
|
class Subscription {
|
||||||
|
constructor(consumer, params = {}, mixin) {
|
||||||
|
this.consumer = consumer;
|
||||||
|
this.identifier = JSON.stringify(params);
|
||||||
|
extend(this, mixin);
|
||||||
|
}
|
||||||
|
perform(action, data = {}) {
|
||||||
|
data.action = action;
|
||||||
|
return this.send(data);
|
||||||
|
}
|
||||||
|
send(data) {
|
||||||
|
return this.consumer.send({
|
||||||
|
command: "message",
|
||||||
|
identifier: this.identifier,
|
||||||
|
data: JSON.stringify(data)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
unsubscribe() {
|
||||||
|
return this.consumer.subscriptions.remove(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class SubscriptionGuarantor {
|
||||||
|
constructor(subscriptions) {
|
||||||
|
this.subscriptions = subscriptions;
|
||||||
|
this.pendingSubscriptions = [];
|
||||||
|
}
|
||||||
|
guarantee(subscription) {
|
||||||
|
if (this.pendingSubscriptions.indexOf(subscription) == -1) {
|
||||||
|
logger.log(`SubscriptionGuarantor guaranteeing ${subscription.identifier}`);
|
||||||
|
this.pendingSubscriptions.push(subscription);
|
||||||
|
} else {
|
||||||
|
logger.log(`SubscriptionGuarantor already guaranteeing ${subscription.identifier}`);
|
||||||
|
}
|
||||||
|
this.startGuaranteeing();
|
||||||
|
}
|
||||||
|
forget(subscription) {
|
||||||
|
logger.log(`SubscriptionGuarantor forgetting ${subscription.identifier}`);
|
||||||
|
this.pendingSubscriptions = this.pendingSubscriptions.filter((s => s !== subscription));
|
||||||
|
}
|
||||||
|
startGuaranteeing() {
|
||||||
|
this.stopGuaranteeing();
|
||||||
|
this.retrySubscribing();
|
||||||
|
}
|
||||||
|
stopGuaranteeing() {
|
||||||
|
clearTimeout(this.retryTimeout);
|
||||||
|
}
|
||||||
|
retrySubscribing() {
|
||||||
|
this.retryTimeout = setTimeout((() => {
|
||||||
|
if (this.subscriptions && typeof this.subscriptions.subscribe === "function") {
|
||||||
|
this.pendingSubscriptions.map((subscription => {
|
||||||
|
logger.log(`SubscriptionGuarantor resubscribing ${subscription.identifier}`);
|
||||||
|
this.subscriptions.subscribe(subscription);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}), 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Subscriptions {
|
||||||
|
constructor(consumer) {
|
||||||
|
this.consumer = consumer;
|
||||||
|
this.guarantor = new SubscriptionGuarantor(this);
|
||||||
|
this.subscriptions = [];
|
||||||
|
}
|
||||||
|
create(channelName, mixin) {
|
||||||
|
const channel = channelName;
|
||||||
|
const params = typeof channel === "object" ? channel : {
|
||||||
|
channel: channel
|
||||||
|
};
|
||||||
|
const subscription = new Subscription(this.consumer, params, mixin);
|
||||||
|
return this.add(subscription);
|
||||||
|
}
|
||||||
|
add(subscription) {
|
||||||
|
this.subscriptions.push(subscription);
|
||||||
|
this.consumer.ensureActiveConnection();
|
||||||
|
this.notify(subscription, "initialized");
|
||||||
|
this.subscribe(subscription);
|
||||||
|
return subscription;
|
||||||
|
}
|
||||||
|
remove(subscription) {
|
||||||
|
this.forget(subscription);
|
||||||
|
if (!this.findAll(subscription.identifier).length) {
|
||||||
|
this.sendCommand(subscription, "unsubscribe");
|
||||||
|
}
|
||||||
|
return subscription;
|
||||||
|
}
|
||||||
|
reject(identifier) {
|
||||||
|
return this.findAll(identifier).map((subscription => {
|
||||||
|
this.forget(subscription);
|
||||||
|
this.notify(subscription, "rejected");
|
||||||
|
return subscription;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
forget(subscription) {
|
||||||
|
this.guarantor.forget(subscription);
|
||||||
|
this.subscriptions = this.subscriptions.filter((s => s !== subscription));
|
||||||
|
return subscription;
|
||||||
|
}
|
||||||
|
findAll(identifier) {
|
||||||
|
return this.subscriptions.filter((s => s.identifier === identifier));
|
||||||
|
}
|
||||||
|
reload() {
|
||||||
|
return this.subscriptions.map((subscription => this.subscribe(subscription)));
|
||||||
|
}
|
||||||
|
notifyAll(callbackName, ...args) {
|
||||||
|
return this.subscriptions.map((subscription => this.notify(subscription, callbackName, ...args)));
|
||||||
|
}
|
||||||
|
notify(subscription, callbackName, ...args) {
|
||||||
|
let subscriptions;
|
||||||
|
if (typeof subscription === "string") {
|
||||||
|
subscriptions = this.findAll(subscription);
|
||||||
|
} else {
|
||||||
|
subscriptions = [ subscription ];
|
||||||
|
}
|
||||||
|
return subscriptions.map((subscription => typeof subscription[callbackName] === "function" ? subscription[callbackName](...args) : undefined));
|
||||||
|
}
|
||||||
|
subscribe(subscription) {
|
||||||
|
if (this.sendCommand(subscription, "subscribe")) {
|
||||||
|
this.guarantor.guarantee(subscription);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
confirmSubscription(identifier) {
|
||||||
|
logger.log(`Subscription confirmed ${identifier}`);
|
||||||
|
this.findAll(identifier).map((subscription => this.guarantor.forget(subscription)));
|
||||||
|
}
|
||||||
|
sendCommand(subscription, command) {
|
||||||
|
const {identifier: identifier} = subscription;
|
||||||
|
return this.consumer.send({
|
||||||
|
command: command,
|
||||||
|
identifier: identifier
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Consumer {
|
||||||
|
constructor(url) {
|
||||||
|
this._url = url;
|
||||||
|
this.subscriptions = new Subscriptions(this);
|
||||||
|
this.connection = new Connection(this);
|
||||||
|
}
|
||||||
|
get url() {
|
||||||
|
return createWebSocketURL(this._url);
|
||||||
|
}
|
||||||
|
send(data) {
|
||||||
|
return this.connection.send(data);
|
||||||
|
}
|
||||||
|
connect() {
|
||||||
|
return this.connection.open();
|
||||||
|
}
|
||||||
|
disconnect() {
|
||||||
|
return this.connection.close({
|
||||||
|
allowReconnect: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ensureActiveConnection() {
|
||||||
|
if (!this.connection.isActive()) {
|
||||||
|
return this.connection.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function createWebSocketURL(url) {
|
||||||
|
if (typeof url === "function") {
|
||||||
|
url = url();
|
||||||
|
}
|
||||||
|
if (url && !/^wss?:/i.test(url)) {
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
a.href = a.href;
|
||||||
|
a.protocol = a.protocol.replace("http", "ws");
|
||||||
|
return a.href;
|
||||||
|
} else {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function createConsumer(url = getConfig("url") || INTERNAL.default_mount_path) {
|
||||||
|
return new Consumer(url);
|
||||||
|
}
|
||||||
|
function getConfig(name) {
|
||||||
|
const element = document.head.querySelector(`meta[name='action-cable-${name}']`);
|
||||||
|
if (element) {
|
||||||
|
return element.getAttribute("content");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.Connection = Connection;
|
||||||
|
exports.ConnectionMonitor = ConnectionMonitor;
|
||||||
|
exports.Consumer = Consumer;
|
||||||
|
exports.INTERNAL = INTERNAL;
|
||||||
|
exports.Subscription = Subscription;
|
||||||
|
exports.SubscriptionGuarantor = SubscriptionGuarantor;
|
||||||
|
exports.Subscriptions = Subscriptions;
|
||||||
|
exports.adapters = adapters;
|
||||||
|
exports.createConsumer = createConsumer;
|
||||||
|
exports.createWebSocketURL = createWebSocketURL;
|
||||||
|
exports.getConfig = getConfig;
|
||||||
|
exports.logger = logger;
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
}));
|
Binary file not shown.
|
@ -0,0 +1,491 @@
|
||||||
|
var adapters = {
|
||||||
|
logger: self.console,
|
||||||
|
WebSocket: self.WebSocket
|
||||||
|
};
|
||||||
|
|
||||||
|
var logger = {
|
||||||
|
log(...messages) {
|
||||||
|
if (this.enabled) {
|
||||||
|
messages.push(Date.now());
|
||||||
|
adapters.logger.log("[ActionCable]", ...messages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const now = () => (new Date).getTime();
|
||||||
|
|
||||||
|
const secondsSince = time => (now() - time) / 1e3;
|
||||||
|
|
||||||
|
class ConnectionMonitor {
|
||||||
|
constructor(connection) {
|
||||||
|
this.visibilityDidChange = this.visibilityDidChange.bind(this);
|
||||||
|
this.connection = connection;
|
||||||
|
this.reconnectAttempts = 0;
|
||||||
|
}
|
||||||
|
start() {
|
||||||
|
if (!this.isRunning()) {
|
||||||
|
this.startedAt = now();
|
||||||
|
delete this.stoppedAt;
|
||||||
|
this.startPolling();
|
||||||
|
addEventListener("visibilitychange", this.visibilityDidChange);
|
||||||
|
logger.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stop() {
|
||||||
|
if (this.isRunning()) {
|
||||||
|
this.stoppedAt = now();
|
||||||
|
this.stopPolling();
|
||||||
|
removeEventListener("visibilitychange", this.visibilityDidChange);
|
||||||
|
logger.log("ConnectionMonitor stopped");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isRunning() {
|
||||||
|
return this.startedAt && !this.stoppedAt;
|
||||||
|
}
|
||||||
|
recordPing() {
|
||||||
|
this.pingedAt = now();
|
||||||
|
}
|
||||||
|
recordConnect() {
|
||||||
|
this.reconnectAttempts = 0;
|
||||||
|
this.recordPing();
|
||||||
|
delete this.disconnectedAt;
|
||||||
|
logger.log("ConnectionMonitor recorded connect");
|
||||||
|
}
|
||||||
|
recordDisconnect() {
|
||||||
|
this.disconnectedAt = now();
|
||||||
|
logger.log("ConnectionMonitor recorded disconnect");
|
||||||
|
}
|
||||||
|
startPolling() {
|
||||||
|
this.stopPolling();
|
||||||
|
this.poll();
|
||||||
|
}
|
||||||
|
stopPolling() {
|
||||||
|
clearTimeout(this.pollTimeout);
|
||||||
|
}
|
||||||
|
poll() {
|
||||||
|
this.pollTimeout = setTimeout((() => {
|
||||||
|
this.reconnectIfStale();
|
||||||
|
this.poll();
|
||||||
|
}), this.getPollInterval());
|
||||||
|
}
|
||||||
|
getPollInterval() {
|
||||||
|
const {staleThreshold: staleThreshold, reconnectionBackoffRate: reconnectionBackoffRate} = this.constructor;
|
||||||
|
const backoff = Math.pow(1 + reconnectionBackoffRate, Math.min(this.reconnectAttempts, 10));
|
||||||
|
const jitterMax = this.reconnectAttempts === 0 ? 1 : reconnectionBackoffRate;
|
||||||
|
const jitter = jitterMax * Math.random();
|
||||||
|
return staleThreshold * 1e3 * backoff * (1 + jitter);
|
||||||
|
}
|
||||||
|
reconnectIfStale() {
|
||||||
|
if (this.connectionIsStale()) {
|
||||||
|
logger.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${secondsSince(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`);
|
||||||
|
this.reconnectAttempts++;
|
||||||
|
if (this.disconnectedRecently()) {
|
||||||
|
logger.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${secondsSince(this.disconnectedAt)} s`);
|
||||||
|
} else {
|
||||||
|
logger.log("ConnectionMonitor reopening");
|
||||||
|
this.connection.reopen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get refreshedAt() {
|
||||||
|
return this.pingedAt ? this.pingedAt : this.startedAt;
|
||||||
|
}
|
||||||
|
connectionIsStale() {
|
||||||
|
return secondsSince(this.refreshedAt) > this.constructor.staleThreshold;
|
||||||
|
}
|
||||||
|
disconnectedRecently() {
|
||||||
|
return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold;
|
||||||
|
}
|
||||||
|
visibilityDidChange() {
|
||||||
|
if (document.visibilityState === "visible") {
|
||||||
|
setTimeout((() => {
|
||||||
|
if (this.connectionIsStale() || !this.connection.isOpen()) {
|
||||||
|
logger.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`);
|
||||||
|
this.connection.reopen();
|
||||||
|
}
|
||||||
|
}), 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionMonitor.staleThreshold = 6;
|
||||||
|
|
||||||
|
ConnectionMonitor.reconnectionBackoffRate = .15;
|
||||||
|
|
||||||
|
var INTERNAL = {
|
||||||
|
message_types: {
|
||||||
|
welcome: "welcome",
|
||||||
|
disconnect: "disconnect",
|
||||||
|
ping: "ping",
|
||||||
|
confirmation: "confirm_subscription",
|
||||||
|
rejection: "reject_subscription"
|
||||||
|
},
|
||||||
|
disconnect_reasons: {
|
||||||
|
unauthorized: "unauthorized",
|
||||||
|
invalid_request: "invalid_request",
|
||||||
|
server_restart: "server_restart"
|
||||||
|
},
|
||||||
|
default_mount_path: "/cable",
|
||||||
|
protocols: [ "actioncable-v1-json", "actioncable-unsupported" ]
|
||||||
|
};
|
||||||
|
|
||||||
|
const {message_types: message_types, protocols: protocols} = INTERNAL;
|
||||||
|
|
||||||
|
const supportedProtocols = protocols.slice(0, protocols.length - 1);
|
||||||
|
|
||||||
|
const indexOf = [].indexOf;
|
||||||
|
|
||||||
|
class Connection {
|
||||||
|
constructor(consumer) {
|
||||||
|
this.open = this.open.bind(this);
|
||||||
|
this.consumer = consumer;
|
||||||
|
this.subscriptions = this.consumer.subscriptions;
|
||||||
|
this.monitor = new ConnectionMonitor(this);
|
||||||
|
this.disconnected = true;
|
||||||
|
}
|
||||||
|
send(data) {
|
||||||
|
if (this.isOpen()) {
|
||||||
|
this.webSocket.send(JSON.stringify(data));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
open() {
|
||||||
|
if (this.isActive()) {
|
||||||
|
logger.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${protocols}`);
|
||||||
|
if (this.webSocket) {
|
||||||
|
this.uninstallEventHandlers();
|
||||||
|
}
|
||||||
|
this.webSocket = new adapters.WebSocket(this.consumer.url, protocols);
|
||||||
|
this.installEventHandlers();
|
||||||
|
this.monitor.start();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close({allowReconnect: allowReconnect} = {
|
||||||
|
allowReconnect: true
|
||||||
|
}) {
|
||||||
|
if (!allowReconnect) {
|
||||||
|
this.monitor.stop();
|
||||||
|
}
|
||||||
|
if (this.isOpen()) {
|
||||||
|
return this.webSocket.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reopen() {
|
||||||
|
logger.log(`Reopening WebSocket, current state is ${this.getState()}`);
|
||||||
|
if (this.isActive()) {
|
||||||
|
try {
|
||||||
|
return this.close();
|
||||||
|
} catch (error) {
|
||||||
|
logger.log("Failed to reopen WebSocket", error);
|
||||||
|
} finally {
|
||||||
|
logger.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`);
|
||||||
|
setTimeout(this.open, this.constructor.reopenDelay);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return this.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getProtocol() {
|
||||||
|
if (this.webSocket) {
|
||||||
|
return this.webSocket.protocol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isOpen() {
|
||||||
|
return this.isState("open");
|
||||||
|
}
|
||||||
|
isActive() {
|
||||||
|
return this.isState("open", "connecting");
|
||||||
|
}
|
||||||
|
isProtocolSupported() {
|
||||||
|
return indexOf.call(supportedProtocols, this.getProtocol()) >= 0;
|
||||||
|
}
|
||||||
|
isState(...states) {
|
||||||
|
return indexOf.call(states, this.getState()) >= 0;
|
||||||
|
}
|
||||||
|
getState() {
|
||||||
|
if (this.webSocket) {
|
||||||
|
for (let state in adapters.WebSocket) {
|
||||||
|
if (adapters.WebSocket[state] === this.webSocket.readyState) {
|
||||||
|
return state.toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
installEventHandlers() {
|
||||||
|
for (let eventName in this.events) {
|
||||||
|
const handler = this.events[eventName].bind(this);
|
||||||
|
this.webSocket[`on${eventName}`] = handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uninstallEventHandlers() {
|
||||||
|
for (let eventName in this.events) {
|
||||||
|
this.webSocket[`on${eventName}`] = function() {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection.reopenDelay = 500;
|
||||||
|
|
||||||
|
Connection.prototype.events = {
|
||||||
|
message(event) {
|
||||||
|
if (!this.isProtocolSupported()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const {identifier: identifier, message: message, reason: reason, reconnect: reconnect, type: type} = JSON.parse(event.data);
|
||||||
|
switch (type) {
|
||||||
|
case message_types.welcome:
|
||||||
|
this.monitor.recordConnect();
|
||||||
|
return this.subscriptions.reload();
|
||||||
|
|
||||||
|
case message_types.disconnect:
|
||||||
|
logger.log(`Disconnecting. Reason: ${reason}`);
|
||||||
|
return this.close({
|
||||||
|
allowReconnect: reconnect
|
||||||
|
});
|
||||||
|
|
||||||
|
case message_types.ping:
|
||||||
|
return this.monitor.recordPing();
|
||||||
|
|
||||||
|
case message_types.confirmation:
|
||||||
|
this.subscriptions.confirmSubscription(identifier);
|
||||||
|
return this.subscriptions.notify(identifier, "connected");
|
||||||
|
|
||||||
|
case message_types.rejection:
|
||||||
|
return this.subscriptions.reject(identifier);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return this.subscriptions.notify(identifier, "received", message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
open() {
|
||||||
|
logger.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`);
|
||||||
|
this.disconnected = false;
|
||||||
|
if (!this.isProtocolSupported()) {
|
||||||
|
logger.log("Protocol is unsupported. Stopping monitor and disconnecting.");
|
||||||
|
return this.close({
|
||||||
|
allowReconnect: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
close(event) {
|
||||||
|
logger.log("WebSocket onclose event");
|
||||||
|
if (this.disconnected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.disconnected = true;
|
||||||
|
this.monitor.recordDisconnect();
|
||||||
|
return this.subscriptions.notifyAll("disconnected", {
|
||||||
|
willAttemptReconnect: this.monitor.isRunning()
|
||||||
|
});
|
||||||
|
},
|
||||||
|
error() {
|
||||||
|
logger.log("WebSocket onerror event");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const extend = function(object, properties) {
|
||||||
|
if (properties != null) {
|
||||||
|
for (let key in properties) {
|
||||||
|
const value = properties[key];
|
||||||
|
object[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Subscription {
|
||||||
|
constructor(consumer, params = {}, mixin) {
|
||||||
|
this.consumer = consumer;
|
||||||
|
this.identifier = JSON.stringify(params);
|
||||||
|
extend(this, mixin);
|
||||||
|
}
|
||||||
|
perform(action, data = {}) {
|
||||||
|
data.action = action;
|
||||||
|
return this.send(data);
|
||||||
|
}
|
||||||
|
send(data) {
|
||||||
|
return this.consumer.send({
|
||||||
|
command: "message",
|
||||||
|
identifier: this.identifier,
|
||||||
|
data: JSON.stringify(data)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
unsubscribe() {
|
||||||
|
return this.consumer.subscriptions.remove(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubscriptionGuarantor {
|
||||||
|
constructor(subscriptions) {
|
||||||
|
this.subscriptions = subscriptions;
|
||||||
|
this.pendingSubscriptions = [];
|
||||||
|
}
|
||||||
|
guarantee(subscription) {
|
||||||
|
if (this.pendingSubscriptions.indexOf(subscription) == -1) {
|
||||||
|
logger.log(`SubscriptionGuarantor guaranteeing ${subscription.identifier}`);
|
||||||
|
this.pendingSubscriptions.push(subscription);
|
||||||
|
} else {
|
||||||
|
logger.log(`SubscriptionGuarantor already guaranteeing ${subscription.identifier}`);
|
||||||
|
}
|
||||||
|
this.startGuaranteeing();
|
||||||
|
}
|
||||||
|
forget(subscription) {
|
||||||
|
logger.log(`SubscriptionGuarantor forgetting ${subscription.identifier}`);
|
||||||
|
this.pendingSubscriptions = this.pendingSubscriptions.filter((s => s !== subscription));
|
||||||
|
}
|
||||||
|
startGuaranteeing() {
|
||||||
|
this.stopGuaranteeing();
|
||||||
|
this.retrySubscribing();
|
||||||
|
}
|
||||||
|
stopGuaranteeing() {
|
||||||
|
clearTimeout(this.retryTimeout);
|
||||||
|
}
|
||||||
|
retrySubscribing() {
|
||||||
|
this.retryTimeout = setTimeout((() => {
|
||||||
|
if (this.subscriptions && typeof this.subscriptions.subscribe === "function") {
|
||||||
|
this.pendingSubscriptions.map((subscription => {
|
||||||
|
logger.log(`SubscriptionGuarantor resubscribing ${subscription.identifier}`);
|
||||||
|
this.subscriptions.subscribe(subscription);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}), 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Subscriptions {
|
||||||
|
constructor(consumer) {
|
||||||
|
this.consumer = consumer;
|
||||||
|
this.guarantor = new SubscriptionGuarantor(this);
|
||||||
|
this.subscriptions = [];
|
||||||
|
}
|
||||||
|
create(channelName, mixin) {
|
||||||
|
const channel = channelName;
|
||||||
|
const params = typeof channel === "object" ? channel : {
|
||||||
|
channel: channel
|
||||||
|
};
|
||||||
|
const subscription = new Subscription(this.consumer, params, mixin);
|
||||||
|
return this.add(subscription);
|
||||||
|
}
|
||||||
|
add(subscription) {
|
||||||
|
this.subscriptions.push(subscription);
|
||||||
|
this.consumer.ensureActiveConnection();
|
||||||
|
this.notify(subscription, "initialized");
|
||||||
|
this.subscribe(subscription);
|
||||||
|
return subscription;
|
||||||
|
}
|
||||||
|
remove(subscription) {
|
||||||
|
this.forget(subscription);
|
||||||
|
if (!this.findAll(subscription.identifier).length) {
|
||||||
|
this.sendCommand(subscription, "unsubscribe");
|
||||||
|
}
|
||||||
|
return subscription;
|
||||||
|
}
|
||||||
|
reject(identifier) {
|
||||||
|
return this.findAll(identifier).map((subscription => {
|
||||||
|
this.forget(subscription);
|
||||||
|
this.notify(subscription, "rejected");
|
||||||
|
return subscription;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
forget(subscription) {
|
||||||
|
this.guarantor.forget(subscription);
|
||||||
|
this.subscriptions = this.subscriptions.filter((s => s !== subscription));
|
||||||
|
return subscription;
|
||||||
|
}
|
||||||
|
findAll(identifier) {
|
||||||
|
return this.subscriptions.filter((s => s.identifier === identifier));
|
||||||
|
}
|
||||||
|
reload() {
|
||||||
|
return this.subscriptions.map((subscription => this.subscribe(subscription)));
|
||||||
|
}
|
||||||
|
notifyAll(callbackName, ...args) {
|
||||||
|
return this.subscriptions.map((subscription => this.notify(subscription, callbackName, ...args)));
|
||||||
|
}
|
||||||
|
notify(subscription, callbackName, ...args) {
|
||||||
|
let subscriptions;
|
||||||
|
if (typeof subscription === "string") {
|
||||||
|
subscriptions = this.findAll(subscription);
|
||||||
|
} else {
|
||||||
|
subscriptions = [ subscription ];
|
||||||
|
}
|
||||||
|
return subscriptions.map((subscription => typeof subscription[callbackName] === "function" ? subscription[callbackName](...args) : undefined));
|
||||||
|
}
|
||||||
|
subscribe(subscription) {
|
||||||
|
if (this.sendCommand(subscription, "subscribe")) {
|
||||||
|
this.guarantor.guarantee(subscription);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
confirmSubscription(identifier) {
|
||||||
|
logger.log(`Subscription confirmed ${identifier}`);
|
||||||
|
this.findAll(identifier).map((subscription => this.guarantor.forget(subscription)));
|
||||||
|
}
|
||||||
|
sendCommand(subscription, command) {
|
||||||
|
const {identifier: identifier} = subscription;
|
||||||
|
return this.consumer.send({
|
||||||
|
command: command,
|
||||||
|
identifier: identifier
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Consumer {
|
||||||
|
constructor(url) {
|
||||||
|
this._url = url;
|
||||||
|
this.subscriptions = new Subscriptions(this);
|
||||||
|
this.connection = new Connection(this);
|
||||||
|
}
|
||||||
|
get url() {
|
||||||
|
return createWebSocketURL(this._url);
|
||||||
|
}
|
||||||
|
send(data) {
|
||||||
|
return this.connection.send(data);
|
||||||
|
}
|
||||||
|
connect() {
|
||||||
|
return this.connection.open();
|
||||||
|
}
|
||||||
|
disconnect() {
|
||||||
|
return this.connection.close({
|
||||||
|
allowReconnect: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ensureActiveConnection() {
|
||||||
|
if (!this.connection.isActive()) {
|
||||||
|
return this.connection.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createWebSocketURL(url) {
|
||||||
|
if (typeof url === "function") {
|
||||||
|
url = url();
|
||||||
|
}
|
||||||
|
if (url && !/^wss?:/i.test(url)) {
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
a.href = a.href;
|
||||||
|
a.protocol = a.protocol.replace("http", "ws");
|
||||||
|
return a.href;
|
||||||
|
} else {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createConsumer(url = getConfig("url") || INTERNAL.default_mount_path) {
|
||||||
|
return new Consumer(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getConfig(name) {
|
||||||
|
const element = document.head.querySelector(`meta[name='action-cable-${name}']`);
|
||||||
|
if (element) {
|
||||||
|
return element.getAttribute("content");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Connection, ConnectionMonitor, Consumer, INTERNAL, Subscription, SubscriptionGuarantor, Subscriptions, adapters, createConsumer, createWebSocketURL, getConfig, logger };
|
Binary file not shown.
|
@ -0,0 +1,880 @@
|
||||||
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
||||||
|
|
||||||
|
var activestorage = {exports: {}};
|
||||||
|
|
||||||
|
(function (module, exports) {
|
||||||
|
(function(global, factory) {
|
||||||
|
factory(exports) ;
|
||||||
|
})(commonjsGlobal, (function(exports) {
|
||||||
|
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);
|
||||||
|
exports.DirectUpload = DirectUpload;
|
||||||
|
exports.start = start;
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}(activestorage, activestorage.exports));
|
||||||
|
|
||||||
|
class AttachmentUpload {
|
||||||
|
constructor(attachment, element) {
|
||||||
|
this.attachment = attachment;
|
||||||
|
this.element = element;
|
||||||
|
this.directUpload = new activestorage.exports.DirectUpload(attachment.file, this.directUploadUrl, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this.directUpload.create(this.directUploadDidComplete.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
directUploadWillStoreFileWithXHR(xhr) {
|
||||||
|
xhr.upload.addEventListener("progress", event => {
|
||||||
|
const progress = event.loaded / event.total * 100;
|
||||||
|
this.attachment.setUploadProgress(progress);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
directUploadDidComplete(error, attributes) {
|
||||||
|
if (error) {
|
||||||
|
throw new Error(`Direct upload failed: ${error}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.attachment.setAttributes({
|
||||||
|
sgid: attributes.attachable_sgid,
|
||||||
|
url: this.createBlobUrl(attributes.signed_id, attributes.filename)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createBlobUrl(signedId, filename) {
|
||||||
|
return this.blobUrlTemplate
|
||||||
|
.replace(":signed_id", signedId)
|
||||||
|
.replace(":filename", encodeURIComponent(filename))
|
||||||
|
}
|
||||||
|
|
||||||
|
get directUploadUrl() {
|
||||||
|
return this.element.dataset.directUploadUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
get blobUrlTemplate() {
|
||||||
|
return this.element.dataset.blobUrlTemplate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addEventListener("trix-attachment-add", event => {
|
||||||
|
const { attachment, target } = event;
|
||||||
|
|
||||||
|
if (attachment.file) {
|
||||||
|
const upload = new AttachmentUpload(attachment, target);
|
||||||
|
upload.start();
|
||||||
|
}
|
||||||
|
});
|
Binary file not shown.
|
@ -0,0 +1,823 @@
|
||||||
|
(function(global, factory) {
|
||||||
|
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";
|
||||||
|
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);
|
||||||
|
exports.DirectUpload = DirectUpload;
|
||||||
|
exports.start = start;
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
}));
|
Binary file not shown.
|
@ -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 };
|
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -0,0 +1,476 @@
|
||||||
|
function geojsonDaten() {
|
||||||
|
return {
|
||||||
|
"type": "FeatureCollection",
|
||||||
|
"features": [
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Stadtbezirksbeirat Mitte",
|
||||||
|
"raum": "Neues Rathaus, Zi. 495",
|
||||||
|
"ort": "Martin-Luther-Ring 4-6, 04109 Leipzig",
|
||||||
|
"typ": "Stadtbezirksbeirat",
|
||||||
|
"id": "2350"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.3726786,
|
||||||
|
51.3360228
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Stadtbezirksbeirat Nordost",
|
||||||
|
"raum": "Rathaus Schönefeld, Raum 100",
|
||||||
|
"ort": "Ossietzkystraße 37, 04347 Leipzig",
|
||||||
|
"typ": "Stadtbezirksbeirat",
|
||||||
|
"id": "2284"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.4106166658912,
|
||||||
|
51.35950645
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Stadtbezirksbeirat Ost",
|
||||||
|
"raum": "IC-E Informationszentrum",
|
||||||
|
"ort": "Eisenbahnstraße 49, 04315 Leipzig",
|
||||||
|
"typ": "Stadtbezirksbeirat",
|
||||||
|
"id": "2295"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.4022556,
|
||||||
|
51.3458445
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Stadtbezirksbeirat Südost",
|
||||||
|
"raum": "Franz-Mehring-Schule",
|
||||||
|
"ort": "Gletschersteinstraße 9, 04299 Leipzig",
|
||||||
|
"typ": "Stadtbezirksbeirat",
|
||||||
|
"id": "2324"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.425064636414,
|
||||||
|
51.3165416
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Stadtbezirksbeirat Süd",
|
||||||
|
"raum": "Immanuel-Kant-Gymnasium, Zi. 024",
|
||||||
|
"ort": "Scharnhorststraße 15, 04275 Leipzig",
|
||||||
|
"typ": "Stadtbezirksbeirat",
|
||||||
|
"id": "2369"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.3724315691414,
|
||||||
|
51.3199336
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Stadtbezirksbeirat Südwest",
|
||||||
|
"raum": "Schule am Adler - Oberschule, Erdgeschoss - Raum 10",
|
||||||
|
"ort": "Antonienstraße 24, 04229 Leipzig",
|
||||||
|
"typ": "Stadtbezirksbeirat",
|
||||||
|
"id": "2309"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.3293545312521,
|
||||||
|
51.3209155
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Stadtbezirksbeirat West",
|
||||||
|
"raum": "Freizeittreff \"Völkerfreundschaft\", Großer Saal",
|
||||||
|
"ort": "Stuttgarter Allee 9, 04209 Leipzig",
|
||||||
|
"typ": "Stadtbezirksbeirat",
|
||||||
|
"id": "2282"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.2915533009981,
|
||||||
|
51.3156583
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Stadtbezirksbeirat Alt-West",
|
||||||
|
"raum": "Rathaus Leutzsch, Beratungsraum 1. Etage",
|
||||||
|
"ort": "Georg-Schwarz-Straße 140, 04179 Leipzig",
|
||||||
|
"typ": "Stadtbezirksbeirat",
|
||||||
|
"id": "2271"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.3138069902423,
|
||||||
|
51.34783805
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Stadtbezirksbeirat Nordwest",
|
||||||
|
"raum": "Stadtteilzentrum \"ANKER\"",
|
||||||
|
"ort": "Renftstraße 1, 04159 Leipzig",
|
||||||
|
"typ": "Stadtbezirksbeirat",
|
||||||
|
"id": "2250"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.3430596,
|
||||||
|
51.3675295
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Stadtbezirksbeirat Nord",
|
||||||
|
"raum": "Gohlis-Center, Zi. 340",
|
||||||
|
"ort": "Elsbethstraße 19-25, 04155 Leipzig",
|
||||||
|
"typ": "Stadtbezirksbeirat",
|
||||||
|
"id": "2272"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.3643525,
|
||||||
|
51.3634285
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Ortschaftsrat Böhlitz-Ehrenberg",
|
||||||
|
"raum": "Große Eiche, Salon Böhlitz",
|
||||||
|
"ort": "Leipziger Straße 81, 04178 Leipzig",
|
||||||
|
"typ": "Ortschaftsrat",
|
||||||
|
"id": "2261"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.2907928,
|
||||||
|
51.3595433
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Ortschaftsrat Burghausen",
|
||||||
|
"raum": "ehem. Gemeindeamt Burghausen, Sitzungszimmer",
|
||||||
|
"ort": "Miltitzer Straße 1, 04178 Leipzig",
|
||||||
|
"typ": "Ortschaftsrat",
|
||||||
|
"id": "2259"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.2649439543724,
|
||||||
|
51.35492225
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Ortschaftsrat Engelsdorf",
|
||||||
|
"raum": "Versammlungsraum des Ortschaftsrates Engelsdorf",
|
||||||
|
"ort": "Engelsdorfer Str. 345, 04319 Leipzig",
|
||||||
|
"typ": "Ortschaftsrat",
|
||||||
|
"id": "2336"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.4901256,
|
||||||
|
51.3390546
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Ortschaftsrat Hartmannsdorf-Knautnaundorf",
|
||||||
|
"raum": "Gaststätte \"Zur Ratte\"",
|
||||||
|
"ort": "Erikenstraße 10, 04249 Leipzig",
|
||||||
|
"typ": "Ortschaftsrat",
|
||||||
|
"id": "2283"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.3086769,
|
||||||
|
51.2653949
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Ortschaftsrat Holzhausen",
|
||||||
|
"raum": "Schule Holzhausen, Aula",
|
||||||
|
"ort": "Stötteritzer Landstraße 21, 04288 Leipzig",
|
||||||
|
"typ": "Ortschaftsrat",
|
||||||
|
"id": "2262"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.4658203,
|
||||||
|
51.3049215
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Ortschaftsrat Liebertwolkwitz",
|
||||||
|
"raum": "Rathaus Liebertwolkwitz, Zi. 2",
|
||||||
|
"ort": "Liebertwolkwitzer Markt 1, 04288 Leipzig",
|
||||||
|
"typ": "Ortschaftsrat",
|
||||||
|
"id": "2330"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.4642926352189,
|
||||||
|
51.28270915
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Ortschaftsrat Lindenthal",
|
||||||
|
"raum": "Rathaus Lindenthal, Ratssaal",
|
||||||
|
"ort": "Erich-Thiele-Str. 2, 04159 Leipzig",
|
||||||
|
"typ": "Ortschaftsrat",
|
||||||
|
"id": "2316"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.327974438667297,
|
||||||
|
51.392381000768204
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Ortschaftsrat Lützschena-Stahmeln",
|
||||||
|
"raum": "ehem. Feuerwehrgerätehaus Stahmeln",
|
||||||
|
"ort": "Mühlenstraße 21, 04159 Leipzig",
|
||||||
|
"typ": "Ortschaftsrat",
|
||||||
|
"id": "2368"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.3011131,
|
||||||
|
51.3766107
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Ortschaftsrat Miltitz",
|
||||||
|
"raum": "Grundschule Miltitz, Speiseraum",
|
||||||
|
"ort": "Großmiltitzer Straße 4, 04205 Leipzig",
|
||||||
|
"typ": "Ortschaftsrat",
|
||||||
|
"id": "2365"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.2615069,
|
||||||
|
51.319427
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Ortschaftsrat Mölkau",
|
||||||
|
"raum": "ehem. Gemeindeamt Mölkau, Ratssaal",
|
||||||
|
"ort": "Engelsdorfer Straße 90, 04316 Leipzig",
|
||||||
|
"typ": "Ortschaftsrat",
|
||||||
|
"id": "2255"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.441776,
|
||||||
|
51.3310749
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Ortschaftsrat Plaußig ",
|
||||||
|
"raum": "Naturschutzstation Plaußig, Schulungsraum",
|
||||||
|
"ort": "Plaußiger Dorfstraße 23, 04349 Leipzig",
|
||||||
|
"typ": "Ortschaftsrat",
|
||||||
|
"id": "2377"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.4557221,
|
||||||
|
51.3922605
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Ortschaftsrat Rückmarsdorf ",
|
||||||
|
"raum": "Ortsteilzentrum Rückmarsdorf",
|
||||||
|
"ort": "Ehrenberger Straße 5a, 04178 Leipzig",
|
||||||
|
"typ": "Ortschaftsrat",
|
||||||
|
"id": "2276"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.2784925298815,
|
||||||
|
51.34322465
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Ortschaftsrat Seehausen",
|
||||||
|
"raum": "Gasthof Hohenheida",
|
||||||
|
"ort": "Am Anger 42, 04356 Leipzig",
|
||||||
|
"typ": "Ortschaftsrat",
|
||||||
|
"id": "2312"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.4455644647629,
|
||||||
|
51.4203442
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Ortschaftsrat Wiederitzsch",
|
||||||
|
"raum": "Rathaus Wiederitzsch, Rathaussaal",
|
||||||
|
"ort": "Delitzscher Landstraße 55, 04158 Leipzig",
|
||||||
|
"typ": "Ortschaftsrat",
|
||||||
|
"id": "2304"
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [
|
||||||
|
12.3737383807901,
|
||||||
|
51.3935912
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var locked = null
|
||||||
|
var popUp;
|
||||||
|
|
||||||
|
var hoverToMarkerOffset = function (currentZoomLevel) {
|
||||||
|
return 0.39 / Math.pow(2, currentZoomLevel - 6);
|
||||||
|
};
|
||||||
|
|
||||||
|
var registerListeners = function (map, geojsonLayer) {
|
||||||
|
|
||||||
|
geojsonLayer.on('mouseover', function (event) {
|
||||||
|
var coords = event.layer.feature.geometry.coordinates;
|
||||||
|
if (map && (coords != locked)) {
|
||||||
|
hidePopUp(map);
|
||||||
|
showPopUp(map, event);
|
||||||
|
locked = coords;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
geojsonLayer.on('click', function (event) {
|
||||||
|
if (popUp && map) {
|
||||||
|
var coords = event.layer.feature.geometry.coordinates;
|
||||||
|
if (locked == coords) {
|
||||||
|
locked = null;
|
||||||
|
} else {
|
||||||
|
showPopUp(map, event);
|
||||||
|
locked = coords;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPopUp(map, event) {
|
||||||
|
var coords = event.layer.feature.geometry.coordinates;
|
||||||
|
var popUpCoords = [coords[1] + hoverToMarkerOffset(map.getZoom()), coords[0]];
|
||||||
|
var properties = event.layer.feature.properties
|
||||||
|
popUp = L.popup()
|
||||||
|
.setLatLng(popUpCoords)
|
||||||
|
.setContent(createPopUpContent(properties))
|
||||||
|
.openOn(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hidePopUp(map) {
|
||||||
|
map.closePopup(popUp);
|
||||||
|
popUp = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPopUpContent(properties) {
|
||||||
|
var content = "<b>" + properties.name + "</b>";
|
||||||
|
content += "<br />";
|
||||||
|
content += "<span style=\"text-decoration: underline;\">Adresse:</span> "
|
||||||
|
content += properties.ort
|
||||||
|
content += "<br />"
|
||||||
|
content += "<span style=\"text-decoration: underline;\">Raum:</span> "
|
||||||
|
content += properties.raum
|
||||||
|
content += "<ul>"
|
||||||
|
content += "<li><a href=\"https://ratsinfo.leipzig.de/bi/au020.asp?AULFDNR=" + properties.id + "\">Mitglieder</a></li>"
|
||||||
|
content += "<li><a href=\"https://ratsinfo.leipzig.de/bi/si018_a.asp?GRA=" + properties.id + "\">Sitzungen</a></li>"
|
||||||
|
content += "</ul>"
|
||||||
|
return content
|
||||||
|
};
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 696 B |
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
|
@ -0,0 +1,8 @@
|
||||||
|
// JS and CSS bundles
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Images and fonts so that views can link to them
|
||||||
|
//;
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 618 B |
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
@ -0,0 +1,375 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
Trix 1.3.1
|
||||||
|
Copyright © 2020 Basecamp, LLC
|
||||||
|
http://trix-editor.org/*/
|
||||||
|
trix-editor {
|
||||||
|
border: 1px solid #bbb;
|
||||||
|
border-radius: 3px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.4em 0.6em;
|
||||||
|
min-height: 5em;
|
||||||
|
outline: none; }
|
||||||
|
trix-toolbar * {
|
||||||
|
box-sizing: border-box; }
|
||||||
|
trix-toolbar .trix-button-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
overflow-x: auto; }
|
||||||
|
trix-toolbar .trix-button-group {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border: 1px solid #bbb;
|
||||||
|
border-top-color: #ccc;
|
||||||
|
border-bottom-color: #888;
|
||||||
|
border-radius: 3px; }
|
||||||
|
trix-toolbar .trix-button-group:not(:first-child) {
|
||||||
|
margin-left: 1.5vw; }
|
||||||
|
@media (max-device-width: 768px) {
|
||||||
|
trix-toolbar .trix-button-group:not(:first-child) {
|
||||||
|
margin-left: 0; } }
|
||||||
|
trix-toolbar .trix-button-group-spacer {
|
||||||
|
flex-grow: 1; }
|
||||||
|
@media (max-device-width: 768px) {
|
||||||
|
trix-toolbar .trix-button-group-spacer {
|
||||||
|
display: none; } }
|
||||||
|
trix-toolbar .trix-button {
|
||||||
|
position: relative;
|
||||||
|
float: left;
|
||||||
|
color: rgba(0, 0, 0, 0.6);
|
||||||
|
font-size: 0.75em;
|
||||||
|
font-weight: 600;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 0 0.5em;
|
||||||
|
margin: 0;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
border-radius: 0;
|
||||||
|
background: transparent; }
|
||||||
|
trix-toolbar .trix-button:not(:first-child) {
|
||||||
|
border-left: 1px solid #ccc; }
|
||||||
|
trix-toolbar .trix-button.trix-active {
|
||||||
|
background: #cbeefa;
|
||||||
|
color: black; }
|
||||||
|
trix-toolbar .trix-button:not(:disabled) {
|
||||||
|
cursor: pointer; }
|
||||||
|
trix-toolbar .trix-button:disabled {
|
||||||
|
color: rgba(0, 0, 0, 0.125); }
|
||||||
|
@media (max-device-width: 768px) {
|
||||||
|
trix-toolbar .trix-button {
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
padding: 0 0.3em; } }
|
||||||
|
trix-toolbar .trix-button--icon {
|
||||||
|
font-size: inherit;
|
||||||
|
width: 2.6em;
|
||||||
|
height: 1.6em;
|
||||||
|
max-width: calc(0.8em + 4vw);
|
||||||
|
text-indent: -9999px; }
|
||||||
|
@media (max-device-width: 768px) {
|
||||||
|
trix-toolbar .trix-button--icon {
|
||||||
|
height: 2em;
|
||||||
|
max-width: calc(0.8em + 3.5vw); } }
|
||||||
|
trix-toolbar .trix-button--icon::before {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
opacity: 0.6;
|
||||||
|
content: "";
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: contain; }
|
||||||
|
@media (max-device-width: 768px) {
|
||||||
|
trix-toolbar .trix-button--icon::before {
|
||||||
|
right: 6%;
|
||||||
|
left: 6%; } }
|
||||||
|
trix-toolbar .trix-button--icon.trix-active::before {
|
||||||
|
opacity: 1; }
|
||||||
|
trix-toolbar .trix-button--icon:disabled::before {
|
||||||
|
opacity: 0.125; }
|
||||||
|
trix-toolbar .trix-button--icon-attach::before {
|
||||||
|
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M16.5%206v11.5a4%204%200%201%201-8%200V5a2.5%202.5%200%200%201%205%200v10.5a1%201%200%201%201-2%200V6H10v9.5a2.5%202.5%200%200%200%205%200V5a4%204%200%201%200-8%200v12.5a5.5%205.5%200%200%200%2011%200V6h-1.5z%22%2F%3E%3C%2Fsvg%3E);
|
||||||
|
top: 8%;
|
||||||
|
bottom: 4%; }
|
||||||
|
trix-toolbar .trix-button--icon-bold::before {
|
||||||
|
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M15.6%2011.8c1-.7%201.6-1.8%201.6-2.8a4%204%200%200%200-4-4H7v14h7c2.1%200%203.7-1.7%203.7-3.8%200-1.5-.8-2.8-2.1-3.4zM10%207.5h3a1.5%201.5%200%201%201%200%203h-3v-3zm3.5%209H10v-3h3.5a1.5%201.5%200%201%201%200%203z%22%2F%3E%3C%2Fsvg%3E); }
|
||||||
|
trix-toolbar .trix-button--icon-italic::before {
|
||||||
|
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M10%205v3h2.2l-3.4%208H6v3h8v-3h-2.2l3.4-8H18V5h-8z%22%2F%3E%3C%2Fsvg%3E); }
|
||||||
|
trix-toolbar .trix-button--icon-link::before {
|
||||||
|
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M9.88%2013.7a4.3%204.3%200%200%201%200-6.07l3.37-3.37a4.26%204.26%200%200%201%206.07%200%204.3%204.3%200%200%201%200%206.06l-1.96%201.72a.91.91%200%201%201-1.3-1.3l1.97-1.71a2.46%202.46%200%200%200-3.48-3.48l-3.38%203.37a2.46%202.46%200%200%200%200%203.48.91.91%200%201%201-1.3%201.3z%22%2F%3E%3Cpath%20d%3D%22M4.25%2019.46a4.3%204.3%200%200%201%200-6.07l1.93-1.9a.91.91%200%201%201%201.3%201.3l-1.93%201.9a2.46%202.46%200%200%200%203.48%203.48l3.37-3.38c.96-.96.96-2.52%200-3.48a.91.91%200%201%201%201.3-1.3%204.3%204.3%200%200%201%200%206.07l-3.38%203.38a4.26%204.26%200%200%201-6.07%200z%22%2F%3E%3C%2Fsvg%3E); }
|
||||||
|
trix-toolbar .trix-button--icon-strike::before {
|
||||||
|
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M12.73%2014l.28.14c.26.15.45.3.57.44.12.14.18.3.18.5%200%20.3-.15.56-.44.75-.3.2-.76.3-1.39.3A13.52%2013.52%200%200%201%207%2014.95v3.37a10.64%2010.64%200%200%200%204.84.88c1.26%200%202.35-.19%203.28-.56.93-.37%201.64-.9%202.14-1.57s.74-1.45.74-2.32c0-.26-.02-.51-.06-.75h-5.21zm-5.5-4c-.08-.34-.12-.7-.12-1.1%200-1.29.52-2.3%201.58-3.02%201.05-.72%202.5-1.08%204.34-1.08%201.62%200%203.28.34%204.97%201l-1.3%202.93c-1.47-.6-2.73-.9-3.8-.9-.55%200-.96.08-1.2.26-.26.17-.38.38-.38.64%200%20.27.16.52.48.74.17.12.53.3%201.05.53H7.23zM3%2013h18v-2H3v2z%22%2F%3E%3C%2Fsvg%3E); }
|
||||||
|
trix-toolbar .trix-button--icon-quote::before {
|
||||||
|
background-image: url(data:image/svg+xml,%3Csvg%20version%3D%221%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M6%2017h3l2-4V7H5v6h3zm8%200h3l2-4V7h-6v6h3z%22%2F%3E%3C%2Fsvg%3E); }
|
||||||
|
trix-toolbar .trix-button--icon-heading-1::before {
|
||||||
|
background-image: url(data:image/svg+xml,%3Csvg%20version%3D%221%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M12%209v3H9v7H6v-7H3V9h9zM8%204h14v3h-6v12h-3V7H8V4z%22%2F%3E%3C%2Fsvg%3E); }
|
||||||
|
trix-toolbar .trix-button--icon-code::before {
|
||||||
|
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M18.2%2012L15%2015.2l1.4%201.4L21%2012l-4.6-4.6L15%208.8l3.2%203.2zM5.8%2012L9%208.8%207.6%207.4%203%2012l4.6%204.6L9%2015.2%205.8%2012z%22%2F%3E%3C%2Fsvg%3E); }
|
||||||
|
trix-toolbar .trix-button--icon-bullet-list::before {
|
||||||
|
background-image: url(data:image/svg+xml,%3Csvg%20version%3D%221%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%204a2%202%200%201%200%200%204%202%202%200%200%200%200-4zm0%206a2%202%200%201%200%200%204%202%202%200%200%200%200-4zm0%206a2%202%200%201%200%200%204%202%202%200%200%200%200-4zm4%203h14v-2H8v2zm0-6h14v-2H8v2zm0-8v2h14V5H8z%22%2F%3E%3C%2Fsvg%3E); }
|
||||||
|
trix-toolbar .trix-button--icon-number-list::before {
|
||||||
|
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M2%2017h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1%203h1.8L2%2013.1v.9h3v-1H3.2L5%2010.9V10H2v1zm5-6v2h14V5H7zm0%2014h14v-2H7v2zm0-6h14v-2H7v2z%22%2F%3E%3C%2Fsvg%3E); }
|
||||||
|
trix-toolbar .trix-button--icon-undo::before {
|
||||||
|
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M12.5%208c-2.6%200-5%201-6.9%202.6L2%207v9h9l-3.6-3.6A8%208%200%200%201%2020%2016l2.4-.8a10.5%2010.5%200%200%200-10-7.2z%22%2F%3E%3C%2Fsvg%3E); }
|
||||||
|
trix-toolbar .trix-button--icon-redo::before {
|
||||||
|
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M18.4%2010.6a10.5%2010.5%200%200%200-16.9%204.6L4%2016a8%208%200%200%201%2012.7-3.6L13%2016h9V7l-3.6%203.6z%22%2F%3E%3C%2Fsvg%3E); }
|
||||||
|
trix-toolbar .trix-button--icon-decrease-nesting-level::before {
|
||||||
|
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M3%2019h19v-2H3v2zm7-6h12v-2H10v2zm-8.3-.3l2.8%202.9L6%2014.2%204%2012l2-2-1.4-1.5L1%2012l.7.7zM3%205v2h19V5H3z%22%2F%3E%3C%2Fsvg%3E); }
|
||||||
|
trix-toolbar .trix-button--icon-increase-nesting-level::before {
|
||||||
|
background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M3%2019h19v-2H3v2zm7-6h12v-2H10v2zm-6.9-1L1%2014.2l1.4%201.4L6%2012l-.7-.7-2.8-2.8L1%209.9%203.1%2012zM3%205v2h19V5H3z%22%2F%3E%3C%2Fsvg%3E); }
|
||||||
|
trix-toolbar .trix-dialogs {
|
||||||
|
position: relative; }
|
||||||
|
trix-toolbar .trix-dialog {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
font-size: 0.75em;
|
||||||
|
padding: 15px 10px;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 0.3em 1em #ccc;
|
||||||
|
border-top: 2px solid #888;
|
||||||
|
border-radius: 5px;
|
||||||
|
z-index: 5; }
|
||||||
|
trix-toolbar .trix-input--dialog {
|
||||||
|
font-size: inherit;
|
||||||
|
font-weight: normal;
|
||||||
|
padding: 0.5em 0.8em;
|
||||||
|
margin: 0 10px 0 0;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid #bbb;
|
||||||
|
background-color: #fff;
|
||||||
|
box-shadow: none;
|
||||||
|
outline: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none; }
|
||||||
|
trix-toolbar .trix-input--dialog.validate:invalid {
|
||||||
|
box-shadow: #F00 0px 0px 1.5px 1px; }
|
||||||
|
trix-toolbar .trix-button--dialog {
|
||||||
|
font-size: inherit;
|
||||||
|
padding: 0.5em;
|
||||||
|
border-bottom: none; }
|
||||||
|
trix-toolbar .trix-dialog--link {
|
||||||
|
max-width: 600px; }
|
||||||
|
trix-toolbar .trix-dialog__link-fields {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline; }
|
||||||
|
trix-toolbar .trix-dialog__link-fields .trix-input {
|
||||||
|
flex: 1; }
|
||||||
|
trix-toolbar .trix-dialog__link-fields .trix-button-group {
|
||||||
|
flex: 0 0 content;
|
||||||
|
margin: 0; }
|
||||||
|
trix-editor [data-trix-mutable]:not(.attachment__caption-editor) {
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none; }
|
||||||
|
|
||||||
|
trix-editor [data-trix-mutable]::-moz-selection,
|
||||||
|
trix-editor [data-trix-cursor-target]::-moz-selection, trix-editor [data-trix-mutable] ::-moz-selection {
|
||||||
|
background: none; }
|
||||||
|
trix-editor [data-trix-mutable]::selection,
|
||||||
|
trix-editor [data-trix-cursor-target]::selection, trix-editor [data-trix-mutable] ::selection {
|
||||||
|
background: none; }
|
||||||
|
|
||||||
|
trix-editor [data-trix-mutable].attachment__caption-editor:focus::-moz-selection {
|
||||||
|
background: highlight; }
|
||||||
|
trix-editor [data-trix-mutable].attachment__caption-editor:focus::selection {
|
||||||
|
background: highlight; }
|
||||||
|
|
||||||
|
trix-editor [data-trix-mutable].attachment.attachment--file {
|
||||||
|
box-shadow: 0 0 0 2px highlight;
|
||||||
|
border-color: transparent; }
|
||||||
|
trix-editor [data-trix-mutable].attachment img {
|
||||||
|
box-shadow: 0 0 0 2px highlight; }
|
||||||
|
trix-editor .attachment {
|
||||||
|
position: relative; }
|
||||||
|
trix-editor .attachment:hover {
|
||||||
|
cursor: default; }
|
||||||
|
trix-editor .attachment--preview .attachment__caption:hover {
|
||||||
|
cursor: text; }
|
||||||
|
trix-editor .attachment__progress {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
height: 20px;
|
||||||
|
top: calc(50% - 10px);
|
||||||
|
left: 5%;
|
||||||
|
width: 90%;
|
||||||
|
opacity: 0.9;
|
||||||
|
transition: opacity 200ms ease-in; }
|
||||||
|
trix-editor .attachment__progress[value="100"] {
|
||||||
|
opacity: 0; }
|
||||||
|
trix-editor .attachment__caption-editor {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-size: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
color: inherit;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: top;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none; }
|
||||||
|
trix-editor .attachment__toolbar {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
top: -0.9em;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center; }
|
||||||
|
trix-editor .trix-button-group {
|
||||||
|
display: inline-flex; }
|
||||||
|
trix-editor .trix-button {
|
||||||
|
position: relative;
|
||||||
|
float: left;
|
||||||
|
color: #666;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 80%;
|
||||||
|
padding: 0 0.8em;
|
||||||
|
margin: 0;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
background: transparent; }
|
||||||
|
trix-editor .trix-button:not(:first-child) {
|
||||||
|
border-left: 1px solid #ccc; }
|
||||||
|
trix-editor .trix-button.trix-active {
|
||||||
|
background: #cbeefa; }
|
||||||
|
trix-editor .trix-button:not(:disabled) {
|
||||||
|
cursor: pointer; }
|
||||||
|
trix-editor .trix-button--remove {
|
||||||
|
text-indent: -9999px;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0;
|
||||||
|
outline: none;
|
||||||
|
width: 1.8em;
|
||||||
|
height: 1.8em;
|
||||||
|
line-height: 1.8em;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 2px solid highlight;
|
||||||
|
box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.25); }
|
||||||
|
trix-editor .trix-button--remove::before {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
opacity: 0.7;
|
||||||
|
content: "";
|
||||||
|
background-image: url(data:image/svg+xml,%3Csvg%20height%3D%2224%22%20width%3D%2224%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M19%206.4L17.6%205%2012%2010.6%206.4%205%205%206.4l5.6%205.6L5%2017.6%206.4%2019l5.6-5.6%205.6%205.6%201.4-1.4-5.6-5.6z%22%2F%3E%3Cpath%20d%3D%22M0%200h24v24H0z%22%20fill%3D%22none%22%2F%3E%3C%2Fsvg%3E);
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 90%; }
|
||||||
|
trix-editor .trix-button--remove:hover {
|
||||||
|
border-color: #333; }
|
||||||
|
trix-editor .trix-button--remove:hover::before {
|
||||||
|
opacity: 1; }
|
||||||
|
trix-editor .attachment__metadata-container {
|
||||||
|
position: relative; }
|
||||||
|
trix-editor .attachment__metadata {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 2em;
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
max-width: 90%;
|
||||||
|
padding: 0.1em 0.6em;
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #fff;
|
||||||
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
|
border-radius: 3px; }
|
||||||
|
trix-editor .attachment__metadata .attachment__name {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 100%;
|
||||||
|
vertical-align: bottom;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap; }
|
||||||
|
trix-editor .attachment__metadata .attachment__size {
|
||||||
|
margin-left: 0.2em;
|
||||||
|
white-space: nowrap; }
|
||||||
|
@charset "UTF-8";
|
||||||
|
.trix-content {
|
||||||
|
line-height: 1.5; }
|
||||||
|
.trix-content * {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0; }
|
||||||
|
.trix-content h1 {
|
||||||
|
font-size: 1.2em;
|
||||||
|
line-height: 1.2; }
|
||||||
|
.trix-content blockquote {
|
||||||
|
border: 0 solid #ccc;
|
||||||
|
border-left-width: 0.3em;
|
||||||
|
margin-left: 0.3em;
|
||||||
|
padding-left: 0.6em; }
|
||||||
|
.trix-content [dir=rtl] blockquote,
|
||||||
|
.trix-content blockquote[dir=rtl] {
|
||||||
|
border-width: 0;
|
||||||
|
border-right-width: 0.3em;
|
||||||
|
margin-right: 0.3em;
|
||||||
|
padding-right: 0.6em; }
|
||||||
|
.trix-content li {
|
||||||
|
margin-left: 1em; }
|
||||||
|
.trix-content [dir=rtl] li {
|
||||||
|
margin-right: 1em; }
|
||||||
|
.trix-content pre {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
vertical-align: top;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 0.9em;
|
||||||
|
padding: 0.5em;
|
||||||
|
white-space: pre;
|
||||||
|
background-color: #eee;
|
||||||
|
overflow-x: auto; }
|
||||||
|
.trix-content img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto; }
|
||||||
|
.trix-content .attachment {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
max-width: 100%; }
|
||||||
|
.trix-content .attachment a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none; }
|
||||||
|
.trix-content .attachment a:hover, .trix-content .attachment a:visited:hover {
|
||||||
|
color: inherit; }
|
||||||
|
.trix-content .attachment__caption {
|
||||||
|
text-align: center; }
|
||||||
|
.trix-content .attachment__caption .attachment__name + .attachment__size::before {
|
||||||
|
content: ' · '; }
|
||||||
|
.trix-content .attachment--preview {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center; }
|
||||||
|
.trix-content .attachment--preview .attachment__caption {
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.9em;
|
||||||
|
line-height: 1.2; }
|
||||||
|
.trix-content .attachment--file {
|
||||||
|
color: #333;
|
||||||
|
line-height: 1;
|
||||||
|
margin: 0 2px 2px 2px;
|
||||||
|
padding: 0.4em 1em;
|
||||||
|
border: 1px solid #bbb;
|
||||||
|
border-radius: 5px; }
|
||||||
|
.trix-content .attachment-gallery {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
position: relative; }
|
||||||
|
.trix-content .attachment-gallery .attachment {
|
||||||
|
flex: 1 0 33%;
|
||||||
|
padding: 0 0.5em;
|
||||||
|
max-width: 33%; }
|
||||||
|
.trix-content .attachment-gallery.attachment-gallery--2 .attachment, .trix-content .attachment-gallery.attachment-gallery--4 .attachment {
|
||||||
|
flex-basis: 50%;
|
||||||
|
max-width: 50%; }
|
Binary file not shown.
Loading…
Reference in a new issue