mirror of
https://github.com/CodeforLeipzig/stadtratmonitor.git
synced 2024-12-21 23:33:14 +01:00
update to node 18
This commit is contained in:
parent
30fb4b37a0
commit
168149936c
57 changed files with 53882 additions and 31 deletions
|
@ -1 +1 @@
|
|||
3.2.2
|
||||
3.0.2
|
||||
|
|
22
Dockerfile
22
Dockerfile
|
@ -1,14 +1,14 @@
|
|||
FROM amd64/ruby:3.2.2-bullseye
|
||||
FROM ubuntu:latest
|
||||
|
||||
RUN apt-get update && apt-get install -y curl
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -
|
||||
|
||||
RUN apt-get update && apt-get install -y ruby ruby-dev ruby-bundler \
|
||||
build-essential zlib1g-dev libsqlite3-dev libxml2-dev libxslt1-dev pkg-config nodejs
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
RUN gem install bundler
|
||||
|
||||
# Add google package repository for google chrome
|
||||
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
|
||||
&& echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y build-essential zlib1g-dev libsqlite3-dev nodejs npm \
|
||||
libxml2-dev libxslt1-dev pkg-config google-chrome-stable
|
||||
|
||||
ENV DOCKERIZE_VERSION v0.6.1
|
||||
RUN curl -sSLO https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
|
||||
&& tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
|
||||
|
@ -19,7 +19,7 @@ RUN mkdir -p /app
|
|||
WORKDIR /tmp
|
||||
|
||||
COPY Gemfile Gemfile
|
||||
#COPY Gemfile.lock Gemfile.lock
|
||||
COPY Gemfile.lock Gemfile.lock
|
||||
RUN bundle config build.nokogiri --use-system-libraries
|
||||
RUN bundle update
|
||||
RUN bundle install
|
||||
|
@ -27,7 +27,7 @@ RUN bundle install
|
|||
ADD . /app
|
||||
WORKDIR /app
|
||||
|
||||
RUN npm install -g yarn
|
||||
RUN npm install -g yarn sass
|
||||
|
||||
COPY ./docker-entrypoint.sh /
|
||||
RUN chmod +x docker-entrypoint.sh
|
||||
|
|
9
Gemfile
9
Gemfile
|
@ -1,6 +1,6 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
ruby "3.2.2"
|
||||
ruby "3.0.2"
|
||||
|
||||
gem 'rails', '~> 7.0.4'
|
||||
gem 'rails-i18n'
|
||||
|
@ -25,9 +25,6 @@ gem 'cssbundling-rails'
|
|||
gem "jsbundling-rails", "~> 1.1"
|
||||
gem 'jquery-rails'
|
||||
gem 'bootstrap'
|
||||
gem "sass", "~> 3.7"
|
||||
gem 'sassc'
|
||||
gem 'sassc-rails'
|
||||
gem "importmap-rails", "~> 1.1"
|
||||
gem 'slim-rails'
|
||||
gem 'turbolinks'
|
||||
|
@ -66,3 +63,7 @@ group :test do
|
|||
gem 'shoulda-matchers', '~> 3.1'
|
||||
gem 'simplecov', require: false
|
||||
end
|
||||
|
||||
gem "dartsass", "~> 1.49"
|
||||
|
||||
gem "tzinfo-data", "~> 1.2023"
|
||||
|
|
18
Gemfile.lock
18
Gemfile.lock
|
@ -100,6 +100,7 @@ GEM
|
|||
crass (1.0.6)
|
||||
cssbundling-rails (1.1.2)
|
||||
railties (>= 6.0.0)
|
||||
dartsass (1.49.8)
|
||||
database_cleaner (2.0.2)
|
||||
database_cleaner-active_record (>= 2, < 3)
|
||||
database_cleaner-active_record (2.1.0)
|
||||
|
@ -284,9 +285,6 @@ GEM
|
|||
zeitwerk (~> 2.5)
|
||||
rainbow (3.1.1)
|
||||
rake (13.0.6)
|
||||
rb-fsevent (0.11.2)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
regexp_parser (2.7.0)
|
||||
rest-client (2.1.0)
|
||||
http-accept (>= 1.7.0, < 2.0)
|
||||
|
@ -328,11 +326,6 @@ GEM
|
|||
rubocop (>= 0.82.0)
|
||||
ruby-progressbar (1.13.0)
|
||||
ruby2_keywords (0.0.5)
|
||||
sass (3.7.4)
|
||||
sass-listen (~> 4.0.0)
|
||||
sass-listen (4.0.0)
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
rb-inotify (~> 0.9, >= 0.9.7)
|
||||
sassc (2.4.0)
|
||||
ffi (~> 1.9)
|
||||
sassc-rails (2.1.2)
|
||||
|
@ -381,6 +374,8 @@ GEM
|
|||
turbolinks-source (5.2.0)
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
tzinfo-data (1.2023.3)
|
||||
tzinfo (>= 1.0.0)
|
||||
uglifier (4.2.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unf (0.1.4)
|
||||
|
@ -407,6 +402,7 @@ DEPENDENCIES
|
|||
capybara
|
||||
coveralls
|
||||
cssbundling-rails
|
||||
dartsass (~> 1.49)
|
||||
database_cleaner
|
||||
elasticsearch (~> 7.10.1)
|
||||
elasticsearch-dsl
|
||||
|
@ -432,9 +428,6 @@ DEPENDENCIES
|
|||
rspec-rails (~> 3.0)
|
||||
rubocop
|
||||
rubocop-faker
|
||||
sass (~> 3.7)
|
||||
sassc
|
||||
sassc-rails
|
||||
shoulda-matchers (~> 3.1)
|
||||
simplecov
|
||||
slim-rails
|
||||
|
@ -442,11 +435,12 @@ DEPENDENCIES
|
|||
spring-commands-rspec
|
||||
sqlite3
|
||||
turbolinks
|
||||
tzinfo-data (~> 1.2023)
|
||||
uglifier
|
||||
validate_url
|
||||
|
||||
RUBY VERSION
|
||||
ruby 3.2.2p53
|
||||
ruby 3.0.2p107
|
||||
|
||||
BUNDLED WITH
|
||||
2.4.10
|
||||
|
|
|
@ -73,9 +73,10 @@ rake assets:clean
|
|||
rake assets:clobber
|
||||
rake tmp:clear
|
||||
|
||||
rails css:install:bootstrap
|
||||
sass ./app/assets/stylesheets/application.bootstrap.scss:./app/assets/builds/application.css --load-path=node_modules
|
||||
rails javascript:install:esbuild
|
||||
npm install -g sass
|
||||
#rails css:install:bootstrap
|
||||
#rails javascript:install:esbuild
|
||||
rake assets:precompile
|
||||
```
|
||||
|
||||
|
||||
|
|
1
app/assets/stylesheets/application.sass.scss
Normal file
1
app/assets/stylesheets/application.sass.scss
Normal file
|
@ -0,0 +1 @@
|
|||
// Entry point for your Sass build
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
export{afterMain,afterRead,afterWrite,auto,basePlacements,beforeMain,beforeRead,beforeWrite,bottom,clippingParents,end,left,main,modifierPhases,placements,popper,read,reference,right,start,top,variationPlacements,viewport,write}from"./enums.js";import"./modifiers/index.js";export{c as createPopperBase,p as popperGenerator}from"../_/1f65884f.js";export{createPopper}from"./popper.js";export{createPopper as createPopperLite}from"./popper-lite.js";export{default as detectOverflow}from"./utils/detectOverflow.js";export{default as applyStyles}from"./modifiers/applyStyles.js";export{default as arrow}from"./modifiers/arrow.js";export{default as computeStyles}from"./modifiers/computeStyles.js";export{default as eventListeners}from"./modifiers/eventListeners.js";export{default as flip}from"./modifiers/flip.js";export{default as hide}from"./modifiers/hide.js";export{default as offset}from"./modifiers/offset.js";export{default as popperOffsets}from"./modifiers/popperOffsets.js";export{default as preventOverflow}from"./modifiers/preventOverflow.js";import"./dom-utils/getCompositeRect.js";import"../_/bde78e08.js";import"./dom-utils/instanceOf.js";import"./dom-utils/getWindow.js";import"../_/69760856.js";import"../_/3601fa6b.js";import"./dom-utils/getNodeScroll.js";import"./dom-utils/getWindowScroll.js";import"./dom-utils/getHTMLElementScroll.js";import"./dom-utils/getNodeName.js";import"./dom-utils/getWindowScrollBarX.js";import"./dom-utils/getDocumentElement.js";import"./dom-utils/isScrollParent.js";import"./dom-utils/getComputedStyle.js";import"./dom-utils/getLayoutRect.js";import"./dom-utils/listScrollParents.js";import"./dom-utils/getScrollParent.js";import"./dom-utils/getParentNode.js";import"./dom-utils/getOffsetParent.js";import"../_/f0637918.js";import"../_/96c549a6.js";import"./dom-utils/getViewportRect.js";import"./dom-utils/getDocumentRect.js";import"../_/63b6cb9b.js";import"../_/c0068ee4.js";import"../_/9a91a998.js";import"./utils/getMainAxisFromPlacement.js";import"../_/c3ec9c52.js";import"../_/dc8ee67b.js";import"./utils/getOppositePlacement.js";import"./utils/getOppositeVariationPlacement.js";import"./utils/computeAutoPlacement.js";
|
Binary file not shown.
|
@ -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 it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
19
public/assets/bootstrap-ae6ca66c9b373fd13a73cfdac892c83d10a73e5ebe9807283d4d1310f3d8c58e.js
vendored
Normal file
19
public/assets/bootstrap-ae6ca66c9b373fd13a73cfdac892c83d10a73e5ebe9807283d4d1310f3d8c58e.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -0,0 +1,2 @@
|
|||
import t from"path";import e from"stylus-type-utils";var n={name:"foundation",version:"4.2.1-1",main:"stylus/foundation",repository:{type:"git",url:"https://github.com/blai/foundation.git"},devDependencies:{grunt:"~0.4.0","grunt-contrib-watch":"~0.1.0","grunt-contrib-qunit":"~0.1.1"},licenses:[{type:"MIT",url:"https://github.com/zurb/foundation/blob/master/LICENSE"}],dependencies:{stylus:"~0.32.1","stylus-type-utils":"~0.0.3"},keywords:["zurb","foundation","stylus","express"]};var s={};var r=t;var i=n;var a=new URL(import.meta.url.slice(0,import.meta.url.lastIndexOf("/"))).pathname;var o=[e];s=s=function plugin(){return function(t){t.include(a);o.forEach((function(e){t.use(e())}))}};s.theme=i.name;s.version=i.version;s.path=a;s.dependencies=o;s.assetPaths=[r.join(new URL(import.meta.url.slice(0,import.meta.url.lastIndexOf("/"))).pathname,"..","js")];var u=s;const p=s.theme,l=s.version,m=s.assetPaths;const c=s.path,d=s.dependencies;export default u;export{m as assetPaths,d as dependencies,c as path,p as theme,l as version};
|
||||
|
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
11008
public/assets/jquery-3158ee616193dde0b605a15cb9ca832f9de674111b7cf4393353432ab8fa272d.js
vendored
Normal file
11008
public/assets/jquery-3158ee616193dde0b605a15cb9ca832f9de674111b7cf4393353432ab8fa272d.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
Binary file not shown.
75
public/assets/jquery-7e3a32706efcf9a09cdea0060f664493d23be51e63c145259fb2b5747fc9d578.js
vendored
Normal file
75
public/assets/jquery-7e3a32706efcf9a09cdea0060f664493d23be51e63c145259fb2b5747fc9d578.js
vendored
Normal file
File diff suppressed because one or more lines are too long
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,2 @@
|
|||
|
||||
|
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 |
|
@ -0,0 +1,2 @@
|
|||
import{e as r}from"../../_/c5b352d6.js";export{e as default}from"../../_/c5b352d6.js";import"../../_/e0803811.js";var a=r._makeLong;var v=r.basename;var o=r.delimiter;var s=r.dirname;var i=r.extname;var m=r.format;var t=r.isAbsolute;var n=r.join;var p=r.normalize;var l=r.parse;var d=r.posix;var b=r.relative;var f=r.resolve;var j=r.sep;var x=r.win32;export{a as _makeLong,v as basename,o as delimiter,s as dirname,i as extname,m as format,t as isAbsolute,n as join,p as normalize,l as parse,d as posix,b as relative,f as resolve,j as sep,x as win32};
|
||||
|
Binary file not shown.
|
@ -0,0 +1,2 @@
|
|||
var e={name:"stylus-type-utils",version:"0.0.3",description:"Stylus typography functions and type conversion",main:"lib/type-utils.js",scripts:{test:"mocha"},repository:{type:"git",url:"git://github.com/blakeembrey/stylus-type-utils.git"},keywords:["stylus","typeograhy","coercion","rem","em","px","pt","percent"],homepage:"https://github.com/blakeembrey/stylus-type-utils",author:"Blake Embrey",license:"MIT",readmeFilename:"Readme.md",peerDependencies:{stylus:"0.x"},devDependencies:{stylus:"~0.32.0"}};var t={};var s=t=function plugin(){return function(e){e.include(new URL(import.meta.url.slice(0,import.meta.url.lastIndexOf("/"))).pathname);e.import("type-utils")}};s.path=new URL(import.meta.url.slice(0,import.meta.url.lastIndexOf("/"))).pathname;s.version=e.version;var i=t;export default i;
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
@ -0,0 +1,376 @@
|
|||
|
||||
/*
|
||||
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;
|
||||
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]::-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