diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
index 0a86376..744012a 100644
--- a/.idea/dataSources.xml
+++ b/.idea/dataSources.xml
@@ -1,12 +1,17 @@
-
+
sqlite.xerial
true
org.sqlite.JDBC
- jdbc:sqlite:C:\Users\lunde\Desktop\skyflask\skanhama\site.db
+ jdbc:sqlite:C:\Users\lunde\Desktop\skyflask\site.db
$ProjectFileDir$
+
+
+ file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.34.0/sqlite-jdbc-3.34.0.jar
+
+
\ No newline at end of file
diff --git a/config.py b/config.py
index 54adb80..36951c7 100644
--- a/config.py
+++ b/config.py
@@ -1,4 +1,11 @@
+import os
+basedir = os.path.abspath(os.path.dirname(__file__))
+
+
class Config(object):
- SECRET_KEY = "cloaked"
- SQLALCHEMY_DATABASE_URI = "sqlite:///site.db"
+ SECRET_KEY = os.environ.get("SECRET_KEY") or "cloaked"
+ SQLALCHEMY_DATABASE_URI = os.environ.get("DATABASE_URL") or "sqlite:///" + os.path.join(basedir, "site.db")
SQLALCHEMY_TRACK_MODIFICATIONS = False
+ MAX_CONTENT_LENGTH = 50 * 1024 * 1024
+ # MAX_DOWNLOAD_SIZE = 50 * 1024 * 1024
+ # MAX_UPLOAD_SIZE = 40 * 1024 * 1024
diff --git a/skanhama/__init__.py b/skanhama/__init__.py
index 9904fd4..142f77c 100644
--- a/skanhama/__init__.py
+++ b/skanhama/__init__.py
@@ -1,12 +1,13 @@
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
+from flask_migrate import Migrate
from flask_login import LoginManager
+from config import Config
app = Flask(__name__)
-app.config["SECRET_KEY"] = "cloaked"
-app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///site.db"
-app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
+app.config.from_object(Config)
db = SQLAlchemy(app)
+migrate = Migrate(app, db)
login_manager = LoginManager(app)
login_manager.login_view = "login"
login_manager.login_message_category = "flash flash-fail"
diff --git a/skanhama/forms.py b/skanhama/forms.py
index 8dcd10b..fa4057b 100644
--- a/skanhama/forms.py
+++ b/skanhama/forms.py
@@ -1,7 +1,7 @@
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed, FileSize
from flask_login import current_user
-from wtforms import StringField, PasswordField, SubmitField, BooleanField, TextAreaField, SelectField
+from wtforms import StringField, PasswordField, SubmitField, BooleanField, TextAreaField, SelectField, MultipleFileField
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
from skanhama.models import User
@@ -21,7 +21,7 @@ def validate_username(self, username):
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user:
- raise ValidationError("Unable to create account. Please ensure you have submitted correct information.")
+ raise ValidationError("An account with that email address already exists.")
class LoginForm(FlaskForm):
@@ -56,6 +56,7 @@ def validate_email(self, email):
class UploadPackage(FlaskForm):
+ # TODO: add base game as input
name = StringField("Package Name", validators=[DataRequired()])
version = StringField("Current Version", validators=[DataRequired(), Length(min=1, max=30)])
author = StringField("Author(s) or Team", validators=[DataRequired()])
@@ -63,6 +64,11 @@ class UploadPackage(FlaskForm):
description = TextAreaField("Description", validators=[DataRequired(), Length(min=1, max=5000)])
requirements = TextAreaField("Requirements", validators=[DataRequired()])
category = SelectField("Primary Category", choices=["Combat", "Sex"], validators=[DataRequired()])
+ game = SelectField("Game Version", choices=[(1, "Skyrim"), (2, "Skyrim Special Edition"),
+ (3, "Skyrim Anniversary Edition")],
+ validators=[DataRequired()], default=2)
nsfw = BooleanField("NSFW Content")
- package = FileField("Select Package", validators=[FileAllowed(["zip"]), FileSize(max_size=20*1024*1024)])
+ package = FileField("Select Package", validators=[FileAllowed(["zip"]), FileSize(max_size=50*1024*1024)])
+ banner = FileField("Select Banner Image", validators=[FileAllowed(["jpg", "gif", "png"]), FileSize(max_size=4*1024*1024)])
+ gallery = MultipleFileField("Add Gallery Images", validators=[FileAllowed(["jpg", "gif", "png"]), FileSize(max_size=10*1024*1024)])
upload = SubmitField("Upload")
diff --git a/skanhama/models.py b/skanhama/models.py
index 633f105..dd3e461 100644
--- a/skanhama/models.py
+++ b/skanhama/models.py
@@ -10,15 +10,14 @@ def load_user(user_id):
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
- username = db.Column(db.String(23), unique=True, nullable=False)
+ username = db.Column(db.String(64), unique=True, index=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
- password = db.Column(db.String(60), nullable=False)
+ password_hash = db.Column(db.String(128), nullable=False)
registered_on = db.Column(db.DateTime, nullable=False)
confirmed = db.Column(db.Boolean, nullable=False, default=False)
confirmed_on = db.Column(db.DateTime, nullable=True)
- admin = db.Column(db.Boolean, nullable=False, default=False)
uploads = db.relationship("Package", backref="upload_author", lazy="dynamic")
- comments = db.relationship("Comment", backref="comment_author", lazy=True)
+ comments = db.relationship("Comment", backref="comment_author", lazy="dynamic")
def __repr__(self):
return f"User ('{self.id}', '{self.username}', '{self.email}', '{self.confirmed_on}, 'Admin={self.admin}')"
@@ -26,22 +25,23 @@ def __repr__(self):
class Package(db.Model):
id = db.Column(db.Integer, primary_key=True)
- name = db.Column(db.String(120), unique=True, nullable=False)
+ name = db.Column(db.String(120), unique=True, index=True, nullable=False)
version = db.Column(db.String(30), nullable=False)
- author = db.Column(db.String(100), nullable=False)
+ author = db.Column(db.String(100), index=True, nullable=False)
nsfw = db.Column(db.Boolean, nullable=False)
summary = db.Column(db.String(230), nullable=False)
description = db.Column(db.Text, nullable=False)
requirements = db.Column(db.Text, nullable=False)
package_dir = db.Column(db.String(400), nullable=False, unique=True)
date_uploaded = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
- downloads_total = db.Column(db.BigInteger, nullable=False)
+ downloads_total = db.Column(db.BigInteger, index=True, nullable=False)
downloads_current_version = db.Column(db.BigInteger, nullable=False)
- likes = db.Column(db.BigInteger, nullable=False)
+ likes = db.Column(db.BigInteger, index=True, nullable=False)
views_total = db.Column(db.BigInteger, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
category = db.relationship("Categories", backref="category_id", lazy=True)
comments = db.relationship("Comment", backref="package_comments", lazy=True)
+ games = db.relationship("Games", backref="games_id", lazy=True)
def __repr__(self):
return f"Package ('{self.date_uploaded}', {self.id}', '{self.name}', '{self.uploaderl}', '{self.synposis}')"
@@ -64,6 +64,11 @@ def __repr__(self):
return f"Package ('{self.id}', {self.name}')"
+class Games(db.Model):
+ id = db.Column(db.Integer, db.ForeignKey("package.id"), primary_key=True)
+ name = db.Column(db.String(100), unique=True, nullable=False)
+
+
class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True)
comment = db.Column(db.Text, nullable=False)
diff --git a/skanhama/routes.py b/skanhama/routes.py
index 9ea2900..5872da1 100644
--- a/skanhama/routes.py
+++ b/skanhama/routes.py
@@ -1,4 +1,3 @@
-import secrets
import os.path
import sqlite3
import zipfile
@@ -29,8 +28,8 @@ def register():
form = RegistrationForm()
if form.validate_on_submit():
hashed_password = generate_password_hash(form.password.data, "sha256")
- user = User(username=form.username.data, email=form.email.data, password=hashed_password,
- registered_on=datetime.now(), confirmed=False, admin=False)
+ user = User(username=form.username.data, email=form.email.data, password_hash=hashed_password,
+ registered_on=datetime.now(), confirmed=False)
db.session.add(user)
db.session.commit()
flash(f"An email has been sent to the registered email for user {form.username.data}. Please "
@@ -46,7 +45,7 @@ def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
- if user and check_password_hash(user.password, form.password.data):
+ if user and check_password_hash(user.password_hash, form.password.data):
login_user(user, remember=form.remember.data)
next_page = request.args.get("next")
return redirect(next_page) if next_page else redirect(url_for("home"))
@@ -121,9 +120,10 @@ def browse():
# Processes the uploaded package
-#
+# TODO: potentially stream the uploaded file first before saving to disk? See
+# https://blog.miguelgrinberg.com/post/handling-file-uploads-with-flask
def process_package(form):
- processor_version = 0.1
+ processor_version = "0.10"
f_name, f_ext = os.path.splitext(form.package.data.filename)
root_dir = Path(app.root_path, "static/packages", current_user.username)
extracted_dir = Path(root_dir, str(form.name.data + "_" + form.version.data))
@@ -165,6 +165,8 @@ def process_package(form):
shutil.rmtree(extracted_dir)
return file_dict
+# def secure_validate_hkx(hkx_file):
+
@app.route("/upload", methods=["GET", "POST"])
@login_required
@@ -177,8 +179,11 @@ def upload():
if file_dict:
print(f"package_data: {file_dict['_package_data'][1]}")
pack = Package(name=form.name.data,
- version=form.version.data,
author=current_user.username,
+ version=form.version.data,
+ category=form.category.data,
+ game=form.category.data,
+ nsfw=form.nsfw.data,
summary=form.summary.data,
description=form.description.data,
requirements=form.requirements.data,
@@ -188,7 +193,6 @@ def upload():
downloads_current_version=0,
views_total=0,
likes=0,
- nsfw=form.nsfw.data,
user_id=current_user.id)
db.session.add(pack)
db.session.commit()
diff --git a/skanhama/site.db b/skanhama/site.db
index b029f17..e69de29 100644
Binary files a/skanhama/site.db and b/skanhama/site.db differ
diff --git a/skanhama/static/dropzone-min.js b/skanhama/static/dropzone-min.js
new file mode 100644
index 0000000..99f18a7
--- /dev/null
+++ b/skanhama/static/dropzone-min.js
@@ -0,0 +1,1795 @@
+! function() {
+ function e(e) {
+ return e && e.__esModule ? e.default : e
+ }
+
+ function t(e) {
+ if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return e
+ }
+
+ function i(e, t) {
+ if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function")
+ }
+
+ function n(e, t) {
+ for (var i = 0; i < t.length; i++) {
+ var n = t[i];
+ n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, n.key, n)
+ }
+ }
+
+ function r(e, t, i) {
+ return t && n(e.prototype, t), i && n(e, i), e
+ }
+
+ function a(e) {
+ return a = Object.setPrototypeOf ? Object.getPrototypeOf : function(e) {
+ return e.__proto__ || Object.getPrototypeOf(e)
+ }, a(e)
+ }
+
+ function o(e, t) {
+ return o = Object.setPrototypeOf || function(e, t) {
+ return e.__proto__ = t, e
+ }, o(e, t)
+ }
+
+ function l(e, t) {
+ if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function");
+ e.prototype = Object.create(t && t.prototype, {
+ constructor: {
+ value: e,
+ writable: !0,
+ configurable: !0
+ }
+ }), t && o(e, t)
+ }
+
+ function s(e, i) {
+ return !i || "object" != ((n = i) && n.constructor === Symbol ? "symbol" : typeof n) && "function" != typeof i ? t(e) : i;
+ var n
+ }
+ var u;
+
+ function c(e) {
+ return Array.isArray(e) || "[object Object]" == {}.toString.call(e)
+ }
+
+ function d(e) {
+ return !e || "object" != typeof e && "function" != typeof e
+ }
+ u = function e() {
+ var t = [].slice.call(arguments),
+ i = !1;
+ "boolean" == typeof t[0] && (i = t.shift());
+ var n = t[0];
+ if (d(n)) throw new Error("extendee must be an object");
+ for (var r = t.slice(1), a = r.length, o = 0; o < a; o++) {
+ var l = r[o];
+ for (var s in l)
+ if (Object.prototype.hasOwnProperty.call(l, s)) {
+ var u = l[s];
+ if (i && c(u)) {
+ var h = Array.isArray(u) ? [] : {};
+ n[s] = e(!0, Object.prototype.hasOwnProperty.call(n, s) && !d(n[s]) ? n[s] : h, u)
+ } else n[s] = u
+ }
+ }
+ return n
+ };
+ var h = function() {
+ "use strict";
+
+ function e() {
+ i(this, e)
+ }
+ return r(e, [{
+ key: "on",
+ value: function(e, t) {
+ return this._callbacks = this._callbacks || {}, this._callbacks[e] || (this._callbacks[e] = []), this._callbacks[e].push(t), this
+ }
+ }, {
+ key: "emit",
+ value: function(e) {
+ for (var t = arguments.length, i = new Array(t > 1 ? t - 1 : 0), n = 1; n < t; n++) i[n - 1] = arguments[n];
+ this._callbacks = this._callbacks || {};
+ var r = this._callbacks[e],
+ a = !0,
+ o = !1,
+ l = void 0;
+ if (r) try {
+ for (var s, u = r[Symbol.iterator](); !(a = (s = u.next()).done); a = !0) {
+ var c = s.value;
+ c.apply(this, i)
+ }
+ } catch (e) {
+ o = !0, l = e
+ } finally {
+ try {
+ a || null == u.return || u.return()
+ } finally {
+ if (o) throw l
+ }
+ }
+ return this.element && this.element.dispatchEvent(this.makeEvent("dropzone:" + e, {
+ args: i
+ })), this
+ }
+ }, {
+ key: "makeEvent",
+ value: function(e, t) {
+ var i = {
+ bubbles: !0,
+ cancelable: !0,
+ detail: t
+ };
+ if ("function" == typeof window.CustomEvent) return new CustomEvent(e, i);
+ var n = document.createEvent("CustomEvent");
+ return n.initCustomEvent(e, i.bubbles, i.cancelable, i.detail), n
+ }
+ }, {
+ key: "off",
+ value: function(e, t) {
+ if (!this._callbacks || 0 === arguments.length) return this._callbacks = {}, this;
+ var i = this._callbacks[e];
+ if (!i) return this;
+ if (1 === arguments.length) return delete this._callbacks[e], this;
+ for (var n = 0; n < i.length; n++) {
+ var r = i[n];
+ if (r === t) {
+ i.splice(n, 1);
+ break
+ }
+ }
+ return this
+ }
+ }]), e
+ }();
+ var p = {
+ url: null,
+ method: "post",
+ withCredentials: !1,
+ timeout: null,
+ parallelUploads: 2,
+ uploadMultiple: !1,
+ chunking: !1,
+ forceChunking: !1,
+ chunkSize: 2e6,
+ parallelChunkUploads: !1,
+ retryChunks: !1,
+ retryChunksLimit: 3,
+ maxFilesize: 256,
+ paramName: "file",
+ createImageThumbnails: !0,
+ maxThumbnailFilesize: 10,
+ thumbnailWidth: 120,
+ thumbnailHeight: 120,
+ thumbnailMethod: "crop",
+ resizeWidth: null,
+ resizeHeight: null,
+ resizeMimeType: null,
+ resizeQuality: .8,
+ resizeMethod: "contain",
+ filesizeBase: 1e3,
+ maxFiles: null,
+ headers: null,
+ clickable: !0,
+ ignoreHiddenFiles: !0,
+ acceptedFiles: null,
+ acceptedMimeTypes: null,
+ autoProcessQueue: !0,
+ autoQueue: !0,
+ addRemoveLinks: !1,
+ previewsContainer: null,
+ disablePreviews: !1,
+ hiddenInputContainer: "body",
+ capture: null,
+ renameFilename: null,
+ renameFile: null,
+ forceFallback: !1,
+ dictDefaultMessage: "Drop files here to upload",
+ dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.",
+ dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.",
+ dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.",
+ dictInvalidFileType: "You can't upload files of this type.",
+ dictResponseError: "Server responded with {{statusCode}} code.",
+ dictCancelUpload: "Cancel upload",
+ dictUploadCanceled: "Upload canceled.",
+ dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?",
+ dictRemoveFile: "Remove file",
+ dictRemoveFileConfirmation: null,
+ dictMaxFilesExceeded: "You can not upload any more files.",
+ dictFileSizeUnits: {
+ tb: "TB",
+ gb: "GB",
+ mb: "MB",
+ kb: "KB",
+ b: "b"
+ },
+ init: function() {},
+ params: function(e, t, i) {
+ if (i) return {
+ dzuuid: i.file.upload.uuid,
+ dzchunkindex: i.index,
+ dztotalfilesize: i.file.size,
+ dzchunksize: this.options.chunkSize,
+ dztotalchunkcount: i.file.upload.totalChunkCount,
+ dzchunkbyteoffset: i.index * this.options.chunkSize
+ }
+ },
+ accept: function(e, t) {
+ return t()
+ },
+ chunksUploaded: function(e, t) {
+ t()
+ },
+ fallback: function() {
+ var e;
+ this.element.className = "".concat(this.element.className, " dz-browser-not-supported");
+ var t = !0,
+ i = !1,
+ n = void 0;
+ try {
+ for (var r, a = this.element.getElementsByTagName("div")[Symbol.iterator](); !(t = (r = a.next()).done); t = !0) {
+ var o = r.value;
+ if (/(^| )dz-message($| )/.test(o.className)) {
+ e = o, o.className = "dz-message";
+ break
+ }
+ }
+ } catch (e) {
+ i = !0, n = e
+ } finally {
+ try {
+ t || null == a.return || a.return()
+ } finally {
+ if (i) throw n
+ }
+ }
+ e || (e = f.createElement('
'), this.element.appendChild(e));
+ var l = e.getElementsByTagName("span")[0];
+ return l && (null != l.textContent ? l.textContent = this.options.dictFallbackMessage : null != l.innerText && (l.innerText = this.options.dictFallbackMessage)), this.element.appendChild(this.getFallbackForm())
+ },
+ resize: function(e, t, i, n) {
+ var r = {
+ srcX: 0,
+ srcY: 0,
+ srcWidth: e.width,
+ srcHeight: e.height
+ },
+ a = e.width / e.height;
+ null == t && null == i ? (t = r.srcWidth, i = r.srcHeight) : null == t ? t = i * a : null == i && (i = t / a);
+ var o = (t = Math.min(t, r.srcWidth)) / (i = Math.min(i, r.srcHeight));
+ if (r.srcWidth > t || r.srcHeight > i)
+ if ("crop" === n) a > o ? (r.srcHeight = e.height, r.srcWidth = r.srcHeight * o) : (r.srcWidth = e.width, r.srcHeight = r.srcWidth / o);
+ else {
+ if ("contain" !== n) throw new Error("Unknown resizeMethod '".concat(n, "'"));
+ a > o ? i = t / a : t = i * a
+ } return r.srcX = (e.width - r.srcWidth) / 2, r.srcY = (e.height - r.srcHeight) / 2, r.trgWidth = t, r.trgHeight = i, r
+ },
+ transformFile: function(e, t) {
+ return (this.options.resizeWidth || this.options.resizeHeight) && e.type.match(/image.*/) ? this.resizeImage(e, this.options.resizeWidth, this.options.resizeHeight, this.options.resizeMethod, t) : t(e)
+ },
+ previewTemplate: e(''),
+ drop: function(e) {
+ return this.element.classList.remove("dz-drag-hover")
+ },
+ dragstart: function(e) {},
+ dragend: function(e) {
+ return this.element.classList.remove("dz-drag-hover")
+ },
+ dragenter: function(e) {
+ return this.element.classList.add("dz-drag-hover")
+ },
+ dragover: function(e) {
+ return this.element.classList.add("dz-drag-hover")
+ },
+ dragleave: function(e) {
+ return this.element.classList.remove("dz-drag-hover")
+ },
+ paste: function(e) {},
+ reset: function() {
+ return this.element.classList.remove("dz-started")
+ },
+ addedfile: function(e) {
+ if (this.element === this.previewsContainer && this.element.classList.add("dz-started"), this.previewsContainer && !this.options.disablePreviews) {
+ var t = this;
+ e.previewElement = f.createElement(this.options.previewTemplate.trim()), e.previewTemplate = e.previewElement, this.previewsContainer.appendChild(e.previewElement);
+ var i = !0,
+ n = !1,
+ r = void 0;
+ try {
+ for (var a, o = e.previewElement.querySelectorAll("[data-dz-name]")[Symbol.iterator](); !(i = (a = o.next()).done); i = !0) {
+ var l = a.value;
+ l.textContent = e.name
+ }
+ } catch (e) {
+ n = !0, r = e
+ } finally {
+ try {
+ i || null == o.return || o.return()
+ } finally {
+ if (n) throw r
+ }
+ }
+ var s = !0,
+ u = !1,
+ c = void 0;
+ try {
+ for (var d, h = e.previewElement.querySelectorAll("[data-dz-size]")[Symbol.iterator](); !(s = (d = h.next()).done); s = !0)(l = d.value).innerHTML = this.filesize(e.size)
+ } catch (e) {
+ u = !0, c = e
+ } finally {
+ try {
+ s || null == h.return || h.return()
+ } finally {
+ if (u) throw c
+ }
+ }
+ this.options.addRemoveLinks && (e._removeLink = f.createElement(''.concat(this.options.dictRemoveFile, "")), e.previewElement.appendChild(e._removeLink));
+ var p = function(i) {
+ var n = t;
+ if (i.preventDefault(), i.stopPropagation(), e.status === f.UPLOADING) return f.confirm(t.options.dictCancelUploadConfirmation, (function() {
+ return n.removeFile(e)
+ }));
+ var r = t;
+ return t.options.dictRemoveFileConfirmation ? f.confirm(t.options.dictRemoveFileConfirmation, (function() {
+ return r.removeFile(e)
+ })) : t.removeFile(e)
+ },
+ m = !0,
+ v = !1,
+ y = void 0;
+ try {
+ for (var g, b = e.previewElement.querySelectorAll("[data-dz-remove]")[Symbol.iterator](); !(m = (g = b.next()).done); m = !0) {
+ g.value.addEventListener("click", p)
+ }
+ } catch (e) {
+ v = !0, y = e
+ } finally {
+ try {
+ m || null == b.return || b.return()
+ } finally {
+ if (v) throw y
+ }
+ }
+ }
+ },
+ removedfile: function(e) {
+ return null != e.previewElement && null != e.previewElement.parentNode && e.previewElement.parentNode.removeChild(e.previewElement), this._updateMaxFilesReachedClass()
+ },
+ thumbnail: function(e, t) {
+ if (e.previewElement) {
+ e.previewElement.classList.remove("dz-file-preview");
+ var i = !0,
+ n = !1,
+ r = void 0;
+ try {
+ for (var a, o = e.previewElement.querySelectorAll("[data-dz-thumbnail]")[Symbol.iterator](); !(i = (a = o.next()).done); i = !0) {
+ var l = a.value;
+ l.alt = e.name, l.src = t
+ }
+ } catch (e) {
+ n = !0, r = e
+ } finally {
+ try {
+ i || null == o.return || o.return()
+ } finally {
+ if (n) throw r
+ }
+ }
+ return setTimeout((function() {
+ return e.previewElement.classList.add("dz-image-preview")
+ }), 1)
+ }
+ },
+ error: function(e, t) {
+ if (e.previewElement) {
+ e.previewElement.classList.add("dz-error"), "string" != typeof t && t.error && (t = t.error);
+ var i = !0,
+ n = !1,
+ r = void 0;
+ try {
+ for (var a, o = e.previewElement.querySelectorAll("[data-dz-errormessage]")[Symbol.iterator](); !(i = (a = o.next()).done); i = !0) {
+ a.value.textContent = t
+ }
+ } catch (e) {
+ n = !0, r = e
+ } finally {
+ try {
+ i || null == o.return || o.return()
+ } finally {
+ if (n) throw r
+ }
+ }
+ }
+ },
+ errormultiple: function() {},
+ processing: function(e) {
+ if (e.previewElement && (e.previewElement.classList.add("dz-processing"), e._removeLink)) return e._removeLink.innerHTML = this.options.dictCancelUpload
+ },
+ processingmultiple: function() {},
+ uploadprogress: function(e, t, i) {
+ var n = !0,
+ r = !1,
+ a = void 0;
+ if (e.previewElement) try {
+ for (var o, l = e.previewElement.querySelectorAll("[data-dz-uploadprogress]")[Symbol.iterator](); !(n = (o = l.next()).done); n = !0) {
+ var s = o.value;
+ "PROGRESS" === s.nodeName ? s.value = t : s.style.width = "".concat(t, "%")
+ }
+ } catch (e) {
+ r = !0, a = e
+ } finally {
+ try {
+ n || null == l.return || l.return()
+ } finally {
+ if (r) throw a
+ }
+ }
+ },
+ totaluploadprogress: function() {},
+ sending: function() {},
+ sendingmultiple: function() {},
+ success: function(e) {
+ if (e.previewElement) return e.previewElement.classList.add("dz-success")
+ },
+ successmultiple: function() {},
+ canceled: function(e) {
+ return this.emit("error", e, this.options.dictUploadCanceled)
+ },
+ canceledmultiple: function() {},
+ complete: function(e) {
+ if (e._removeLink && (e._removeLink.innerHTML = this.options.dictRemoveFile), e.previewElement) return e.previewElement.classList.add("dz-complete")
+ },
+ completemultiple: function() {},
+ maxfilesexceeded: function() {},
+ maxfilesreached: function() {},
+ queuecomplete: function() {},
+ addedfiles: function() {}
+ },
+ f = function(n) {
+ "use strict";
+
+ function o(n, r) {
+ var l, c, d, h;
+ if (i(this, o), (l = s(this, (c = o, a(c)).call(this))).element = n, l.clickableElements = [], l.listeners = [], l.files = [], "string" == typeof l.element && (l.element = document.querySelector(l.element)), !l.element || null == l.element.nodeType) throw new Error("Invalid dropzone element.");
+ if (l.element.dropzone) throw new Error("Dropzone already attached.");
+ o.instances.push(t(l)), l.element.dropzone = t(l);
+ var f = null != (h = o.optionsForElement(l.element)) ? h : {};
+ if (l.options = e(u)(!0, {}, p, f, null != r ? r : {}), l.options.previewTemplate = l.options.previewTemplate.replace(/\n*/g, ""), l.options.forceFallback || !o.isBrowserSupported()) return s(l, l.options.fallback.call(t(l)));
+ if (null == l.options.url && (l.options.url = l.element.getAttribute("action")), !l.options.url) throw new Error("No URL provided.");
+ if (l.options.acceptedFiles && l.options.acceptedMimeTypes) throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated.");
+ if (l.options.uploadMultiple && l.options.chunking) throw new Error("You cannot set both: uploadMultiple and chunking.");
+ return l.options.acceptedMimeTypes && (l.options.acceptedFiles = l.options.acceptedMimeTypes, delete l.options.acceptedMimeTypes), null != l.options.renameFilename && (l.options.renameFile = function(e) {
+ return l.options.renameFilename.call(t(l), e.name, e)
+ }), "string" == typeof l.options.method && (l.options.method = l.options.method.toUpperCase()), (d = l.getExistingFallback()) && d.parentNode && d.parentNode.removeChild(d), !1 !== l.options.previewsContainer && (l.options.previewsContainer ? l.previewsContainer = o.getElement(l.options.previewsContainer, "previewsContainer") : l.previewsContainer = l.element), l.options.clickable && (!0 === l.options.clickable ? l.clickableElements = [l.element] : l.clickableElements = o.getElements(l.options.clickable, "clickable")), l.init(), l
+ }
+ return l(o, n), r(o, [{
+ key: "getAcceptedFiles",
+ value: function() {
+ return this.files.filter((function(e) {
+ return e.accepted
+ })).map((function(e) {
+ return e
+ }))
+ }
+ }, {
+ key: "getRejectedFiles",
+ value: function() {
+ return this.files.filter((function(e) {
+ return !e.accepted
+ })).map((function(e) {
+ return e
+ }))
+ }
+ }, {
+ key: "getFilesWithStatus",
+ value: function(e) {
+ return this.files.filter((function(t) {
+ return t.status === e
+ })).map((function(e) {
+ return e
+ }))
+ }
+ }, {
+ key: "getQueuedFiles",
+ value: function() {
+ return this.getFilesWithStatus(o.QUEUED)
+ }
+ }, {
+ key: "getUploadingFiles",
+ value: function() {
+ return this.getFilesWithStatus(o.UPLOADING)
+ }
+ }, {
+ key: "getAddedFiles",
+ value: function() {
+ return this.getFilesWithStatus(o.ADDED)
+ }
+ }, {
+ key: "getActiveFiles",
+ value: function() {
+ return this.files.filter((function(e) {
+ return e.status === o.UPLOADING || e.status === o.QUEUED
+ })).map((function(e) {
+ return e
+ }))
+ }
+ }, {
+ key: "init",
+ value: function() {
+ var e = this,
+ t = this,
+ i = this,
+ n = this,
+ r = this,
+ a = this,
+ l = this,
+ s = this,
+ u = this,
+ c = this,
+ d = this;
+ if ("form" === this.element.tagName && this.element.setAttribute("enctype", "multipart/form-data"), this.element.classList.contains("dropzone") && !this.element.querySelector(".dz-message") && this.element.appendChild(o.createElement('"))), this.clickableElements.length) {
+ var h = this,
+ p = function() {
+ var e = h;
+ h.hiddenFileInput && h.hiddenFileInput.parentNode.removeChild(h.hiddenFileInput), h.hiddenFileInput = document.createElement("input"), h.hiddenFileInput.setAttribute("type", "file"), (null === h.options.maxFiles || h.options.maxFiles > 1) && h.hiddenFileInput.setAttribute("multiple", "multiple"), h.hiddenFileInput.className = "dz-hidden-input", null !== h.options.acceptedFiles && h.hiddenFileInput.setAttribute("accept", h.options.acceptedFiles), null !== h.options.capture && h.hiddenFileInput.setAttribute("capture", h.options.capture), h.hiddenFileInput.setAttribute("tabindex", "-1"), h.hiddenFileInput.style.visibility = "hidden", h.hiddenFileInput.style.position = "absolute", h.hiddenFileInput.style.top = "0", h.hiddenFileInput.style.left = "0", h.hiddenFileInput.style.height = "0", h.hiddenFileInput.style.width = "0", o.getElement(h.options.hiddenInputContainer, "hiddenInputContainer").appendChild(h.hiddenFileInput), h.hiddenFileInput.addEventListener("change", (function() {
+ var t = e.hiddenFileInput.files,
+ i = !0,
+ n = !1,
+ r = void 0;
+ if (t.length) try {
+ for (var a, o = t[Symbol.iterator](); !(i = (a = o.next()).done); i = !0) {
+ var l = a.value;
+ e.addFile(l)
+ }
+ } catch (e) {
+ n = !0, r = e
+ } finally {
+ try {
+ i || null == o.return || o.return()
+ } finally {
+ if (n) throw r
+ }
+ }
+ e.emit("addedfiles", t), p()
+ }))
+ };
+ p()
+ }
+ this.URL = null !== window.URL ? window.URL : window.webkitURL;
+ var f = !0,
+ m = !1,
+ v = void 0;
+ try {
+ for (var y, g = this.events[Symbol.iterator](); !(f = (y = g.next()).done); f = !0) {
+ var b = y.value;
+ this.on(b, this.options[b])
+ }
+ } catch (e) {
+ m = !0, v = e
+ } finally {
+ try {
+ f || null == g.return || g.return()
+ } finally {
+ if (m) throw v
+ }
+ }
+ this.on("uploadprogress", (function() {
+ return e.updateTotalUploadProgress()
+ })), this.on("removedfile", (function() {
+ return t.updateTotalUploadProgress()
+ })), this.on("canceled", (function(e) {
+ return i.emit("complete", e)
+ })), this.on("complete", (function(e) {
+ var t = n;
+ if (0 === n.getAddedFiles().length && 0 === n.getUploadingFiles().length && 0 === n.getQueuedFiles().length) return setTimeout((function() {
+ return t.emit("queuecomplete")
+ }), 0)
+ }));
+ var k = function(e) {
+ if (function(e) {
+ if (e.dataTransfer.types)
+ for (var t = 0; t < e.dataTransfer.types.length; t++)
+ if ("Files" === e.dataTransfer.types[t]) return !0;
+ return !1
+ }(e)) return e.stopPropagation(), e.preventDefault ? e.preventDefault() : e.returnValue = !1
+ };
+ return this.listeners = [{
+ element: this.element,
+ events: {
+ dragstart: function(e) {
+ return r.emit("dragstart", e)
+ },
+ dragenter: function(e) {
+ return k(e), a.emit("dragenter", e)
+ },
+ dragover: function(e) {
+ var t;
+ try {
+ t = e.dataTransfer.effectAllowed
+ } catch (e) {}
+ return e.dataTransfer.dropEffect = "move" === t || "linkMove" === t ? "move" : "copy", k(e), l.emit("dragover", e)
+ },
+ dragleave: function(e) {
+ return s.emit("dragleave", e)
+ },
+ drop: function(e) {
+ return k(e), u.drop(e)
+ },
+ dragend: function(e) {
+ return c.emit("dragend", e)
+ }
+ }
+ }], this.clickableElements.forEach((function(e) {
+ var t = d;
+ return d.listeners.push({
+ element: e,
+ events: {
+ click: function(i) {
+ return (e !== t.element || i.target === t.element || o.elementInside(i.target, t.element.querySelector(".dz-message"))) && t.hiddenFileInput.click(), !0
+ }
+ }
+ })
+ })), this.enable(), this.options.init.call(this)
+ }
+ }, {
+ key: "destroy",
+ value: function() {
+ return this.disable(), this.removeAllFiles(!0), (null != this.hiddenFileInput ? this.hiddenFileInput.parentNode : void 0) && (this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput), this.hiddenFileInput = null), delete this.element.dropzone, o.instances.splice(o.instances.indexOf(this), 1)
+ }
+ }, {
+ key: "updateTotalUploadProgress",
+ value: function() {
+ var e, t = 0,
+ i = 0;
+ if (this.getActiveFiles().length) {
+ var n = !0,
+ r = !1,
+ a = void 0;
+ try {
+ for (var o, l = this.getActiveFiles()[Symbol.iterator](); !(n = (o = l.next()).done); n = !0) {
+ var s = o.value;
+ t += s.upload.bytesSent, i += s.upload.total
+ }
+ } catch (e) {
+ r = !0, a = e
+ } finally {
+ try {
+ n || null == l.return || l.return()
+ } finally {
+ if (r) throw a
+ }
+ }
+ e = 100 * t / i
+ } else e = 100;
+ return this.emit("totaluploadprogress", e, i, t)
+ }
+ }, {
+ key: "_getParamName",
+ value: function(e) {
+ return "function" == typeof this.options.paramName ? this.options.paramName(e) : "".concat(this.options.paramName).concat(this.options.uploadMultiple ? "[".concat(e, "]") : "")
+ }
+ }, {
+ key: "_renameFile",
+ value: function(e) {
+ return "function" != typeof this.options.renameFile ? e.name : this.options.renameFile(e)
+ }
+ }, {
+ key: "getFallbackForm",
+ value: function() {
+ var e, t;
+ if (e = this.getExistingFallback()) return e;
+ var i = '');
+ var n = o.createElement(i);
+ return "FORM" !== this.element.tagName ? (t = o.createElement(''))).appendChild(n) : (this.element.setAttribute("enctype", "multipart/form-data"), this.element.setAttribute("method", this.options.method)), null != t ? t : n
+ }
+ }, {
+ key: "getExistingFallback",
+ value: function() {
+ var e = function(e) {
+ var t = !0,
+ i = !1,
+ n = void 0;
+ try {
+ for (var r, a = e[Symbol.iterator](); !(t = (r = a.next()).done); t = !0) {
+ var o = r.value;
+ if (/(^| )fallback($| )/.test(o.className)) return o
+ }
+ } catch (e) {
+ i = !0, n = e
+ } finally {
+ try {
+ t || null == a.return || a.return()
+ } finally {
+ if (i) throw n
+ }
+ }
+ },
+ t = !0,
+ i = !1,
+ n = void 0;
+ try {
+ for (var r, a = ["div", "form"][Symbol.iterator](); !(t = (r = a.next()).done); t = !0) {
+ var o, l = r.value;
+ if (o = e(this.element.getElementsByTagName(l))) return o
+ }
+ } catch (e) {
+ i = !0, n = e
+ } finally {
+ try {
+ t || null == a.return || a.return()
+ } finally {
+ if (i) throw n
+ }
+ }
+ }
+ }, {
+ key: "setupEventListeners",
+ value: function() {
+ return this.listeners.map((function(e) {
+ return function() {
+ var t = [];
+ for (var i in e.events) {
+ var n = e.events[i];
+ t.push(e.element.addEventListener(i, n, !1))
+ }
+ return t
+ }()
+ }))
+ }
+ }, {
+ key: "removeEventListeners",
+ value: function() {
+ return this.listeners.map((function(e) {
+ return function() {
+ var t = [];
+ for (var i in e.events) {
+ var n = e.events[i];
+ t.push(e.element.removeEventListener(i, n, !1))
+ }
+ return t
+ }()
+ }))
+ }
+ }, {
+ key: "disable",
+ value: function() {
+ var e = this;
+ return this.clickableElements.forEach((function(e) {
+ return e.classList.remove("dz-clickable")
+ })), this.removeEventListeners(), this.disabled = !0, this.files.map((function(t) {
+ return e.cancelUpload(t)
+ }))
+ }
+ }, {
+ key: "enable",
+ value: function() {
+ return delete this.disabled, this.clickableElements.forEach((function(e) {
+ return e.classList.add("dz-clickable")
+ })), this.setupEventListeners()
+ }
+ }, {
+ key: "filesize",
+ value: function(e) {
+ var t = 0,
+ i = "b";
+ if (e > 0) {
+ for (var n = ["tb", "gb", "mb", "kb", "b"], r = 0; r < n.length; r++) {
+ var a = n[r];
+ if (e >= Math.pow(this.options.filesizeBase, 4 - r) / 10) {
+ t = e / Math.pow(this.options.filesizeBase, 4 - r), i = a;
+ break
+ }
+ }
+ t = Math.round(10 * t) / 10
+ }
+ return "".concat(t, " ").concat(this.options.dictFileSizeUnits[i])
+ }
+ }, {
+ key: "_updateMaxFilesReachedClass",
+ value: function() {
+ return null != this.options.maxFiles && this.getAcceptedFiles().length >= this.options.maxFiles ? (this.getAcceptedFiles().length === this.options.maxFiles && this.emit("maxfilesreached", this.files), this.element.classList.add("dz-max-files-reached")) : this.element.classList.remove("dz-max-files-reached")
+ }
+ }, {
+ key: "drop",
+ value: function(e) {
+ if (e.dataTransfer) {
+ this.emit("drop", e);
+ for (var t = [], i = 0; i < e.dataTransfer.files.length; i++) t[i] = e.dataTransfer.files[i];
+ if (t.length) {
+ var n = e.dataTransfer.items;
+ n && n.length && null != n[0].webkitGetAsEntry ? this._addFilesFromItems(n) : this.handleFiles(t)
+ }
+ this.emit("addedfiles", t)
+ }
+ }
+ }, {
+ key: "paste",
+ value: function(e) {
+ if (null != (t = null != e ? e.clipboardData : void 0, i = function(e) {
+ return e.items
+ }, null != t ? i(t) : void 0)) {
+ var t, i;
+ this.emit("paste", e);
+ var n = e.clipboardData.items;
+ return n.length ? this._addFilesFromItems(n) : void 0
+ }
+ }
+ }, {
+ key: "handleFiles",
+ value: function(e) {
+ var t = !0,
+ i = !1,
+ n = void 0;
+ try {
+ for (var r, a = e[Symbol.iterator](); !(t = (r = a.next()).done); t = !0) {
+ var o = r.value;
+ this.addFile(o)
+ }
+ } catch (e) {
+ i = !0, n = e
+ } finally {
+ try {
+ t || null == a.return || a.return()
+ } finally {
+ if (i) throw n
+ }
+ }
+ }
+ }, {
+ key: "_addFilesFromItems",
+ value: function(e) {
+ var t = this;
+ return function() {
+ var i = [],
+ n = !0,
+ r = !1,
+ a = void 0;
+ try {
+ for (var o, l = e[Symbol.iterator](); !(n = (o = l.next()).done); n = !0) {
+ var s, u = o.value;
+ null != u.webkitGetAsEntry && (s = u.webkitGetAsEntry()) ? s.isFile ? i.push(t.addFile(u.getAsFile())) : s.isDirectory ? i.push(t._addFilesFromDirectory(s, s.name)) : i.push(void 0) : null != u.getAsFile && (null == u.kind || "file" === u.kind) ? i.push(t.addFile(u.getAsFile())) : i.push(void 0)
+ }
+ } catch (e) {
+ r = !0, a = e
+ } finally {
+ try {
+ n || null == l.return || l.return()
+ } finally {
+ if (r) throw a
+ }
+ }
+ return i
+ }()
+ }
+ }, {
+ key: "_addFilesFromDirectory",
+ value: function(e, t) {
+ var i = this,
+ n = e.createReader(),
+ r = function(e) {
+ return t = console, i = "log", n = function(t) {
+ return t.log(e)
+ }, null != t && "function" == typeof t[i] ? n(t, i) : void 0;
+ var t, i, n
+ },
+ a = function() {
+ var e = i;
+ return n.readEntries((function(i) {
+ if (i.length > 0) {
+ var n = !0,
+ r = !1,
+ o = void 0;
+ try {
+ for (var l, s = i[Symbol.iterator](); !(n = (l = s.next()).done); n = !0) {
+ var u = l.value,
+ c = e;
+ u.isFile ? u.file((function(e) {
+ if (!c.options.ignoreHiddenFiles || "." !== e.name.substring(0, 1)) return e.fullPath = "".concat(t, "/").concat(e.name), c.addFile(e)
+ })) : u.isDirectory && e._addFilesFromDirectory(u, "".concat(t, "/").concat(u.name))
+ }
+ } catch (e) {
+ r = !0, o = e
+ } finally {
+ try {
+ n || null == s.return || s.return()
+ } finally {
+ if (r) throw o
+ }
+ }
+ a()
+ }
+ return null
+ }), r)
+ };
+ return a()
+ }
+ }, {
+ key: "accept",
+ value: function(e, t) {
+ this.options.maxFilesize && e.size > 1048576 * this.options.maxFilesize ? t(this.options.dictFileTooBig.replace("{{filesize}}", Math.round(e.size / 1024 / 10.24) / 100).replace("{{maxFilesize}}", this.options.maxFilesize)) : o.isValidFile(e, this.options.acceptedFiles) ? null != this.options.maxFiles && this.getAcceptedFiles().length >= this.options.maxFiles ? (t(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}", this.options.maxFiles)), this.emit("maxfilesexceeded", e)) : this.options.accept.call(this, e, t) : t(this.options.dictInvalidFileType)
+ }
+ }, {
+ key: "addFile",
+ value: function(e) {
+ var t = this;
+ e.upload = {
+ uuid: o.uuidv4(),
+ progress: 0,
+ total: e.size,
+ bytesSent: 0,
+ filename: this._renameFile(e)
+ }, this.files.push(e), e.status = o.ADDED, this.emit("addedfile", e), this._enqueueThumbnail(e), this.accept(e, (function(i) {
+ i ? (e.accepted = !1, t._errorProcessing([e], i)) : (e.accepted = !0, t.options.autoQueue && t.enqueueFile(e)), t._updateMaxFilesReachedClass()
+ }))
+ }
+ }, {
+ key: "enqueueFiles",
+ value: function(e) {
+ var t = !0,
+ i = !1,
+ n = void 0;
+ try {
+ for (var r, a = e[Symbol.iterator](); !(t = (r = a.next()).done); t = !0) {
+ var o = r.value;
+ this.enqueueFile(o)
+ }
+ } catch (e) {
+ i = !0, n = e
+ } finally {
+ try {
+ t || null == a.return || a.return()
+ } finally {
+ if (i) throw n
+ }
+ }
+ return null
+ }
+ }, {
+ key: "enqueueFile",
+ value: function(e) {
+ if (e.status !== o.ADDED || !0 !== e.accepted) throw new Error("This file can't be queued because it has already been processed or was rejected.");
+ var t = this;
+ if (e.status = o.QUEUED, this.options.autoProcessQueue) return setTimeout((function() {
+ return t.processQueue()
+ }), 0)
+ }
+ }, {
+ key: "_enqueueThumbnail",
+ value: function(e) {
+ if (this.options.createImageThumbnails && e.type.match(/image.*/) && e.size <= 1048576 * this.options.maxThumbnailFilesize) {
+ var t = this;
+ return this._thumbnailQueue.push(e), setTimeout((function() {
+ return t._processThumbnailQueue()
+ }), 0)
+ }
+ }
+ }, {
+ key: "_processThumbnailQueue",
+ value: function() {
+ var e = this;
+ if (!this._processingThumbnail && 0 !== this._thumbnailQueue.length) {
+ this._processingThumbnail = !0;
+ var t = this._thumbnailQueue.shift();
+ return this.createThumbnail(t, this.options.thumbnailWidth, this.options.thumbnailHeight, this.options.thumbnailMethod, !0, (function(i) {
+ return e.emit("thumbnail", t, i), e._processingThumbnail = !1, e._processThumbnailQueue()
+ }))
+ }
+ }
+ }, {
+ key: "removeFile",
+ value: function(e) {
+ if (e.status === o.UPLOADING && this.cancelUpload(e), this.files = m(this.files, e), this.emit("removedfile", e), 0 === this.files.length) return this.emit("reset")
+ }
+ }, {
+ key: "removeAllFiles",
+ value: function(e) {
+ null == e && (e = !1);
+ var t = !0,
+ i = !1,
+ n = void 0;
+ try {
+ for (var r, a = this.files.slice()[Symbol.iterator](); !(t = (r = a.next()).done); t = !0) {
+ var l = r.value;
+ (l.status !== o.UPLOADING || e) && this.removeFile(l)
+ }
+ } catch (e) {
+ i = !0, n = e
+ } finally {
+ try {
+ t || null == a.return || a.return()
+ } finally {
+ if (i) throw n
+ }
+ }
+ return null
+ }
+ }, {
+ key: "resizeImage",
+ value: function(e, t, i, n, r) {
+ var a = this;
+ return this.createThumbnail(e, t, i, n, !0, (function(t, i) {
+ if (null == i) return r(e);
+ var n = a.options.resizeMimeType;
+ null == n && (n = e.type);
+ var l = i.toDataURL(n, a.options.resizeQuality);
+ return "image/jpeg" !== n && "image/jpg" !== n || (l = g.restore(e.dataURL, l)), r(o.dataURItoBlob(l))
+ }))
+ }
+ }, {
+ key: "createThumbnail",
+ value: function(e, t, i, n, r, a) {
+ var o = this,
+ l = new FileReader;
+ l.onload = function() {
+ e.dataURL = l.result, "image/svg+xml" !== e.type ? o.createThumbnailFromUrl(e, t, i, n, r, a) : null != a && a(l.result)
+ }, l.readAsDataURL(e)
+ }
+ }, {
+ key: "displayExistingFile",
+ value: function(e, t, i, n, r) {
+ var a = void 0 === r || r;
+ if (this.emit("addedfile", e), this.emit("complete", e), a) {
+ var o = this;
+ e.dataURL = t, this.createThumbnailFromUrl(e, this.options.thumbnailWidth, this.options.thumbnailHeight, this.options.thumbnailMethod, this.options.fixOrientation, (function(t) {
+ o.emit("thumbnail", e, t), i && i()
+ }), n)
+ } else this.emit("thumbnail", e, t), i && i()
+ }
+ }, {
+ key: "createThumbnailFromUrl",
+ value: function(e, t, i, n, r, a, o) {
+ var l = this,
+ s = document.createElement("img");
+ return o && (s.crossOrigin = o), r = "from-image" != getComputedStyle(document.body).imageOrientation && r, s.onload = function() {
+ var o = l,
+ u = function(e) {
+ return e(1)
+ };
+ return "undefined" != typeof EXIF && null !== EXIF && r && (u = function(e) {
+ return EXIF.getData(s, (function() {
+ return e(EXIF.getTag(this, "Orientation"))
+ }))
+ }), u((function(r) {
+ e.width = s.width, e.height = s.height;
+ var l = o.options.resize.call(o, e, t, i, n),
+ u = document.createElement("canvas"),
+ c = u.getContext("2d");
+ switch (u.width = l.trgWidth, u.height = l.trgHeight, r > 4 && (u.width = l.trgHeight, u.height = l.trgWidth), r) {
+ case 2:
+ c.translate(u.width, 0), c.scale(-1, 1);
+ break;
+ case 3:
+ c.translate(u.width, u.height), c.rotate(Math.PI);
+ break;
+ case 4:
+ c.translate(0, u.height), c.scale(1, -1);
+ break;
+ case 5:
+ c.rotate(.5 * Math.PI), c.scale(1, -1);
+ break;
+ case 6:
+ c.rotate(.5 * Math.PI), c.translate(0, -u.width);
+ break;
+ case 7:
+ c.rotate(.5 * Math.PI), c.translate(u.height, -u.width), c.scale(-1, 1);
+ break;
+ case 8:
+ c.rotate(-.5 * Math.PI), c.translate(-u.height, 0)
+ }
+ y(c, s, null != l.srcX ? l.srcX : 0, null != l.srcY ? l.srcY : 0, l.srcWidth, l.srcHeight, null != l.trgX ? l.trgX : 0, null != l.trgY ? l.trgY : 0, l.trgWidth, l.trgHeight);
+ var d = u.toDataURL("image/png");
+ if (null != a) return a(d, u)
+ }))
+ }, null != a && (s.onerror = a), s.src = e.dataURL
+ }
+ }, {
+ key: "processQueue",
+ value: function() {
+ var e = this.options.parallelUploads,
+ t = this.getUploadingFiles().length,
+ i = t;
+ if (!(t >= e)) {
+ var n = this.getQueuedFiles();
+ if (n.length > 0) {
+ if (this.options.uploadMultiple) return this.processFiles(n.slice(0, e - t));
+ for (; i < e;) {
+ if (!n.length) return;
+ this.processFile(n.shift()), i++
+ }
+ }
+ }
+ }
+ }, {
+ key: "processFile",
+ value: function(e) {
+ return this.processFiles([e])
+ }
+ }, {
+ key: "processFiles",
+ value: function(e) {
+ var t = !0,
+ i = !1,
+ n = void 0;
+ try {
+ for (var r, a = e[Symbol.iterator](); !(t = (r = a.next()).done); t = !0) {
+ var l = r.value;
+ l.processing = !0, l.status = o.UPLOADING, this.emit("processing", l)
+ }
+ } catch (e) {
+ i = !0, n = e
+ } finally {
+ try {
+ t || null == a.return || a.return()
+ } finally {
+ if (i) throw n
+ }
+ }
+ return this.options.uploadMultiple && this.emit("processingmultiple", e), this.uploadFiles(e)
+ }
+ }, {
+ key: "_getFilesWithXhr",
+ value: function(e) {
+ return this.files.filter((function(t) {
+ return t.xhr === e
+ })).map((function(e) {
+ return e
+ }))
+ }
+ }, {
+ key: "cancelUpload",
+ value: function(e) {
+ if (e.status === o.UPLOADING) {
+ var t = this._getFilesWithXhr(e.xhr),
+ i = !0,
+ n = !1,
+ r = void 0;
+ try {
+ for (var a, l = t[Symbol.iterator](); !(i = (a = l.next()).done); i = !0) {
+ (p = a.value).status = o.CANCELED
+ }
+ } catch (e) {
+ n = !0, r = e
+ } finally {
+ try {
+ i || null == l.return || l.return()
+ } finally {
+ if (n) throw r
+ }
+ }
+ void 0 !== e.xhr && e.xhr.abort();
+ var s = !0,
+ u = !1,
+ c = void 0;
+ try {
+ for (var d, h = t[Symbol.iterator](); !(s = (d = h.next()).done); s = !0) {
+ var p = d.value;
+ this.emit("canceled", p)
+ }
+ } catch (e) {
+ u = !0, c = e
+ } finally {
+ try {
+ s || null == h.return || h.return()
+ } finally {
+ if (u) throw c
+ }
+ }
+ this.options.uploadMultiple && this.emit("canceledmultiple", t)
+ } else e.status !== o.ADDED && e.status !== o.QUEUED || (e.status = o.CANCELED, this.emit("canceled", e), this.options.uploadMultiple && this.emit("canceledmultiple", [e]));
+ if (this.options.autoProcessQueue) return this.processQueue()
+ }
+ }, {
+ key: "resolveOption",
+ value: function(e) {
+ for (var t = arguments.length, i = new Array(t > 1 ? t - 1 : 0), n = 1; n < t; n++) i[n - 1] = arguments[n];
+ return "function" == typeof e ? e.apply(this, i) : e
+ }
+ }, {
+ key: "uploadFile",
+ value: function(e) {
+ return this.uploadFiles([e])
+ }
+ }, {
+ key: "uploadFiles",
+ value: function(e) {
+ var t = this;
+ this._transformFiles(e, (function(i) {
+ if (t.options.chunking) {
+ var n = i[0];
+ e[0].upload.chunked = t.options.chunking && (t.options.forceChunking || n.size > t.options.chunkSize), e[0].upload.totalChunkCount = Math.ceil(n.size / t.options.chunkSize)
+ }
+ if (e[0].upload.chunked) {
+ var r = t,
+ a = t,
+ l = e[0];
+ n = i[0];
+ l.upload.chunks = [];
+ var s = function() {
+ for (var t = 0; void 0 !== l.upload.chunks[t];) t++;
+ if (!(t >= l.upload.totalChunkCount)) {
+ 0;
+ var i = t * r.options.chunkSize,
+ a = Math.min(i + r.options.chunkSize, n.size),
+ s = {
+ name: r._getParamName(0),
+ data: n.webkitSlice ? n.webkitSlice(i, a) : n.slice(i, a),
+ filename: l.upload.filename,
+ chunkIndex: t
+ };
+ l.upload.chunks[t] = {
+ file: l,
+ index: t,
+ dataBlock: s,
+ status: o.UPLOADING,
+ progress: 0,
+ retries: 0
+ }, r._uploadData(e, [s])
+ }
+ };
+ if (l.upload.finishedChunkUpload = function(t, i) {
+ var n = a,
+ r = !0;
+ t.status = o.SUCCESS, t.dataBlock = null, t.xhr = null;
+ for (var u = 0; u < l.upload.totalChunkCount; u++) {
+ if (void 0 === l.upload.chunks[u]) return s();
+ l.upload.chunks[u].status !== o.SUCCESS && (r = !1)
+ }
+ r && a.options.chunksUploaded(l, (function() {
+ n._finished(e, i, null)
+ }))
+ }, t.options.parallelChunkUploads)
+ for (var u = 0; u < l.upload.totalChunkCount; u++) s();
+ else s()
+ } else {
+ var c = [];
+ for (u = 0; u < e.length; u++) c[u] = {
+ name: t._getParamName(u),
+ data: i[u],
+ filename: e[u].upload.filename
+ };
+ t._uploadData(e, c)
+ }
+ }))
+ }
+ }, {
+ key: "_getChunk",
+ value: function(e, t) {
+ for (var i = 0; i < e.upload.totalChunkCount; i++)
+ if (void 0 !== e.upload.chunks[i] && e.upload.chunks[i].xhr === t) return e.upload.chunks[i]
+ }
+ }, {
+ key: "_uploadData",
+ value: function(t, i) {
+ var n = this,
+ r = this,
+ a = this,
+ o = this,
+ l = new XMLHttpRequest,
+ s = !0,
+ c = !1,
+ d = void 0;
+ try {
+ for (var h, p = t[Symbol.iterator](); !(s = (h = p.next()).done); s = !0) {
+ (_ = h.value).xhr = l
+ }
+ } catch (e) {
+ c = !0, d = e
+ } finally {
+ try {
+ s || null == p.return || p.return()
+ } finally {
+ if (c) throw d
+ }
+ }
+ t[0].upload.chunked && (t[0].upload.chunks[i[0].chunkIndex].xhr = l);
+ var f = this.resolveOption(this.options.method, t),
+ m = this.resolveOption(this.options.url, t);
+ l.open(f, m, !0), this.resolveOption(this.options.timeout, t) && (l.timeout = this.resolveOption(this.options.timeout, t)), l.withCredentials = !!this.options.withCredentials, l.onload = function(e) {
+ n._finishedUploading(t, l, e)
+ }, l.ontimeout = function() {
+ r._handleUploadError(t, l, "Request timedout after ".concat(r.options.timeout / 1e3, " seconds"))
+ }, l.onerror = function() {
+ a._handleUploadError(t, l)
+ }, (null != l.upload ? l.upload : l).onprogress = function(e) {
+ return o._updateFilesUploadProgress(t, l, e)
+ };
+ var v = {
+ Accept: "application/json",
+ "Cache-Control": "no-cache",
+ "X-Requested-With": "XMLHttpRequest"
+ };
+ for (var y in this.options.headers && e(u)(v, this.options.headers), v) {
+ var g = v[y];
+ g && l.setRequestHeader(y, g)
+ }
+ var b = new FormData;
+ if (this.options.params) {
+ var k = this.options.params;
+ for (var w in "function" == typeof k && (k = k.call(this, t, l, t[0].upload.chunked ? this._getChunk(t[0], l) : null)), k) {
+ var F = k[w];
+ if (Array.isArray(F))
+ for (var E = 0; E < F.length; E++) b.append(w, F[E]);
+ else b.append(w, F)
+ }
+ }
+ var x = !0,
+ z = !1,
+ C = void 0;
+ try {
+ for (var S, A = t[Symbol.iterator](); !(x = (S = A.next()).done); x = !0) {
+ var _ = S.value;
+ this.emit("sending", _, l, b)
+ }
+ } catch (e) {
+ z = !0, C = e
+ } finally {
+ try {
+ x || null == A.return || A.return()
+ } finally {
+ if (z) throw C
+ }
+ }
+ this.options.uploadMultiple && this.emit("sendingmultiple", t, l, b), this._addFormElementData(b);
+ for (E = 0; E < i.length; E++) {
+ var T = i[E];
+ b.append(T.name, T.data, T.filename)
+ }
+ this.submitRequest(l, b, t)
+ }
+ }, {
+ key: "_transformFiles",
+ value: function(e, t) {
+ for (var i = this, n = function(n) {
+ i.options.transformFile.call(i, e[n], (function(i) {
+ r[n] = i, ++a === e.length && t(r)
+ }))
+ }, r = [], a = 0, o = 0; o < e.length; o++) n(o)
+ }
+ }, {
+ key: "_addFormElementData",
+ value: function(e) {
+ var t = !0,
+ i = !1,
+ n = void 0;
+ if ("FORM" === this.element.tagName) try {
+ for (var r = this.element.querySelectorAll("input, textarea, select, button")[Symbol.iterator](); !(t = (s = r.next()).done); t = !0) {
+ var a = s.value,
+ o = a.getAttribute("name"),
+ l = a.getAttribute("type");
+ if (l && (l = l.toLowerCase()), null != o)
+ if ("SELECT" === a.tagName && a.hasAttribute("multiple")) {
+ t = !0, i = !1, n = void 0;
+ try {
+ var s;
+ for (r = a.options[Symbol.iterator](); !(t = (s = r.next()).done); t = !0) {
+ var u = s.value;
+ u.selected && e.append(o, u.value)
+ }
+ } catch (e) {
+ i = !0, n = e
+ } finally {
+ try {
+ t || null == r.return || r.return()
+ } finally {
+ if (i) throw n
+ }
+ }
+ } else(!l || "checkbox" !== l && "radio" !== l || a.checked) && e.append(o, a.value)
+ }
+ } catch (e) {
+ i = !0, n = e
+ } finally {
+ try {
+ t || null == r.return || r.return()
+ } finally {
+ if (i) throw n
+ }
+ }
+ }
+ }, {
+ key: "_updateFilesUploadProgress",
+ value: function(e, t, i) {
+ var n = !0,
+ r = !1,
+ a = void 0;
+ if (e[0].upload.chunked) {
+ c = e[0];
+ var o = this._getChunk(c, t);
+ i ? (o.progress = 100 * i.loaded / i.total, o.total = i.total, o.bytesSent = i.loaded) : (o.progress = 100, o.bytesSent = o.total), c.upload.progress = 0, c.upload.total = 0, c.upload.bytesSent = 0;
+ for (var l = 0; l < c.upload.totalChunkCount; l++) c.upload.chunks[l] && void 0 !== c.upload.chunks[l].progress && (c.upload.progress += c.upload.chunks[l].progress, c.upload.total += c.upload.chunks[l].total, c.upload.bytesSent += c.upload.chunks[l].bytesSent);
+ c.upload.progress = c.upload.progress / c.upload.totalChunkCount, this.emit("uploadprogress", c, c.upload.progress, c.upload.bytesSent)
+ } else try {
+ for (var s, u = e[Symbol.iterator](); !(n = (s = u.next()).done); n = !0) {
+ var c;
+ (c = s.value).upload.total && c.upload.bytesSent && c.upload.bytesSent == c.upload.total || (i ? (c.upload.progress = 100 * i.loaded / i.total, c.upload.total = i.total, c.upload.bytesSent = i.loaded) : (c.upload.progress = 100, c.upload.bytesSent = c.upload.total), this.emit("uploadprogress", c, c.upload.progress, c.upload.bytesSent))
+ }
+ } catch (e) {
+ r = !0, a = e
+ } finally {
+ try {
+ n || null == u.return || u.return()
+ } finally {
+ if (r) throw a
+ }
+ }
+ }
+ }, {
+ key: "_finishedUploading",
+ value: function(e, t, i) {
+ var n;
+ if (e[0].status !== o.CANCELED && 4 === t.readyState) {
+ if ("arraybuffer" !== t.responseType && "blob" !== t.responseType && (n = t.responseText, t.getResponseHeader("content-type") && ~t.getResponseHeader("content-type").indexOf("application/json"))) try {
+ n = JSON.parse(n)
+ } catch (e) {
+ i = e, n = "Invalid JSON response from server."
+ }
+ this._updateFilesUploadProgress(e, t), 200 <= t.status && t.status < 300 ? e[0].upload.chunked ? e[0].upload.finishedChunkUpload(this._getChunk(e[0], t), n) : this._finished(e, n, i) : this._handleUploadError(e, t, n)
+ }
+ }
+ }, {
+ key: "_handleUploadError",
+ value: function(e, t, i) {
+ if (e[0].status !== o.CANCELED) {
+ if (e[0].upload.chunked && this.options.retryChunks) {
+ var n = this._getChunk(e[0], t);
+ if (n.retries++ < this.options.retryChunksLimit) return void this._uploadData(e, [n.dataBlock]);
+ console.warn("Retried this chunk too often. Giving up.")
+ }
+ this._errorProcessing(e, i || this.options.dictResponseError.replace("{{statusCode}}", t.status), t)
+ }
+ }
+ }, {
+ key: "submitRequest",
+ value: function(e, t, i) {
+ 1 == e.readyState ? e.send(t) : console.warn("Cannot send this request because the XMLHttpRequest.readyState is not OPENED.")
+ }
+ }, {
+ key: "_finished",
+ value: function(e, t, i) {
+ var n = !0,
+ r = !1,
+ a = void 0;
+ try {
+ for (var l, s = e[Symbol.iterator](); !(n = (l = s.next()).done); n = !0) {
+ var u = l.value;
+ u.status = o.SUCCESS, this.emit("success", u, t, i), this.emit("complete", u)
+ }
+ } catch (e) {
+ r = !0, a = e
+ } finally {
+ try {
+ n || null == s.return || s.return()
+ } finally {
+ if (r) throw a
+ }
+ }
+ if (this.options.uploadMultiple && (this.emit("successmultiple", e, t, i), this.emit("completemultiple", e)), this.options.autoProcessQueue) return this.processQueue()
+ }
+ }, {
+ key: "_errorProcessing",
+ value: function(e, t, i) {
+ var n = !0,
+ r = !1,
+ a = void 0;
+ try {
+ for (var l, s = e[Symbol.iterator](); !(n = (l = s.next()).done); n = !0) {
+ var u = l.value;
+ u.status = o.ERROR, this.emit("error", u, t, i), this.emit("complete", u)
+ }
+ } catch (e) {
+ r = !0, a = e
+ } finally {
+ try {
+ n || null == s.return || s.return()
+ } finally {
+ if (r) throw a
+ }
+ }
+ if (this.options.uploadMultiple && (this.emit("errormultiple", e, t, i), this.emit("completemultiple", e)), this.options.autoProcessQueue) return this.processQueue()
+ }
+ }], [{
+ key: "initClass",
+ value: function() {
+ this.prototype.Emitter = h, this.prototype.events = ["drop", "dragstart", "dragend", "dragenter", "dragover", "dragleave", "addedfile", "addedfiles", "removedfile", "thumbnail", "error", "errormultiple", "processing", "processingmultiple", "uploadprogress", "totaluploadprogress", "sending", "sendingmultiple", "success", "successmultiple", "canceled", "canceledmultiple", "complete", "completemultiple", "reset", "maxfilesexceeded", "maxfilesreached", "queuecomplete"], this.prototype._thumbnailQueue = [], this.prototype._processingThumbnail = !1
+ }
+ }, {
+ key: "uuidv4",
+ value: function() {
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (function(e) {
+ var t = 16 * Math.random() | 0;
+ return ("x" === e ? t : 3 & t | 8).toString(16)
+ }))
+ }
+ }]), o
+ }(h);
+ f.initClass(), f.options = {}, f.optionsForElement = function(e) {
+ return e.getAttribute("id") ? f.options[v(e.getAttribute("id"))] : void 0
+ }, f.instances = [], f.forElement = function(e) {
+ if ("string" == typeof e && (e = document.querySelector(e)), null == (null != e ? e.dropzone : void 0)) throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone.");
+ return e.dropzone
+ }, f.discover = function() {
+ var e;
+ if (document.querySelectorAll) e = document.querySelectorAll(".dropzone");
+ else {
+ e = [];
+ var t = function(t) {
+ return function() {
+ var i = [],
+ n = !0,
+ r = !1,
+ a = void 0;
+ try {
+ for (var o, l = t[Symbol.iterator](); !(n = (o = l.next()).done); n = !0) {
+ var s = o.value;
+ /(^| )dropzone($| )/.test(s.className) ? i.push(e.push(s)) : i.push(void 0)
+ }
+ } catch (e) {
+ r = !0, a = e
+ } finally {
+ try {
+ n || null == l.return || l.return()
+ } finally {
+ if (r) throw a
+ }
+ }
+ return i
+ }()
+ };
+ t(document.getElementsByTagName("div")), t(document.getElementsByTagName("form"))
+ }
+ return function() {
+ var t = [],
+ i = !0,
+ n = !1,
+ r = void 0;
+ try {
+ for (var a, o = e[Symbol.iterator](); !(i = (a = o.next()).done); i = !0) {
+ var l = a.value;
+ !1 !== f.optionsForElement(l) ? t.push(new f(l)) : t.push(void 0)
+ }
+ } catch (e) {
+ n = !0, r = e
+ } finally {
+ try {
+ i || null == o.return || o.return()
+ } finally {
+ if (n) throw r
+ }
+ }
+ return t
+ }()
+ }, f.blockedBrowsers = [/opera.*(Macintosh|Windows Phone).*version\/12/i], f.isBrowserSupported = function() {
+ var e = !0;
+ if (window.File && window.FileReader && window.FileList && window.Blob && window.FormData && document.querySelector)
+ if ("classList" in document.createElement("a")) {
+ void 0 !== f.blacklistedBrowsers && (f.blockedBrowsers = f.blacklistedBrowsers);
+ var t = !0,
+ i = !1,
+ n = void 0;
+ try {
+ for (var r, a = f.blockedBrowsers[Symbol.iterator](); !(t = (r = a.next()).done); t = !0) {
+ r.value.test(navigator.userAgent) && (e = !1)
+ }
+ } catch (e) {
+ i = !0, n = e
+ } finally {
+ try {
+ t || null == a.return || a.return()
+ } finally {
+ if (i) throw n
+ }
+ }
+ } else e = !1;
+ else e = !1;
+ return e
+ }, f.dataURItoBlob = function(e) {
+ for (var t = atob(e.split(",")[1]), i = e.split(",")[0].split(":")[1].split(";")[0], n = new ArrayBuffer(t.length), r = new Uint8Array(n), a = 0, o = t.length, l = 0 <= o; l ? a <= o : a >= o; l ? a++ : a--) r[a] = t.charCodeAt(a);
+ return new Blob([n], {
+ type: i
+ })
+ };
+ var m = function(e, t) {
+ return e.filter((function(e) {
+ return e !== t
+ })).map((function(e) {
+ return e
+ }))
+ },
+ v = function(e) {
+ return e.replace(/[\-_](\w)/g, (function(e) {
+ return e.charAt(1).toUpperCase()
+ }))
+ };
+ f.createElement = function(e) {
+ var t = document.createElement("div");
+ return t.innerHTML = e, t.childNodes[0]
+ }, f.elementInside = function(e, t) {
+ if (e === t) return !0;
+ for (; e = e.parentNode;)
+ if (e === t) return !0;
+ return !1
+ }, f.getElement = function(e, t) {
+ var i;
+ if ("string" == typeof e ? i = document.querySelector(e) : null != e.nodeType && (i = e), null == i) throw new Error("Invalid `".concat(t, "` option provided. Please provide a CSS selector or a plain HTML element."));
+ return i
+ }, f.getElements = function(e, t) {
+ var i, n;
+ if (e instanceof Array) {
+ n = [];
+ try {
+ var r = !0,
+ a = !1,
+ o = void 0;
+ try {
+ for (var l = e[Symbol.iterator](); !(r = (s = l.next()).done); r = !0) i = s.value, n.push(this.getElement(i, t))
+ } catch (e) {
+ a = !0, o = e
+ } finally {
+ try {
+ r || null == l.return || l.return()
+ } finally {
+ if (a) throw o
+ }
+ }
+ } catch (e) {
+ n = null
+ }
+ } else if ("string" == typeof e) {
+ n = [];
+ r = !0, a = !1, o = void 0;
+ try {
+ var s;
+ for (l = document.querySelectorAll(e)[Symbol.iterator](); !(r = (s = l.next()).done); r = !0) i = s.value, n.push(i)
+ } catch (e) {
+ a = !0, o = e
+ } finally {
+ try {
+ r || null == l.return || l.return()
+ } finally {
+ if (a) throw o
+ }
+ }
+ } else null != e.nodeType && (n = [e]);
+ if (null == n || !n.length) throw new Error("Invalid `".concat(t, "` option provided. Please provide a CSS selector, a plain HTML element or a list of those."));
+ return n
+ }, f.confirm = function(e, t, i) {
+ return window.confirm(e) ? t() : null != i ? i() : void 0
+ }, f.isValidFile = function(e, t) {
+ if (!t) return !0;
+ t = t.split(",");
+ var i = e.type,
+ n = i.replace(/\/.*$/, ""),
+ r = !0,
+ a = !1,
+ o = void 0;
+ try {
+ for (var l, s = t[Symbol.iterator](); !(r = (l = s.next()).done); r = !0) {
+ var u = l.value;
+ if ("." === (u = u.trim()).charAt(0)) {
+ if (-1 !== e.name.toLowerCase().indexOf(u.toLowerCase(), e.name.length - u.length)) return !0
+ } else if (/\/\*$/.test(u)) {
+ if (n === u.replace(/\/.*$/, "")) return !0
+ } else if (i === u) return !0
+ }
+ } catch (e) {
+ a = !0, o = e
+ } finally {
+ try {
+ r || null == s.return || s.return()
+ } finally {
+ if (a) throw o
+ }
+ }
+ return !1
+ }, "undefined" != typeof jQuery && null !== jQuery && (jQuery.fn.dropzone = function(e) {
+ return this.each((function() {
+ return new f(this, e)
+ }))
+ }), f.ADDED = "added", f.QUEUED = "queued", f.ACCEPTED = f.QUEUED, f.UPLOADING = "uploading", f.PROCESSING = f.UPLOADING, f.CANCELED = "canceled", f.ERROR = "error", f.SUCCESS = "success";
+ var y = function(e, t, i, n, r, a, o, l, s, u) {
+ var c = function(e) {
+ e.naturalWidth;
+ var t = e.naturalHeight,
+ i = document.createElement("canvas");
+ i.width = 1, i.height = t;
+ var n = i.getContext("2d");
+ n.drawImage(e, 0, 0);
+ for (var r = n.getImageData(1, 0, 1, t).data, a = 0, o = t, l = t; l > a;) 0 === r[4 * (l - 1) + 3] ? o = l : a = l, l = o + a >> 1;
+ var s = l / t;
+ return 0 === s ? 1 : s
+ }(t);
+ return e.drawImage(t, i, n, r, a, o, l, s, u / c)
+ },
+ g = function() {
+ "use strict";
+
+ function e() {
+ i(this, e)
+ }
+ return r(e, null, [{
+ key: "initClass",
+ value: function() {
+ this.KEY_STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
+ }
+ }, {
+ key: "encode64",
+ value: function(e) {
+ for (var t = "", i = void 0, n = void 0, r = "", a = void 0, o = void 0, l = void 0, s = "", u = 0; a = (i = e[u++]) >> 2, o = (3 & i) << 4 | (n = e[u++]) >> 4, l = (15 & n) << 2 | (r = e[u++]) >> 6, s = 63 & r, isNaN(n) ? l = s = 64 : isNaN(r) && (s = 64), t = t + this.KEY_STR.charAt(a) + this.KEY_STR.charAt(o) + this.KEY_STR.charAt(l) + this.KEY_STR.charAt(s), i = n = r = "", a = o = l = s = "", u < e.length;);
+ return t
+ }
+ }, {
+ key: "restore",
+ value: function(e, t) {
+ if (!e.match("data:image/jpeg;base64,")) return t;
+ var i = this.decode64(e.replace("data:image/jpeg;base64,", "")),
+ n = this.slice2Segments(i),
+ r = this.exifManipulation(t, n);
+ return "data:image/jpeg;base64,".concat(this.encode64(r))
+ }
+ }, {
+ key: "exifManipulation",
+ value: function(e, t) {
+ var i = this.getExifArray(t),
+ n = this.insertExif(e, i);
+ return new Uint8Array(n)
+ }
+ }, {
+ key: "getExifArray",
+ value: function(e) {
+ for (var t = void 0, i = 0; i < e.length;) {
+ if (255 === (t = e[i])[0] & 225 === t[1]) return t;
+ i++
+ }
+ return []
+ }
+ }, {
+ key: "insertExif",
+ value: function(e, t) {
+ var i = e.replace("data:image/jpeg;base64,", ""),
+ n = this.decode64(i),
+ r = n.indexOf(255, 3),
+ a = n.slice(0, r),
+ o = n.slice(r),
+ l = a;
+ return l = (l = l.concat(t)).concat(o)
+ }
+ }, {
+ key: "slice2Segments",
+ value: function(e) {
+ for (var t = 0, i = [];;) {
+ if (255 === e[t] & 218 === e[t + 1]) break;
+ if (255 === e[t] & 216 === e[t + 1]) t += 2;
+ else {
+ var n = t + (256 * e[t + 2] + e[t + 3]) + 2,
+ r = e.slice(t, n);
+ i.push(r), t = n
+ }
+ if (t > e.length) break
+ }
+ return i
+ }
+ }, {
+ key: "decode64",
+ value: function(e) {
+ var t = void 0,
+ i = void 0,
+ n = "",
+ r = void 0,
+ a = void 0,
+ o = "",
+ l = 0,
+ s = [];
+ for (/[^A-Za-z0-9\+\/\=]/g.exec(e) && console.warn("There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\nExpect errors in decoding."), e = e.replace(/[^A-Za-z0-9\+\/\=]/g, ""); t = this.KEY_STR.indexOf(e.charAt(l++)) << 2 | (r = this.KEY_STR.indexOf(e.charAt(l++))) >> 4, i = (15 & r) << 4 | (a = this.KEY_STR.indexOf(e.charAt(l++))) >> 2, n = (3 & a) << 6 | (o = this.KEY_STR.indexOf(e.charAt(l++))), s.push(t), 64 !== a && s.push(i), 64 !== o && s.push(n), t = i = n = "", r = a = o = "", l < e.length;);
+ return s
+ }
+ }]), e
+ }();
+ g.initClass();
+ window.Dropzone = f
+}();
+//# sourceMappingURL=dropzone-min.js.map
\ No newline at end of file
diff --git a/skanhama/static/dropzone.css b/skanhama/static/dropzone.css
new file mode 100644
index 0000000..b9c0814
--- /dev/null
+++ b/skanhama/static/dropzone.css
@@ -0,0 +1,265 @@
+@keyframes passing-through{
+ 0%{
+ opacity:0;
+ transform:translateY(40px)
+ }
+ 30%,70%{
+ opacity:1;
+ transform:translateY(0px)
+ }
+ 100%{
+ opacity:0;
+ transform:translateY(-40px)
+ }
+}
+@keyframes slide-in{
+ 0%{
+ opacity:0;
+ transform:translateY(40px)
+ }
+ 30%{
+ opacity:1;
+ transform:translateY(0px)
+ }
+}
+@keyframes pulse{
+ 0%{
+ transform:scale(1)
+ }
+ 10%{
+ transform:scale(1.1)
+ }
+ 20%{
+ transform:scale(1)
+ }
+}
+.dropzone,.dropzone *{
+ box-sizing:border-box
+}
+.dropzone{
+ min-height:150px;
+ border:1px solid rgba(0,0,0,.8);
+ border-radius:5px;
+ padding:20px 20px
+}
+.dropzone.dz-clickable{
+ cursor:pointer
+}
+.dropzone.dz-clickable *{
+ cursor:default
+}
+.dropzone.dz-clickable .dz-message,.dropzone.dz-clickable .dz-message *{
+ cursor:pointer
+}
+.dropzone.dz-started .dz-message{
+ display:none
+}
+.dropzone.dz-drag-hover{
+ border-style:solid
+}
+.dropzone.dz-drag-hover .dz-message{
+ opacity:.5
+}
+.dropzone .dz-message{
+ text-align:center;
+ margin:2em 0
+}
+.dropzone .dz-message .dz-button{
+ background:none;
+ color:inherit;
+ border:none;
+ padding:0;
+ font:inherit;
+ cursor:pointer;
+ outline:inherit
+}
+.dropzone .dz-preview{
+ position:relative;
+ display:inline-block;
+ vertical-align:top;
+ margin:16px;
+ min-height:100px
+}
+.dropzone .dz-preview:hover{
+ z-index:1000
+}
+.dropzone .dz-preview:hover .dz-details{
+ opacity:1
+}
+.dropzone .dz-preview.dz-file-preview .dz-image{
+ border-radius:20px;
+ background:#999;
+ background:linear-gradient(to bottom, #eee, #ddd)
+}
+.dropzone .dz-preview.dz-file-preview .dz-details{
+ opacity:1
+}
+.dropzone .dz-preview.dz-image-preview{
+ background:#fff
+}
+.dropzone .dz-preview.dz-image-preview .dz-details{
+ transition:opacity .2s linear
+}
+.dropzone .dz-preview .dz-remove{
+ font-size:14px;
+ text-align:center;
+ display:block;
+ cursor:pointer;
+ border:none
+}
+.dropzone .dz-preview .dz-remove:hover{
+ text-decoration:underline
+}
+.dropzone .dz-preview:hover .dz-details{
+ opacity:1
+}
+.dropzone .dz-preview .dz-details{
+ z-index:20;
+ position:absolute;
+ top:0;
+ left:0;
+ opacity:0;
+ font-size:13px;
+ min-width:100%;
+ max-width:100%;
+ padding:2em 1em;
+ text-align:center;
+ color:rgba(0,0,0,.9);
+ line-height:150%
+}
+.dropzone .dz-preview .dz-details .dz-size{
+ margin-bottom:1em;
+ font-size:16px
+}
+.dropzone .dz-preview .dz-details .dz-filename{
+ white-space:nowrap
+}
+.dropzone .dz-preview .dz-details .dz-filename:hover span{
+ border:1px solid rgba(200,200,200,.8);
+ background-color:rgba(255,255,255,.8)
+}
+.dropzone .dz-preview .dz-details .dz-filename:not(:hover){
+ overflow:hidden;
+ text-overflow:ellipsis
+}
+.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span{
+ border:1px solid transparent
+}
+.dropzone .dz-preview .dz-details .dz-filename span,.dropzone .dz-preview .dz-details .dz-size span{
+ background-color:rgba(255,255,255,.4);
+ padding:0 .4em;
+ border-radius:3px
+}
+.dropzone .dz-preview:hover .dz-image img{
+ transform:scale(1.05, 1.05);
+ filter:blur(8px)
+}
+.dropzone .dz-preview .dz-image{
+ border-radius:20px;
+ overflow:hidden;
+ width:120px;
+ height:120px;
+ position:relative;
+ display:block;
+ z-index:10
+}
+.dropzone .dz-preview .dz-image img{
+ display:block
+}
+.dropzone .dz-preview.dz-success .dz-success-mark{
+ animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1)
+}
+.dropzone .dz-preview.dz-error .dz-error-mark{
+ opacity:1;
+ animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1)
+}
+.dropzone .dz-preview .dz-success-mark,.dropzone .dz-preview .dz-error-mark{
+ pointer-events:none;
+ opacity:0;
+ z-index:500;
+ position:absolute;
+ display:block;
+ top:50%;
+ left:50%;
+ margin-left:-27px;
+ margin-top:-27px;
+ background:rgba(0,0,0,.8);
+ border-radius:50%
+}
+.dropzone .dz-preview .dz-success-mark svg,.dropzone .dz-preview .dz-error-mark svg{
+ display:block;
+ width:54px;
+ height:54px;
+ fill:#fff
+}
+.dropzone .dz-preview.dz-processing .dz-progress{
+ opacity:1;
+ transition:all .2s linear
+}
+.dropzone .dz-preview.dz-complete .dz-progress{
+ opacity:0;
+ transition:opacity .4s ease-in
+}
+.dropzone .dz-preview:not(.dz-processing) .dz-progress{
+ animation:pulse 6s ease infinite
+}
+.dropzone .dz-preview .dz-progress{
+ opacity:1;
+ z-index:1000;
+ pointer-events:none;
+ position:absolute;
+ height:20px;
+ top:50%;
+ margin-top:-10px;
+ left:15%;
+ right:15%;
+ border:3px solid rgba(0,0,0,.8);
+ background:rgba(0,0,0,.8);
+ border-radius:10px;
+ overflow:hidden
+}
+.dropzone .dz-preview .dz-progress .dz-upload{
+ background:#fff;
+ display:block;
+ position:relative;
+ height:100%;
+ width:0;
+ transition:width 300ms ease-in-out;
+ border-radius:17px
+}
+.dropzone .dz-preview.dz-error .dz-error-message{
+ display:block
+}
+.dropzone .dz-preview.dz-error:hover .dz-error-message{
+ opacity:1;
+ pointer-events:auto
+}
+.dropzone .dz-preview .dz-error-message{
+ pointer-events:none;
+ z-index:1000;
+ position:absolute;
+ display:block;
+ display:none;
+ opacity:0;
+ transition:opacity .3s ease;
+ border-radius:8px;
+ font-size:13px;
+ top:130px;
+ left:-10px;
+ width:140px;
+ background:#b10606;
+ padding:.5em 1em;
+ color:#fff
+}
+.dropzone .dz-preview .dz-error-message:after{
+ content:"";
+ position:absolute;
+ top:-6px;
+ left:64px;
+ width:0;
+ height:0;
+ border-left:6px solid transparent;
+ border-right:6px solid transparent;
+ border-bottom:6px solid #b10606
+}
+/*# sourceMappingURL=dropzone.css.map */
\ No newline at end of file
diff --git a/skanhama/static/scripts.js b/skanhama/static/scripts.js
index 3165577..f108f41 100644
--- a/skanhama/static/scripts.js
+++ b/skanhama/static/scripts.js
@@ -1,3 +1,4 @@
+// - Navbar Search - //
// Handle opening and closing of the navbar search input
// Opens on search icon click and closes when user presses outside the search input
const navSearchIcon = document.getElementById("nav-search-icon");
@@ -22,6 +23,7 @@ const navSearchClickOut = (e) => {
}
};
+// - Account Menu - //
// Handle opening and closing of the Account Menu
// Opens on Account icon click and closes when user presses outside the menu
const accountMenuIcon = document.getElementById("accountMenuIcon");
@@ -47,6 +49,7 @@ const accountMenuClickOut = (e) => {
}
}
+// - Requirements Fields - //
// Handle adding of Upload Requirements input fields
// Adds a new div with inputs on icon click
const reqsAddIcon = document.getElementById("icon-reqs-add");
@@ -90,6 +93,204 @@ function reqsRemoveInputFunction() {
this.parentElement.remove();
}
+// Printing the field input data to the form input
+const reqsManual = document.getElementById("reqs-manual");
+const reqsFormControl = document.getElementById("requirements");
+if (reqsManual) {
+ reqsManual.addEventListener("click", reqsDataCompiler);
+}
+function reqsDataCompiler() {
+ let dict = {};
+ const names = document.querySelectorAll(".fc-reqs-name");
+ const links = document.querySelectorAll(".fc-reqs-link");
+ const notes = document.querySelectorAll(".fc-reqs-note");
+ for (let i = 0; i < names.length; i++){
+ if (names[i].value !== "") {
+ dict[i] = [names[i].value, links[i].value, notes[i].value];
+ }
+ }
+ reqsFormControl.textContent = JSON.stringify(dict);
+}
+
+// Print on form submit
+const submit = document.getElementById("submit");
+if (submit) {
+ reqsDataCompiler();
+}
+
+// - Dropzone.js Config - //
+// Upload Dropzone
+if (document.getElementById("dropzoneAnimation")) {
+ // Handle dismiss icon event on error display
+ const errorDismiss1 = document.getElementById("js-error-dismiss-file");
+ const errorDismiss2 = document.getElementById("js-error-dismiss-banner");
+ const errorDismiss3 = document.getElementById("js-error-dismiss-gallery");
+ if (errorDismiss1) {
+ errorDismiss1.addEventListener("click", errorDismiss);
+ }
+ if (errorDismiss2) {
+ errorDismiss2.addEventListener("click", errorDismiss);
+ }
+ if (errorDismiss3) {
+ errorDismiss3.addEventListener("click", errorDismiss);
+ }
+ function errorDismiss() {
+ this.parentElement.classList.add("hidden");
+ }
+
+ // Options - Animation zip file
+ const dropzoneOptionsFile = {
+ dictDefaultMessage: 'Drop your file here or click to select.
Max file size: 40 MB. Accepted file format: .zip.',
+ paramName: "file",
+ maxFilesize: 40, // MB
+ acceptedFiles: ".zip",
+ addRemoveLinks: true,
+ dictRemoveFile: "Remove",
+ dictCancelUpload: "Cancel",
+ uploadMultiple: false,
+ maxFiles: 1,
+ url: "/upload",
+ init: function () {
+ let container = document.getElementById("js-error-file");
+ let error = document.getElementById("js-error-file-text");
+ let error_text = document.createTextNode("");
+ this.on("addedfile", function (file) {
+ let _this = this;
+ console.log(file.name + " -> type: " + file.type);
+ if ($.inArray(file.type, ["application/x-zip-compressed", "application/zip"]) === -1) {
+ _this.removeFile(file);
+ container.classList.remove("hidden");
+ error_text.data = "Incompatible file format. Please ensure that the file is a .zip file.";
+ error.appendChild(error_text);
+ console.log("error > incorrect file type for " + file.name)
+ } else if (this.files.length > 1) {
+ _this.removeFile(file);
+ console.log("error > too many files (" + this.files.length + ") reached when adding " + file.name)
+ error_text.data = "You have reached the maximum number of files and cannot upload any more."
+ error.appendChild(error_text);
+ container.classList.remove("hidden");
+ }
+ });
+ this.on("success", function (file) {
+ console.log("success > " + file.name);
+ if (!container.classList.contains("hidden")) {
+ error.removeChild(error_text);
+ container.classList.add("hidden");
+ }
+ });
+ },
+ accept: function(file, done) {
+ return done();
+ }
+ };
+ // Options - Banner Image
+ const dropzoneOptionsBanner = {
+ dictDefaultMessage: 'Drop your banner image here or click to select.
Max file size: 2 MB. Accepted file formats: .jpg, .jpeg, .gif, .png.',
+ paramName: "file",
+ maxFilesize: 2, // MB
+ acceptedFiles: ".jpg, .gif, .png, .jpeg",
+ addRemoveLinks: true,
+ dictRemoveFile: "Remove",
+ dictCancelUpload: "Cancel",
+ uploadMultiple: false,
+ maxFiles: 1,
+ createImageThumbnails: true,
+ maxThumbnailFilesize: 2,
+ thumbnailWidth: 96,
+ thumbnailHeight: 96,
+ thumbnailMethod: "crop",
+ url: "/upload",
+ init: function () {
+ let container = document.getElementById("js-error-banner");
+ let error = document.getElementById("js-error-banner-text");
+ let error_text = document.createTextNode("");
+ this.on("addedfile", function (file) {
+ let _this = this;
+ console.log(file.name + " -> type: " + file.type);
+ if ($.inArray(file.type, ["image/jpeg", "image/jpg", "image/png", "image/gif"]) === -1) {
+ _this.removeFile(file);
+ container.classList.remove("hidden");
+ error_text.data = "Incompatible file format. Please ensure all files are either .jpg, .jpeg, .gif or .png.";
+ error.appendChild(error_text);
+ console.log("error > incorrect file type for " + file.name)
+ } else if (this.files.length > 1) {
+ _this.removeFile(file);
+ console.log("error > too many files (" + this.files.length + ") reached when adding " + file.name)
+ error_text.data = "You have reached the maximum number of files and cannot upload any more."
+ error.appendChild(error_text);
+ container.classList.remove("hidden");
+ }
+ });
+ this.on("success", function (file) {
+ console.log("success > " + file.name);
+ if (!container.classList.contains("hidden")) {
+ error.removeChild(error_text);
+ container.classList.add("hidden");
+ }
+ });
+ },
+ accept: function(file, done) {
+ return done();
+ }
+ };
+ // Options - Gallery Images
+ const dropzoneOptionsGallery = {
+ dictDefaultMessage: 'Drop your gallery images here or click to select.
Max size per file: 4 MB. Accepted file formats: .jpg, .jpeg, .gif, .png.',
+ paramName: "file",
+ maxFilesize: 4, // MB
+ acceptedFiles: ".jpg, .gif, .png, .jpeg",
+ resizeWidth: 1080,
+ resizeQuality: 1,
+ addRemoveLinks: true,
+ dictRemoveFile: "Remove",
+ dictCancelUpload: "Cancel",
+ uploadMultiple: true,
+ maxFiles: 27,
+ createImageThumbnails: true,
+ maxThumbnailFilesize: 10,
+ thumbnailWidth: 96,
+ thumbnailHeight: 96,
+ thumbnailMethod: "crop",
+ url: "/upload",
+ init: function () {
+ let container = document.getElementById("js-error-gallery");
+ let error = document.getElementById("js-error-gallery-text");
+ let error_text = document.createTextNode("");
+ this.on("addedfile", function (file) {
+ let _this = this;
+ console.log(file.name + " -> type: " + file.type);
+ if ($.inArray(file.type, ["image/jpeg", "image/jpg", "image/png", "image/gif"]) === -1) {
+ _this.removeFile(file);
+ container.classList.remove("hidden");
+ error_text.data = "Incompatible file format. Please ensure all files are either .jpg, .jpeg, .gif or .png.";
+ error.appendChild(error_text);
+ console.log("error > incorrect file type for " + file.name)
+ } else if (this.files.length > 27) {
+ _this.removeFile(file);
+ console.log("error > too many files (" + this.files.length + ") reached when adding " + file.name)
+ error_text.data = "You have reached the maximum number of files and cannot upload any more."
+ error.appendChild(error_text);
+ container.classList.remove("hidden");
+ }
+ });
+ this.on("success", function (file) {
+ console.log("success > " + file.name);
+ if (!container.classList.contains("hidden")) {
+ error.removeChild(error_text);
+ container.classList.add("hidden");
+ }
+ });
+ },
+ accept: function(file, done) {
+ return done();
+ }
+ };
+ const dzAnimations = new Dropzone("div#dropzoneAnimation", dropzoneOptionsFile);
+ const dzBanner = new Dropzone("div#dropzoneBanner", dropzoneOptionsBanner);
+ const dzGallery = new Dropzone("div#dropzoneGallery", dropzoneOptionsGallery);
+}
+
+
// Live (Active) Search function in the search bar in the nav menu
// $(function (){
diff --git a/skanhama/static/style.css b/skanhama/static/style.css
index b08e415..2a308d3 100644
--- a/skanhama/static/style.css
+++ b/skanhama/static/style.css
@@ -7,18 +7,18 @@
--container-body-margin: 0.5rem 2rem;
--container-body-padding: 0.25rem;
--row-gap: calc(10vmin + 5px);
- /*--clr-AA: rgb(102, 252, 241);*/
- /*--clr-AB: rgb(69, 149, 143);*/
- /*--clr-BA: rgb(225, 153, 19);*/
- /*--clr-BB: rgb(141, 95, 34);*/
- /*--clr-CA: rgb(139, 57, 187);*/
- /*--clr-CB: rgb(69, 34, 111);*/
- --clr-AA: rgb(253, 41, 122);
- --clr-AB: rgb(163, 47, 88);
- --clr-CA: rgb(243, 165, 21);
- --clr-CB: rgb(141, 95, 34);
- --clr-BA: rgb(139, 57, 187);
- --clr-BB: rgb(69, 34, 111);
+ --clr-AA: rgb(102, 252, 241);
+ --clr-AB: rgb(69, 149, 143);
+ --clr-BA: rgb(225, 153, 19);
+ --clr-BB: rgb(141, 95, 34);
+ --clr-CA: rgb(139, 57, 187);
+ --clr-CB: rgb(69, 34, 111);
+ /*--clr-AA: rgb(253, 41, 122);*/
+ /*--clr-AB: rgb(163, 47, 88);*/
+ /*--clr-CA: rgb(243, 165, 21);*/
+ /*--clr-CB: rgb(141, 95, 34);*/
+ /*--clr-BA: rgb(139, 57, 187);*/
+ /*--clr-BB: rgb(69, 34, 111);*/
--clr-border-light: rgb(42, 48, 52);
--clr-border-dark: rgb(15, 15, 23);
@@ -40,8 +40,10 @@
--clr-bg-content-accent: rgb(33, 33, 36);
--clr-bg-content-dark: rgb(29, 29, 31);
--clr-bg-footer: var(--clr-bg-header);
- --clr-bg-hover: rgb(43, 43, 49);
- --clr-bg-btn: rgba(16, 16, 19, 0.4);
+ --clr-btn-hover: rgb(35, 35, 40);
+ --clr-btn-solid: rgba(16, 16, 19, 0.4);
+ --clr-bg-fc: rgba(52, 56, 68, 0.15);
+ --clr-bg-light: rgb(222, 225, 229);
--size-h1: 1.3em;
--size-h2: 1.2em;
@@ -106,7 +108,7 @@ a:visited {
***********************************************************************/
/* Misc */
.hidden {
- display: none;
+ display: none !important;
}
/* Main */
.main {
@@ -393,7 +395,7 @@ input:-webkit-autofill:active{
font-family: 'Work Sans', sans-serif;
font-weight: 400;
color: var(--clr-text-light);
- background: rgba(52, 56, 68, 0.15);
+ background: var(--clr-bg-fc);
border: solid var(--clr-offsetA) 1px;
}
.form-control:focus {
@@ -418,6 +420,7 @@ input:-webkit-autofill:active{
/*
Upload Page Forms
+
*/
/* Upload Divs */
.upload-content {
@@ -506,7 +509,10 @@ input:-webkit-autofill:active{
flex-basis: 35%;
}
#upload-category-nsfw {
- flex-basis: 35%;
+ flex-basis: 25%;
+}
+#upload-category-game {
+ flex-basis: 25%;
}
#upload-desc-summary {
width: 50%;
@@ -559,8 +565,115 @@ input:-webkit-autofill:active{
flex-basis: 40%;
}
+/*
+ Dropzone
+*/
+.dropzone {
+ background-color: var(--clr-bg-fc);
+ border: solid var(--clr-offsetA) 1px !important;
+ border-radius: 0 !important;
+ padding: 0.5rem !important;
+ min-height: 175px !important;
+}
+.dz-image {
+ width: 6rem !important;
+ height: 6rem !important;
+ border-radius: 10px !important;
+}
+/* Filename, expands on hover */
+.dz-details {
+ padding: 1.25rem 0.75rem !important;
+}
+.dz-details span {
+ background-color: transparent !important;
+ border: none !important;
+ border-radius: 0 !important;
+ padding: 0 !important;
+}
+.dz-filename:hover span {
+ background-image: var(--gradient-B) !important;
+ border-radius: 5px !important;
+ padding: 0.25rem !important;
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
+}
+/* Remove button */
+.dz-remove {
+ width: inherit;
+ margin-top: 0.3rem;
+ border-radius: 5px;
+ text-decoration: none;
+ background-color: var(--clr-btn-solid);
+ color: white;
+ border: none !important;
+ line-height: 1rem !important;
+ padding: 0.25rem;
+}
+.dz-remove:hover {
+ background-image: var(--gradient-B) !important;
+ text-decoration: none !important;
+}
+/* Hint text */
+.dz-button {
+ font-size: 0.9rem !important;
+ line-height: 2rem !important;
+}
+/* Error message */
+.dz-error-message {
+ background: var(--clr-bg-light) !important;
+ color: var(--clr-text-dark) !important;
+}
+.dz-error-message:after {
+ border-bottom: 6px solid var(--clr-bg-light) !important;
+}
+/* Image previews */
+.dz-image-preview {
+ background: transparent !important;
+}
+/*
+ Javascript enforced error checking
+
+*/
+.js-upload-error {
+ display: flex;
+ flex-direction: row;
+ margin: 0.5rem 0 0 0;
+ padding: 0.25rem;
+ background-color: rgba(156, 41, 58, 0.9);
+ color: var(--clr-text-light);
+ font-size: 0.9rem;
+ width: max-content;
+ border-radius: 3px;
+}
+.js-error-dismiss {
+ font-size: 1rem;
+ padding: 0;
+ margin: 0 0.25rem 0 1rem;
+ cursor: pointer;
+}
+/*
+ Upload Submit Part
+
+*/
+#upload-submit-container {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ margin: 2rem 0;
+}
+#upload-submit-a {
+ flex-basis: 50%;
+}
+#upload-submit-b {
+ flex-basis: 50%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-evenly;
+}
/*
Misc Forms
@@ -782,7 +895,7 @@ Misc Forms
border: solid 1px rgba(0, 0, 0, 0);
}
.dropdown-content a:hover {
- background: var(--clr-bg-hover);
+ background: var(--clr-btn-hover);
border: solid 1px;
border-image: var(--gradient-A);
}
@@ -797,49 +910,51 @@ Misc Forms
background: var(--clr-bg-footer);
}
-/* Buttons */
+/*
+ Buttons
+
+*/
.btn {
width: 8rem;
height: 2.4rem;
display: inline-flex;
justify-content: center;
align-items: center;
-}
-.btn {
cursor: pointer;
text-decoration: none;
color: var(--clr-text-light);
font-size: var(--size-button);
- background-color: var(--clr-bg-btn);
- border: solid var(--clr-border-light) 1px;
-}
-.btn-clear {
- background: none;
+ background-color: var(--clr-btn-solid);
border: solid var(--clr-border-light) 1px;
}
.btn:hover {
color: var(--clr-text-light) !important;
- background: var(--clr-bg-hover);
+ background: var(--clr-btn-hover);
border: solid 1px;
border-image: var(--gradient-A);
}
.btn:visited {
color: var(--clr-text-light);
}
+/* TODO: check if btn-solid is deprecated */
.btn-solid {
color: var(--clr-text-light);
- background: var(--clr-bg-btn);
+ background: var(--clr-btn-solid);
border: solid var(--clr-AA) 1px;
}
.btn-solid:hover {
color: var(--clr-text-light) !important;
- background: var(--clr-bg-hover);
+ background: var(--clr-btn-hover);
border: solid 1px;
border-image: var(--gradient-A);
}
.btn-solid:visited {
color: var(--clr-text-light);
}
+.btn-upload {
+ width: 12rem;
+ height: 3rem;
+}
@@ -868,7 +983,7 @@ Misc Forms
transition: all 150ms ease;
}
.nav-sidebar a:hover {
- background: var(--clr-bg-hover);
+ background: var(--clr-btn-hover);
outline: none;
border: solid var(--clr-bg-header) 1px;
border-image: var(--gradient-A);
diff --git a/skanhama/templates/layout.html b/skanhama/templates/layout.html
index 8c99d0e..3696ee4 100644
--- a/skanhama/templates/layout.html
+++ b/skanhama/templates/layout.html
@@ -19,8 +19,11 @@
-
-
+
+
+ {% block route_references %}
+
+ {% endblock %}
@@ -89,11 +92,11 @@
{{ current_user.username }}
-
+