changed structure for docker usage
This commit is contained in:
BIN
app/favicon/apple-touch-icon.png
Normal file
BIN
app/favicon/apple-touch-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.4 KiB |
BIN
app/favicon/favicon-96x96.png
Normal file
BIN
app/favicon/favicon-96x96.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
BIN
app/favicon/favicon.ico
Normal file
BIN
app/favicon/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
29
app/favicon/favicon.svg
Normal file
29
app/favicon/favicon.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 78 KiB |
1
app/favicon/generated_from.txt
Normal file
1
app/favicon/generated_from.txt
Normal file
@@ -0,0 +1 @@
|
||||
https://realfavicongenerator.net/
|
||||
21
app/favicon/site.webmanifest
Normal file
21
app/favicon/site.webmanifest
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "Unizeug",
|
||||
"short_name": "Unizeug",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/favicon/web-app-manifest-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/favicon/web-app-manifest-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
BIN
app/favicon/web-app-manifest-192x192.png
Normal file
BIN
app/favicon/web-app-manifest-192x192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.0 KiB |
BIN
app/favicon/web-app-manifest-512x512.png
Normal file
BIN
app/favicon/web-app-manifest-512x512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
164
app/index.html
Normal file
164
app/index.html
Normal file
@@ -0,0 +1,164 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<title>Unizeug uploader</title>
|
||||
<link rel="stylesheet" href="static/style.css" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.4.456/pdf.min.js"></script>
|
||||
<script src="static/app.js" defer></script>
|
||||
<script src="static/autocomplete.js" defer></script>
|
||||
<script src="static/dynhide.js" defer></script>
|
||||
<script src="static/filedrop.js" defer></script>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
href="/favicon/favicon-96x96.png"
|
||||
sizes="96x96"
|
||||
/>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon/favicon.svg" />
|
||||
<link rel="shortcut icon" href="/favicon/favicon.ico" />
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="/favicon/apple-touch-icon.png"
|
||||
/>
|
||||
<meta name="apple-mobile-web-app-title" content="Unizeug" />
|
||||
<link rel="manifest" href="/favicon/site.webmanifest" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- The Modal -->
|
||||
<div id="loading" class="modal">
|
||||
<!-- Modal content -->
|
||||
<div class="loading-content">
|
||||
<!-- <span class="close">×</span> -->
|
||||
<div class="loader"></div>
|
||||
<p id="upload_status" class="upload_status_text">Uploading</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- main -->
|
||||
<div class="main">
|
||||
<div class="left" id="controldiv">
|
||||
<div id="fileupload">
|
||||
<form id="uploadform" enctype="multipart/form-data">
|
||||
<div class="filetop">
|
||||
<!-- <label for="filepicker">Choose a file</label> -->
|
||||
<input
|
||||
type="file"
|
||||
name="files"
|
||||
id="filepicker"
|
||||
multiple
|
||||
placeholder="Drop File"
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" id="upload" method="POST" class="fileupload">
|
||||
Upload
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div id="submitdiv">
|
||||
<form id="submitform" ,onsubmit="submitFile(event)">
|
||||
<label for="lva">Lehrveranstaltung:</label>
|
||||
<div class="autocomplete">
|
||||
<input
|
||||
type="text"
|
||||
id="lva"
|
||||
name="lva"
|
||||
placeholder="Lehrveranstaltung"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
<!-- <br /> -->
|
||||
<label for="prof">Vortragende*r:</label>
|
||||
<div class="autocomplete">
|
||||
<input
|
||||
type="text"
|
||||
id="prof"
|
||||
name="prof"
|
||||
placeholder="Vortragende*r"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
<!-- <br /> -->
|
||||
<label for="name">Name:</label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
name="fname"
|
||||
placeholder="Prüfung"
|
||||
/><br />
|
||||
<label for="sem">Semester:</label>
|
||||
<input type="text" id="sem" name="sem" placeholder="2024W" /><br />
|
||||
<input
|
||||
type="radio"
|
||||
id="pruefung"
|
||||
name="stype"
|
||||
value="0"
|
||||
checked="checked"
|
||||
/>
|
||||
<label for="pruefung">Prüfung</label><br />
|
||||
<input type="radio" id="klausur" name="stype" value="1" />
|
||||
<label for="klausur">Klausur</label><br />
|
||||
<input type="radio" id="uebung" name="stype" value="2" />
|
||||
<label for="uebung">Übung</label><br />
|
||||
<input type="radio" id="labor" name="stype" value="3" />
|
||||
<label for="labor">Labor</label><br />
|
||||
<input type="radio" id="unterlagen" name="stype" value="4" />
|
||||
<label for="unterlagen">Unterlagen</label><br />
|
||||
<input type="radio" id="zusammenfassungen" name="stype" value="5" />
|
||||
<label for="zusammenfassungen">Zusammenfassung</label><br />
|
||||
<input type="radio" id="multimedia" name="stype" value="6" />
|
||||
<label for="multimedia">Multimedia</label><br />
|
||||
<br />
|
||||
<div id="subcatdiv">
|
||||
<label for="subcat">Veranstaltung</label>
|
||||
<div class="autocomplete">
|
||||
<input
|
||||
type="text"
|
||||
id="subcat"
|
||||
name="subcat"
|
||||
placeholder="Klausur 1"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="datediv">
|
||||
<label for="date">Datum</label>
|
||||
<input
|
||||
type="date"
|
||||
id="date"
|
||||
name="ex_date"
|
||||
placeholder="Drop File"
|
||||
/><br />
|
||||
</div>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="ocr"
|
||||
id="sec_censor"
|
||||
value="True"
|
||||
/><label for="sec_censor">OCR</label><br /><br />
|
||||
<button type="submit" id="send">Senden</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right" id="rightdiv">
|
||||
<div class="buttons" id="buttonsdiv">
|
||||
<button id="prev">Prev</button><button id="next">Next</button>
|
||||
<div>
|
||||
<span id="npage"></span>
|
||||
<span>/</span>
|
||||
<span id="npages"></span>
|
||||
</div>
|
||||
<button id="clr">Clear Page</button><button id="ca">Claer All</button>
|
||||
</div>
|
||||
<div id="cnvdiv">
|
||||
<div class="stack" id="cnvcont">
|
||||
<canvas id="cnv"></canvas>
|
||||
<canvas id="drw_cnv"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
20
app/init.py
20
app/init.py
@@ -2,12 +2,16 @@ from os.path import isdir
|
||||
from stat import S_ISDIR, S_ISREG
|
||||
import re
|
||||
import pathlib
|
||||
import os
|
||||
|
||||
# from base64 import decodebytes
|
||||
import json
|
||||
import mariadb
|
||||
import logging
|
||||
|
||||
import schedule
|
||||
import time
|
||||
|
||||
CATEGORIES = [
|
||||
"Prüfungen",
|
||||
"Klausuren",
|
||||
@@ -18,7 +22,7 @@ CATEGORIES = [
|
||||
"Multimedia",
|
||||
]
|
||||
SUBCAT_CATEGORIES = ["Klausuren", "Übungen", "Labore"]
|
||||
unizeug_path = "/home/wildarch/web/fet_unizeug/unizeug/"
|
||||
unizeug_path = os.environ.get("UNIZEUG_PATH","./unizeug")
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
logging.basicConfig(
|
||||
@@ -31,7 +35,11 @@ info = log.info
|
||||
error = log.error
|
||||
|
||||
db = mariadb.connect(
|
||||
host="localhost", user="wildserver", password="DBPassword", database="Unizeug"
|
||||
host=os.environ.get("DB_HOST", "db"),
|
||||
user=os.environ.get("DB_USER", "user"),
|
||||
password=os.environ.get("DB_PASSWORD", "DBPASSWORD"),
|
||||
database=os.environ.get("DB_DATABASE", "unizeug"),
|
||||
|
||||
)
|
||||
c = db.cursor()
|
||||
try:
|
||||
@@ -62,6 +70,10 @@ except mariadb.OperationalError:
|
||||
c.execute(
|
||||
"CREATE TABLE SubCats(id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,LId BIGINT(20),PId BIGINT(20),cat TINYINT UNSIGNED,name VARCHAR(256), PRIMARY KEY(id))"
|
||||
)
|
||||
try:
|
||||
c.execute("CREATE TABLE FIP(id UUID DEFAULT(UUID()), filename VARCHAR(256), filetype VARCHAR(8),initTimeStamp DATETIME, PRIMARY KEY(id))")
|
||||
except mariadb.OperationalError:
|
||||
pass
|
||||
db.commit()
|
||||
|
||||
|
||||
@@ -161,3 +173,7 @@ def link_prof(firstname, lastname, lid):
|
||||
|
||||
if __name__ == "__main__":
|
||||
get_dirstruct()
|
||||
schedule.every.day.at("04:00","Europe/Vienna").do(get_dirstruct)
|
||||
while True:
|
||||
schedule.run_pending()
|
||||
time.sleep(1)
|
||||
|
||||
34
app/main.py
34
app/main.py
@@ -25,17 +25,15 @@ import mariadb
|
||||
|
||||
import filetype
|
||||
|
||||
import datetime
|
||||
|
||||
import logging
|
||||
import inspect
|
||||
import pathlib
|
||||
|
||||
from starlette.types import HTTPExceptionHandler
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
logging.basicConfig(
|
||||
filename="app.log",
|
||||
filename=os.environ.get("APP_LOG_PATH"),
|
||||
level=logging.INFO,
|
||||
format="[%(asctime)s, %(filename)s:%(lineno)s -> %(funcName)10s() ]%(levelname)s: %(message)s",
|
||||
)
|
||||
@@ -44,7 +42,10 @@ info = log.info
|
||||
error = log.error
|
||||
|
||||
db = mariadb.connect(
|
||||
host="localhost", user="wildserver", password="DBPassword", database="Unizeug"
|
||||
host=os.environ.get("DB_HOST", "db"),
|
||||
user=os.environ.get("DB_USER", "user"),
|
||||
password=os.environ.get("DB_PASSWORD", "DBPASSWORD"),
|
||||
database=os.environ.get("DB_DATABASE", "unizeug"),
|
||||
)
|
||||
|
||||
info("App Started")
|
||||
@@ -53,8 +54,16 @@ info("App Started")
|
||||
|
||||
# startup()
|
||||
app = FastAPI()
|
||||
app.mount("/favicon", StaticFiles(directory="./favicon"), name="favicon")
|
||||
app.mount("/static", StaticFiles(directory="./static"), name="static")
|
||||
app.mount(
|
||||
"/favicon",
|
||||
StaticFiles(directory=os.environ.get("FAVICON_PATH", ".app/favicon")),
|
||||
name="favicon",
|
||||
)
|
||||
app.mount(
|
||||
"/static",
|
||||
StaticFiles(directory=os.environ.get("STATIC_PATH", "./static")),
|
||||
name="static",
|
||||
)
|
||||
|
||||
|
||||
CATEGORIES = [
|
||||
@@ -66,15 +75,16 @@ CATEGORIES = [
|
||||
"Zusammenfassungen",
|
||||
"Multimedia",
|
||||
]
|
||||
APP_ROOT_PATH = os.environ.get("APP_ROOT_PATH", "./app")
|
||||
SUBCAT_CATEGORIES = ["Klausuren", "Übungen", "Labore"]
|
||||
SUBCAT_CATEGORIES_I = [1, 2, 3]
|
||||
EX_DATE_CATEGORIES = ["Prüfungen", "Klausuren"]
|
||||
EX_DATE_CATEGORIES_I = [0, 1]
|
||||
UNIZEUG_PATH = "./app/dest/"
|
||||
FILES_IN_PROGRESS = "./app/files/"
|
||||
EMPTYFILE = "./app/graphics/empty.pdf"
|
||||
UNSUPPORTEDFILE = "./app/graphics/unsupported.pdf"
|
||||
GREETINGFILE = "./app/graphics/greeting.pdf"
|
||||
UNIZEUG_PATH = os.environ.get("UNIZEUG_PATH", "./app/dest")
|
||||
FILES_IN_PROGRESS = f"{APP_ROOT_PATH}/files/"
|
||||
EMPTYFILE = f"{APP_ROOT_PATH}/graphics/empty.pdf"
|
||||
UNSUPPORTEDFILE = f"{APP_ROOT_PATH}/graphics/unsupported.pdf"
|
||||
GREETINGFILE = f"{APP_ROOT_PATH}/graphics/greeting.pdf"
|
||||
|
||||
|
||||
# cur = db.cursor()
|
||||
@@ -151,7 +161,7 @@ def sqlT(
|
||||
@app.get("/")
|
||||
async def get_index():
|
||||
"""gives the Index.html file"""
|
||||
return FileResponse("./index.html")
|
||||
return FileResponse(f"{APP_ROOT_PATH}/index.html")
|
||||
|
||||
|
||||
@app.get("/files/{file_id}")
|
||||
|
||||
407
app/static/app.js
Normal file
407
app/static/app.js
Normal file
@@ -0,0 +1,407 @@
|
||||
class PDFView {
|
||||
constructor(nameRoute) {
|
||||
this.loadingTask = pdfjsLib.getDocument(nameRoute);
|
||||
this.pdfDoc = null;
|
||||
this.canvas = document.querySelector("#cnv");
|
||||
this.ctx = this.canvas.getContext("2d");
|
||||
this.scale = 1.5;
|
||||
this.numPage = 1;
|
||||
this.maxheight =
|
||||
window.innerHeight -
|
||||
document.getElementById("buttonsdiv").getBoundingClientRect().height;
|
||||
this.maxwidth = document
|
||||
.getElementById("cnvdiv")
|
||||
.getBoundingClientRect().width;
|
||||
this.rendering = false;
|
||||
this.loadingTask.promise.then((pdfDoc_) => {
|
||||
this.pdfDoc = pdfDoc_;
|
||||
document.querySelector("#npages").innerHTML = this.pdfDoc.numPages;
|
||||
this.GeneratePDF();
|
||||
});
|
||||
}
|
||||
GeneratePDF() {
|
||||
this.rendering = true;
|
||||
this.pdfDoc.getPage(this.numPage).then((page) => {
|
||||
let unscaled = page.getViewport({ scale: 1.0 });
|
||||
this.scale = Math.min(
|
||||
this.maxheight / unscaled.height,
|
||||
this.maxwidth / unscaled.width,
|
||||
);
|
||||
});
|
||||
this.pdfDoc.getPage(this.numPage).then((page) => {
|
||||
let viewport = page.getViewport({ scale: this.scale });
|
||||
this.canvas.height = viewport.height;
|
||||
this.canvas.width = viewport.width;
|
||||
|
||||
let renderContext = {
|
||||
canvasContext: this.ctx,
|
||||
viewport: viewport,
|
||||
};
|
||||
doc.cnv.width = this.canvas.width;
|
||||
doc.cnv.height = this.canvas.height;
|
||||
document.getElementById("rightdiv").style.width =
|
||||
((doc.cnv.width / screen.width) * 100).toString() + "vw";
|
||||
document.getElementById("controldiv").style.width =
|
||||
((1 - doc.cnv.width / screen.width) * 100).toString() + "vw";
|
||||
doc.pagescales[this.numPage] = {
|
||||
scale: this.scale,
|
||||
width: doc.cnv.width,
|
||||
height: doc.cnv.height,
|
||||
};
|
||||
|
||||
var renderTask = page.render(renderContext);
|
||||
renderTask.promise.then(() => {
|
||||
doc.drawRects();
|
||||
this.rendering = false;
|
||||
});
|
||||
});
|
||||
document.querySelector("#npage").innerHTML = this.numPage;
|
||||
}
|
||||
|
||||
WaitToRender() {
|
||||
if (this.rendering) {
|
||||
window.setTimeout(this.WaitToRender.bind(this), 100);
|
||||
} else {
|
||||
this.GeneratePDF();
|
||||
}
|
||||
}
|
||||
|
||||
PrevPage() {
|
||||
if (this.numPage === 1) {
|
||||
return;
|
||||
}
|
||||
this.numPage--;
|
||||
this.WaitToRender();
|
||||
}
|
||||
|
||||
NextPage() {
|
||||
if (this.numPage >= this.pdfDoc.numPages) {
|
||||
return;
|
||||
}
|
||||
this.numPage++;
|
||||
this.WaitToRender();
|
||||
}
|
||||
RenderPage() {
|
||||
this.WaitToRender();
|
||||
}
|
||||
}
|
||||
class Rectangle {
|
||||
constructor(canvas, sx, sy, ex, ey, color, alpha = 1) {
|
||||
this.x = sx < ex ? sx : ex;
|
||||
this.y = sy < ey ? sy : ey;
|
||||
this.width = Math.abs(ex - sx);
|
||||
this.height = Math.abs(ey - sy);
|
||||
this.color = color;
|
||||
this.context = canvas.getContext("2d");
|
||||
this.alpha = alpha;
|
||||
}
|
||||
draw() {
|
||||
this.context.globalAlpha = this.alpha;
|
||||
this.context.beginPath();
|
||||
this.context.rect(this.x, this.y, this.width, this.height);
|
||||
this.context.fillStyle = this.color;
|
||||
this.context.strokeStyle = "black";
|
||||
this.context.lineWidth = 1;
|
||||
|
||||
this.context.fill();
|
||||
this.context.stroke();
|
||||
}
|
||||
makeTuple() {
|
||||
return [this.x, this.y, this.width, this.height];
|
||||
}
|
||||
}
|
||||
class PDFDocument {
|
||||
constructor(filename, fileID, filetype) {
|
||||
if (filetype === "pdf") {
|
||||
this.pdf = new PDFView(filename);
|
||||
} else {
|
||||
this.pdf = new PDFView("/files/unsupported");
|
||||
}
|
||||
this.filetype = filetype;
|
||||
this.fname = filename;
|
||||
this.fID = fileID;
|
||||
this.rects = [];
|
||||
this.cnv = document.querySelector("#drw_cnv");
|
||||
this.ctx = this.cnv.getContext("2d");
|
||||
this.temprect = new Rectangle(this.cnv, 0, 0, 0, 0, "white", 0);
|
||||
this.pagescales = [];
|
||||
this.startX = 0;
|
||||
this.startY = 0;
|
||||
}
|
||||
drawAll() {
|
||||
//context = cnv.getContext("2d");
|
||||
this.ctx.clearRect(0, 0, this.cnv.width, this.cnv.height);
|
||||
//pdf.RenderPage();
|
||||
this.drawRects();
|
||||
}
|
||||
drawRects() {
|
||||
if (!(this.pdf.numPage in this.rects)) {
|
||||
this.rects[this.pdf.numPage] = [];
|
||||
}
|
||||
this.temprect.draw();
|
||||
for (var i = 0; i < this.rects[this.pdf.numPage].length; i++) {
|
||||
var shape = this.rects[this.pdf.numPage][i];
|
||||
shape.draw();
|
||||
}
|
||||
}
|
||||
addRect(endpos) {
|
||||
var re = new Rectangle(
|
||||
this.cnv,
|
||||
this.startX,
|
||||
this.startY,
|
||||
endpos.x,
|
||||
endpos.y,
|
||||
"black",
|
||||
);
|
||||
this.rects[this.pdf.numPage].push(re);
|
||||
this.drawAll();
|
||||
}
|
||||
clearCnv() {
|
||||
this.rects[this.pdf.numPage] = [];
|
||||
//context = cnv.getContext("2d");
|
||||
this.ctx.clearRect(0, 0, this.cnv.width, this.cnv.height);
|
||||
//pdf.RenderPage();
|
||||
this.temprect = new Rectangle(this.cnv, 0, 0, 0, 0, "black", 0);
|
||||
}
|
||||
clearAll() {
|
||||
this.rects = [];
|
||||
this.clearCnv();
|
||||
}
|
||||
get paramRects() {
|
||||
let prects = [];
|
||||
for (var k = 1; k < this.rects.length; k++) {
|
||||
prects[k - 1] = [];
|
||||
//console.log(this.rects[k]);
|
||||
if (this.rects[k] === undefined) {
|
||||
continue;
|
||||
}
|
||||
//console.log(this.rects[k].length);
|
||||
//console.log(0 < this.rects[k].length);
|
||||
let len = this.rects[k].length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
//console.log(this.rects[k][i]);
|
||||
prects[k - 1].push(this.rects[k][i].makeTuple());
|
||||
//console.log(prects[k][i]);
|
||||
}
|
||||
}
|
||||
return prects;
|
||||
}
|
||||
}
|
||||
var mouseIsDown = false;
|
||||
var modal;
|
||||
var close_loading;
|
||||
var upload_status;
|
||||
//var startX = 0;
|
||||
//var startY = 0;
|
||||
//var pdf;
|
||||
//var cnv = document.querySelector("#drw_cnv");
|
||||
//var ctx = cnv.getContext("2d");
|
||||
//var rects = {};
|
||||
//var temprect = new Rectangle(cnv, 0, 0, 0, 0, "white", 0);
|
||||
//var pagescales = {};
|
||||
|
||||
function getMousePos(cnv, eve) {
|
||||
var rect = cnv.getBoundingClientRect();
|
||||
return {
|
||||
x: eve.clientX - rect.left,
|
||||
y: eve.clientY - rect.top,
|
||||
};
|
||||
}
|
||||
function mouseDown(eve) {
|
||||
//console.log(eve);
|
||||
if (eve.buttons != 1) {
|
||||
return;
|
||||
}
|
||||
if (mouseIsDown) {
|
||||
return;
|
||||
}
|
||||
mouseIsDown = true;
|
||||
var pos = getMousePos(cnv, eve);
|
||||
doc.startX = pos.x;
|
||||
doc.startY = pos.y;
|
||||
}
|
||||
function mouseUp(eve) {
|
||||
//console.log(eve);
|
||||
if (eve.buttons != 0) {
|
||||
return;
|
||||
}
|
||||
if (!mouseIsDown) {
|
||||
return;
|
||||
}
|
||||
mouseIsDown = false;
|
||||
doc.addRect(getMousePos(cnv, eve));
|
||||
doc.temprect = new Rectangle(doc.cnv, 0, 0, 0, 0, "black", 0);
|
||||
}
|
||||
|
||||
//var mousexy = 0;
|
||||
function mouSexy(eve) {
|
||||
if (mouseIsDown) {
|
||||
var pos = getMousePos(doc.cnv, eve);
|
||||
doc.temprect = new Rectangle(
|
||||
doc.cnv,
|
||||
doc.startX,
|
||||
doc.startY,
|
||||
pos.x,
|
||||
pos.y,
|
||||
"black",
|
||||
0.5,
|
||||
);
|
||||
doc.drawAll();
|
||||
}
|
||||
}
|
||||
function scrollPage(eve) {
|
||||
console.log(eve);
|
||||
if (eve.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
if (eve.deltaY > 0) {
|
||||
doc.pdf.NextPage();
|
||||
} else {
|
||||
doc.pdf.PrevPage();
|
||||
}
|
||||
}
|
||||
const initDraw = () => {
|
||||
var cnv = document.querySelector("#drw_cnv");
|
||||
cnv.addEventListener("mousedown", mouseDown, false);
|
||||
cnv.addEventListener("mouseup", mouseUp, false);
|
||||
cnv.addEventListener("mousemove", mouSexy, false);
|
||||
cnv.addEventListener("wheel", scrollPage, false);
|
||||
};
|
||||
function submitPdf(eve) {
|
||||
eve.preventDefault();
|
||||
var formdata = new FormData(eve.target);
|
||||
console.log(doc.paramRects);
|
||||
formdata.append("rects", JSON.stringify(doc.paramRects));
|
||||
formdata.append("pagescales", JSON.stringify(doc.pagescales.slice(1)));
|
||||
formdata.append("fileId", doc.fID);
|
||||
//formdata.append("filename", doc.filename);
|
||||
formdata.append("ftype", doc.filetype);
|
||||
if (!formdata.has("ocr")) {
|
||||
formdata.append("ocr", "False");
|
||||
}
|
||||
console.log(formdata);
|
||||
submitForm(formdata);
|
||||
}
|
||||
async function submitForm(formData) {
|
||||
try {
|
||||
const updateEventSource = new EventSource(
|
||||
"http://127.0.0.1:8000/get_censor_status/" + doc.fID,
|
||||
);
|
||||
modal.style.display = "flex";
|
||||
// console.log("http://127.0.0.1:8000/get_censor_status/" + doc.fID);
|
||||
updateEventSource.addEventListener("censorUpdate", function(eve) {
|
||||
console.log(eve.data);
|
||||
var data = JSON.parse(eve.data);
|
||||
upload_status.innerText =
|
||||
"Censoring Page " + data.page + "/" + data.pages;
|
||||
});
|
||||
const response = await fetch("http://127.0.0.1:8000/submit", {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
updateEventSource.close();
|
||||
modal.style.display = "none";
|
||||
//let responseJSON=await response.json();
|
||||
if (response.ok) {
|
||||
console.log("Submit OK");
|
||||
doc = new PDFDocument("./files/greeting", "greeting", "pdf");
|
||||
// console.log(response);
|
||||
// window.open(response);
|
||||
// console.log(URL.createObjectURL(response.body));
|
||||
// window.open(response);
|
||||
// window.open(response, (target = "_blank"));
|
||||
// var newWindow = window.open();
|
||||
// newWindow.document.write(response);
|
||||
// var blob = response.blob();
|
||||
const blobURL = URL.createObjectURL(await response.blob());
|
||||
window.open(blobURL, "_blank");
|
||||
} else {
|
||||
console.log("Submit failed");
|
||||
window.alert("Error: " + (await response.json())["detail"]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error" + error);
|
||||
}
|
||||
}
|
||||
function uploadPdf(eve) {
|
||||
eve.preventDefault();
|
||||
const fileupload = document.querySelector("#filepicker");
|
||||
const file = fileupload.files;
|
||||
if (!file) {
|
||||
alert("Please Choose a file");
|
||||
return;
|
||||
}
|
||||
const form = document.querySelector("#uploadform");
|
||||
const formData = new FormData(form);
|
||||
//formData.append("files", file);
|
||||
uploadFile(formData);
|
||||
}
|
||||
async function uploadFile(formData) {
|
||||
try {
|
||||
const response = await fetch("http://127.0.0.1:8000/uploadfile", {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
let responseJSON = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
console.log("upload OK " + responseJSON["filename"]);
|
||||
console.log(response);
|
||||
delete doc.pdf;
|
||||
//delete doc;
|
||||
document.getElementById("name").value = responseJSON.filename;
|
||||
doc = new PDFDocument(
|
||||
responseJSON.path,
|
||||
responseJSON.fid,
|
||||
responseJSON.filetype,
|
||||
);
|
||||
} else {
|
||||
console.log("upload failed");
|
||||
window.alert("Error: " + (await response.json())["detail"]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error: " + error);
|
||||
}
|
||||
}
|
||||
|
||||
function initUpload() {
|
||||
document.querySelector("#uploadform").addEventListener("submit", uploadPdf);
|
||||
document.querySelector("#submitform").addEventListener("submit", submitPdf);
|
||||
}
|
||||
function initListeners() {
|
||||
document.querySelector("#prev").addEventListener("click", function() {
|
||||
doc.pdf.PrevPage();
|
||||
});
|
||||
document.querySelector("#next").addEventListener("click", function() {
|
||||
doc.pdf.NextPage();
|
||||
});
|
||||
document.querySelector("#clr").addEventListener("click", function() {
|
||||
doc.clearCnv();
|
||||
});
|
||||
document.querySelector("#ca").addEventListener("click", function() {
|
||||
doc.clearAll();
|
||||
});
|
||||
}
|
||||
function initLoading() {
|
||||
modal = document.querySelector("#loading");
|
||||
// close_loading = document.querySelector(".close");
|
||||
upload_status = document.querySelector("#upload_status");
|
||||
// close_loading.addEventListener("click", function() {
|
||||
// modal.style.display = "none";
|
||||
// });
|
||||
}
|
||||
const startPdf = () => {
|
||||
// doc = new PDFDocument(
|
||||
// "./files/b78c869f-e0bb-11ef-9b58-84144d05d665",
|
||||
// "b78c869f-e0bb-11ef-9b58-84144d05d665",
|
||||
// "pdf",
|
||||
// );
|
||||
//pdf = new PDFView("./VO_Mathematik_3.pdf");
|
||||
doc = new PDFDocument("./files/greeting", "greeting", "pdf");
|
||||
initLoading();
|
||||
initDraw();
|
||||
initUpload();
|
||||
initListeners();
|
||||
};
|
||||
|
||||
window.addEventListener("load", startPdf);
|
||||
194
app/static/autocomplete.js
Normal file
194
app/static/autocomplete.js
Normal file
@@ -0,0 +1,194 @@
|
||||
var url = "http://127.0.0.1:8000/search/";
|
||||
var lid = null;
|
||||
var pid = null;
|
||||
var activeAutocompletion = null;
|
||||
/*Things I've stolen from https://www.w3schools.com/howto/howto_js_autocomplete.asp*/
|
||||
function autocomplete(inp, type) {
|
||||
/*the autocomplete function takes two arguments,
|
||||
the text field element and an array of possible autocompleted values:*/
|
||||
var currentFocus;
|
||||
/*execute a function when someone writes in the text field:*/
|
||||
inp.addEventListener("focus", (e) => {
|
||||
e.target.select();
|
||||
// this.select();
|
||||
updateAutocomplete();
|
||||
});
|
||||
inp.addEventListener("input", updateAutocomplete);
|
||||
async function updateAutocomplete() {
|
||||
activeAutocompletion = type;
|
||||
var a,
|
||||
b,
|
||||
i,
|
||||
apirq,
|
||||
iname,
|
||||
val = inp.value;
|
||||
/*close any already open lists of autocompleted values*/
|
||||
closeAllLists();
|
||||
if (!val && type === "lva" && pid === null) {
|
||||
return false;
|
||||
}
|
||||
if (type === "lva" && pid !== null) {
|
||||
apirq =
|
||||
url + type + "?searchterm=" + val + "&pid=" + pid + "&searchlim=10";
|
||||
} else if (type === "prof" && lid !== null) {
|
||||
apirq =
|
||||
url + type + "?searchterm=" + val + "&lid=" + lid + "&searchlim=10";
|
||||
} else if (type === "subcat" && lid !== null && pid !== null) {
|
||||
apirq =
|
||||
url +
|
||||
type +
|
||||
"?searchterm=" +
|
||||
val +
|
||||
"&lid=" +
|
||||
lid +
|
||||
"&pid=" +
|
||||
pid +
|
||||
"&cat=" +
|
||||
document.getElementById("submitform").elements["stype"].value +
|
||||
"&searchlim=10";
|
||||
} else {
|
||||
apirq = url + type + "?searchterm=" + val + "&searchlim=10";
|
||||
}
|
||||
const response = await fetch(apirq);
|
||||
currentFocus = -1;
|
||||
/*create a DIV element that will contain the items (values):*/
|
||||
a = document.createElement("DIV");
|
||||
a.setAttribute("id", this.id + "autocomplete-list");
|
||||
a.setAttribute("class", "autocomplete-items");
|
||||
/*append the DIV element as a child of the autocomplete container:*/
|
||||
inp.parentNode.appendChild(a);
|
||||
/*for each item in the array...*/
|
||||
//await response;
|
||||
if (response.ok) {
|
||||
arr = await response.json();
|
||||
} else {
|
||||
console.error("API call failed. Request:\n" + apirq);
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < arr.length; i++) {
|
||||
if (type === "lva") {
|
||||
iname =
|
||||
arr[i]["lvid"].slice(0, 3) +
|
||||
"." +
|
||||
arr[i]["lvid"].slice(3, 6) +
|
||||
" " +
|
||||
arr[i]["lvname"];
|
||||
} else {
|
||||
iname = arr[i]["name"];
|
||||
}
|
||||
console.log(iname);
|
||||
/*create a DIV element for each matching element:*/
|
||||
b = document.createElement("DIV");
|
||||
/*make the matching letters bold:*/
|
||||
//b.innerHTML = "<strong>" + iname.substr(0, val.length) + "</strong>";
|
||||
b.innerHTML = iname; //.substr(val.length);
|
||||
/*insert a input field that will hold the current array item's value:*/
|
||||
b.innerHTML += "<input type='hidden' value='" + i + "'>";
|
||||
/*execute a function when someone clicks on the item value (DIV element):*/
|
||||
b.addEventListener("click", function(e) {
|
||||
/*insert the value for the autocomplete text field:*/
|
||||
if (type === "lva") {
|
||||
const idx = this.getElementsByTagName("input")[0].value;
|
||||
inp.value =
|
||||
arr[idx]["lvid"].slice(0, 3) +
|
||||
"." +
|
||||
arr[idx]["lvid"].slice(3, 6) +
|
||||
" " +
|
||||
arr[idx]["lvname"];
|
||||
lid = arr[idx]["id"];
|
||||
} else if (type === "prof") {
|
||||
const idx = this.getElementsByTagName("input")[0].value;
|
||||
inp.value = arr[idx]["name"];
|
||||
pid = arr[idx]["id"];
|
||||
} else {
|
||||
inp.value = arr[this.getElementsByTagName("input")[0].value]["name"];
|
||||
}
|
||||
/*close the list of autocompleted values,
|
||||
(or any other open lists of autocompleted values:*/
|
||||
closeAllLists();
|
||||
});
|
||||
a.appendChild(b);
|
||||
}
|
||||
/*Add Listener to block the main click listener that destroys the autocompletion*/
|
||||
inp.addEventListener("click", function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
if (activeAutocompletion != type) {
|
||||
closeAllLists(e.target);
|
||||
}
|
||||
});
|
||||
}
|
||||
/*execute a function presses a key on the keyboard:*/
|
||||
inp.addEventListener("keydown", function(e) {
|
||||
var x = document.getElementById(this.id + "autocomplete-list");
|
||||
if (x) x = x.getElementsByTagName("div");
|
||||
if (e.keyCode == 40) {
|
||||
/*If the arrow DOWN key is pressed,
|
||||
increase the currentFocus variable:*/
|
||||
currentFocus++;
|
||||
/*and and make the current item more visible:*/
|
||||
addActive(x);
|
||||
} else if (e.keyCode == 38) {
|
||||
//up
|
||||
/*If the arrow UP key is pressed,
|
||||
decrease the currentFocus variable:*/
|
||||
currentFocus--;
|
||||
/*and and make the current item more visible:*/
|
||||
addActive(x);
|
||||
} else if (e.keyCode == 13) {
|
||||
/*If the ENTER key is pressed, prevent the form from being submitted,*/
|
||||
e.preventDefault();
|
||||
if (currentFocus > -1) {
|
||||
/*and simulate a click on the "active" item:*/
|
||||
if (x) x[currentFocus].click();
|
||||
}
|
||||
}
|
||||
});
|
||||
function addActive(x) {
|
||||
/*a function to classify an item as "active":*/
|
||||
if (!x) return false;
|
||||
/*start by removing the "active" class on all items:*/
|
||||
removeActive(x);
|
||||
if (currentFocus >= x.length) currentFocus = 0;
|
||||
if (currentFocus < 0) currentFocus = x.length - 1;
|
||||
/*add class "autocomplete-active":*/
|
||||
x[currentFocus].classList.add("autocomplete-active");
|
||||
}
|
||||
function removeActive(x) {
|
||||
/*a function to remove the "active" class from all autocomplete items:*/
|
||||
for (var i = 0; i < x.length; i++) {
|
||||
x[i].classList.remove("autocomplete-active");
|
||||
}
|
||||
}
|
||||
function closeAllLists(elmnt) {
|
||||
/*close all autocomplete lists in the document,
|
||||
except the one passed as an argument:*/
|
||||
var x = document.getElementsByClassName("autocomplete-items");
|
||||
for (var i = 0; i < x.length; i++) {
|
||||
if (elmnt != x[i] && elmnt != inp) {
|
||||
x[i].parentNode.removeChild(x[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*execute a function when someone clicks in the document:*/
|
||||
document.addEventListener("click", function(e) {
|
||||
closeAllLists(e.target);
|
||||
});
|
||||
}
|
||||
function enter_current_semeseter() {
|
||||
var semField = document.getElementById("sem");
|
||||
var today = new Date();
|
||||
var year = today.getFullYear();
|
||||
var month = today.getMonth();
|
||||
if (month < 9 && month > 1) {
|
||||
semField.value = String(year) + "S";
|
||||
} else {
|
||||
semField.value = String(year) + "W";
|
||||
}
|
||||
}
|
||||
function init() {
|
||||
autocomplete(document.getElementById("lva"), "lva");
|
||||
autocomplete(document.getElementById("prof"), "prof");
|
||||
autocomplete(document.getElementById("subcat"), "subcat");
|
||||
enter_current_semeseter();
|
||||
}
|
||||
window.addEventListener("load", init);
|
||||
42
app/static/dynhide.js
Normal file
42
app/static/dynhide.js
Normal file
@@ -0,0 +1,42 @@
|
||||
var radiobuttons;
|
||||
var datediv;
|
||||
var subcatdiv;
|
||||
var rdbarr;
|
||||
var subcatcategories = [1, 2, 3];
|
||||
var datecategorires = [0, 1];
|
||||
function changevis() {
|
||||
for (let i = 0; i < rdbarr.length; i++) {
|
||||
if (rdbarr[i].checked) {
|
||||
if (subcatcategories.includes(i)) {
|
||||
subcatdiv.style.display = "block";
|
||||
} else {
|
||||
subcatdiv.style.display = "none";
|
||||
}
|
||||
if (datecategorires.includes(i)) {
|
||||
datediv.style.display = "block";
|
||||
} else {
|
||||
datediv.style.display = "none";
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
function starthide() {
|
||||
radiobuttons = document.getElementsByName("stype");
|
||||
datediv = document.getElementById("datediv");
|
||||
subcatdiv = document.getElementById("subcatdiv");
|
||||
rdbarr = [
|
||||
document.getElementById("pruefung"),
|
||||
document.getElementById("klausur"),
|
||||
document.getElementById("uebung"),
|
||||
document.getElementById("labor"),
|
||||
document.getElementById("unterlagen"),
|
||||
document.getElementById("zusammenfassungen"),
|
||||
document.getElementById("multimedia"),
|
||||
];
|
||||
changevis();
|
||||
radiobuttons.forEach((rdb) => {
|
||||
rdb.addEventListener("change", changevis);
|
||||
});
|
||||
}
|
||||
window.addEventListener("load", starthide);
|
||||
10
app/static/filedrop.js
Normal file
10
app/static/filedrop.js
Normal file
@@ -0,0 +1,10 @@
|
||||
var fileinput;
|
||||
function dropHandler(eve) {
|
||||
eve.preventDefault();
|
||||
fileinput.files = eve.dataTransfer.files;
|
||||
}
|
||||
function init() {
|
||||
fileinput = document.getElementById("filepicker");
|
||||
document.getElementById("filepicker").addEventListener("drop", dropHandler);
|
||||
}
|
||||
window.addEventListener("load", init);
|
||||
321
app/static/style.css
Normal file
321
app/static/style.css
Normal file
@@ -0,0 +1,321 @@
|
||||
html,
|
||||
body {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
background-color: #2f3957;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.right {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
width: 75vw;
|
||||
float: right;
|
||||
/* background-color: navy; */
|
||||
}
|
||||
|
||||
.left {
|
||||
/* background-color: blueviolet; */
|
||||
height: 100%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
span {
|
||||
color: lightgray;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.fullsize {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #0872a9;
|
||||
/* border-radius: 20px; */
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
border-bottom-right-radius: 0px;
|
||||
border-bottom-left-radius: 0px;
|
||||
}
|
||||
|
||||
.main {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#cnvdiv {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
/*display: flex;*/
|
||||
/*text-align: center;*/
|
||||
/*justify-content: center;*/
|
||||
}
|
||||
|
||||
.stack {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
/*text-align: center;*/
|
||||
/*float: right;*/
|
||||
/*margin-right: 0;*/
|
||||
/*margin-left: auto;*/
|
||||
/*display: block;*/
|
||||
}
|
||||
|
||||
.stack>canvas {
|
||||
position: absolute;
|
||||
/*display: block;*/
|
||||
/*display: inline;*/
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
#submitdiv {
|
||||
/*position: relative;*/
|
||||
width: 500px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
label {
|
||||
/* color: white; */
|
||||
background-color: grey;
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
/* margin: 10px; */
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/*Things I've stolen from https://www.w3schools.com/howto/howto_js_autocomplete.asp*/
|
||||
.autocomplete {
|
||||
/*the container must be positioned relative:*/
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
/* width: 400px; */
|
||||
width: 100%;
|
||||
padding: none;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#name {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
input {
|
||||
border: 1px solid #818181;
|
||||
background-color: #a1a1a1;
|
||||
padding: 10px;
|
||||
/* height: 50px; */
|
||||
font-size: 12pt;
|
||||
border-radius: 20px;
|
||||
margin-top: 10px;
|
||||
/* margin-bottom: 10px; */
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
background-color: #b1b1b1;
|
||||
/* width: 100%; */
|
||||
width: 478px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
/* input[type="text"]:focus { */
|
||||
/* border-bottom-right-radius: 0px; */
|
||||
/* border-bottom-left-radius: 0px; */
|
||||
/* outline: none; */
|
||||
/* } */
|
||||
|
||||
div>input[type="text"]:focus {
|
||||
border-bottom-right-radius: 0px;
|
||||
border-bottom-left-radius: 0px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button[type="submit"] {
|
||||
background-color: #0872a9;
|
||||
/* color: #fff; */
|
||||
border-radius: 20px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.autocomplete-items {
|
||||
position: absolute;
|
||||
/* border: 1px solid #d4d4d4; */
|
||||
border: 1px solid #818181;
|
||||
background-color: #b1b1b1;
|
||||
/* background-color: #b1b1b1; */
|
||||
border-bottom: none;
|
||||
border-top: none;
|
||||
z-index: 99;
|
||||
/*position the autocomplete items to be the same width as the container:*/
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-bottom-left-radius: 20px;
|
||||
border-bottom-right-radius: 20px;
|
||||
/* padding: 20px; */
|
||||
/* padding-top: 10px; */
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.autocomplete-items div {
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
/* border-radius: 20px; */
|
||||
background-color: #b1b1b1;
|
||||
border-bottom: 1px solid #d4d4d4;
|
||||
}
|
||||
|
||||
.autocomplete-items div:hover {
|
||||
/*when hovering an item:*/
|
||||
background-color: #0872a9;
|
||||
}
|
||||
|
||||
.autocomplete-active {
|
||||
/*when navigating through the items using the arrow keys:*/
|
||||
background-color: #0872a9 !important;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* filedrop */
|
||||
input[type="file"] {
|
||||
/* flex: 1; */
|
||||
display: flex;
|
||||
background-color: #b1b1b1;
|
||||
border-radius: 20px;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
margin-right: 10px;
|
||||
margin-top: 10px;
|
||||
margin-left: 10px;
|
||||
/* margin-bottom: auto; */
|
||||
}
|
||||
|
||||
input[type="file"]::file-selector-button {
|
||||
background-color: #d1d1d1;
|
||||
border-radius: 20px;
|
||||
border-color: #a1a1a1;
|
||||
}
|
||||
|
||||
#fileupload {
|
||||
/* display: inline-flex; */
|
||||
width: 500px;
|
||||
border-radius: 20px;
|
||||
background-color: #4f5977;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.fileupload {
|
||||
margin-left: auto;
|
||||
margin-right: 10px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
width: 25%;
|
||||
/* align-self: right; */
|
||||
/* float: right; */
|
||||
}
|
||||
|
||||
#uploadform {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.filetop {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
/* background-color: purple; */
|
||||
}
|
||||
|
||||
/* The Modal (background) */
|
||||
.modal {
|
||||
display: none;
|
||||
/* Hidden by default */
|
||||
position: fixed;
|
||||
/* Stay in place */
|
||||
z-index: 1;
|
||||
/* Sit on top */
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
/* Full width */
|
||||
height: 100%;
|
||||
/* Full height */
|
||||
overflow: auto;
|
||||
/* Enable scroll if needed */
|
||||
background-color: #4f5977;
|
||||
/* Fallback color */
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
/* Black w/ opacity */
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Modal Content/Box */
|
||||
.loading-content {
|
||||
background-color: #4f5977;
|
||||
margin: auto;
|
||||
/* 15% from the top and centered */
|
||||
padding: 20px;
|
||||
/* border: 1px solid #888; */
|
||||
/* width: 80%; */
|
||||
border-radius: 15px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* Could be more or less, depending on screen size */
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* The Close Button */
|
||||
.close {
|
||||
color: #aaa;
|
||||
float: right;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.close:hover,
|
||||
.close:focus {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.upload_status_text {
|
||||
color: #ffffff;
|
||||
font-size: 16pt;
|
||||
}
|
||||
|
||||
.loader {
|
||||
margin: auto;
|
||||
border: 16px solid #f3f3f3;
|
||||
/* Light grey */
|
||||
border-top: 16px solid #3498db;
|
||||
/* Blue */
|
||||
border-radius: 50%;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user