- Improved documentation
- Added images - Fixed mistakes - Added build script for zip file
@ -1,15 +1,14 @@
|
||||
\chapter{Einleitung und Installation}\label{ch:einleitung}
|
||||
Immer mehr Programme werden heutzutage nicht mehr als native App sondern als Webapp, die im Browser aufgerufen wird, genutzt.
|
||||
Ein Beispiel dafür sind die Office Anwendungen von Microsoft, die als native Programme und als Web-Version verfügbar sind.
|
||||
Immer mehr Programme werden heutzutage nicht mehr als native App, sondern als Webapp, die im Browser aufgerufen wird, genutzt.
|
||||
Ein Beispiel dafür sind die Office-Anwendungen von Microsoft, die als native Programme und als Web-Version verfügbar sind.
|
||||
Die Web-Version hat dabei den Vorteil, dass sie auch unter Linux oder anderen, eigentlich nicht unterstützten Betriebssystemen, funktioniert.
|
||||
Dadurch können mehr Personen die Anwendung nutzen und oftmals ist auch die Entwicklung einfacher, weil nur für ein System (Browser) und nicht für mehrere Systeme (Windows, Linux, MacOS, \ldots) entwickelt werden muss.
|
||||
|
||||
\section{Installation}
|
||||
\section{Installation}\label{sec:installation}
|
||||
Der Webservice kann mittels Docker gestartet werden.
|
||||
\begin{lstlisting}
|
||||
\begin{lstlisting}[label={lst:lstlisting}]
|
||||
docker run --rm -v "<path>:/app" -v "<path>/upload.ini:/usr/local/etc/php/conf.d/upload.ini" -w /app -p 8080:80 php:7.4-cli php -S 0.0.0.0:80 router.php
|
||||
\end{lstlisting}
|
||||
|
||||
Die eigentliche App wird geöffnet, indem die Datei \glqq index.html\grqq~im Ordner \glqq Frontend\grqq~in einem kompatiblen Browser geöffnet wird.
|
||||
|
||||
Damit alles einwandfrei funktionieren kann, muss der Webservice entweder auf dem gleichen Gerät wie die eigentliche App laufen oder in der Datei \glqq Frontend/static/js/index.js\grqq~ muss die erste Zeile angepasst werden.
|
||||
|
@ -1,33 +1,33 @@
|
||||
\chapter{Allgemeine Informationen}\label{ch:allgemeine_informationen}
|
||||
Bei diesem Projekt wurden ausschließlich die Programmier- beziehungsweise Markupsprachen JavaScript, \gls{css} und \gls{html} verwendet.
|
||||
Bei diesem Projekt wurden ausschließlich die Programmier- beziehungsweise Markup-Sprachen JavaScript, \gls{css} und \gls{html} verwendet.
|
||||
|
||||
Es handelt sich um eine Single-Page-App.
|
||||
Das heißt, die komplette Funktionalität wurde in einer einzelnen \acrshort{html}-Datei und mehreren JavaScript beziehungsweise CSS Dateien umgesetzt.
|
||||
|
||||
Alle Funktionen wurden in folgenden Browsern getestet:
|
||||
|
||||
\section{Desktop}
|
||||
\section{Desktop}\label{sec:desktop}
|
||||
\begin{center}
|
||||
\begin{tabular}{ c c c c c }
|
||||
\bfseries{Browser} & \bfseries{Version} & \bfseries{funktioniert?} & \bfseries{Probleme} \\
|
||||
\begin{tabular}{ l l l }
|
||||
\bfseries{OS} & \bfseries{Browser} & \bfseries{funktioniert?} \\
|
||||
\hline
|
||||
Mozilla Firefox & 90.0b12 & \textcolor{green}{\cmark} & \\
|
||||
Google Chrome & 91.0.4472.114 & \textcolor{red}{\xmark} & Audio + Video abspielen \\
|
||||
Chromium & 91.0.4472.114 & \textcolor{red}{\xmark} & Audio + Video abspielen \\
|
||||
Opera & 77.0.4054.203 & \textcolor{red}{\xmark} & Audio + Video abspielen \\
|
||||
Microsoft Edge & & & \\
|
||||
Internet Explorer & & &
|
||||
Ubuntu 20.04 & Mozilla Firefox 90.0b12 & \textcolor{green}{\cmark} \\
|
||||
Ubuntu 20.04 & Google Chrome 91.0.4472.114 & \textcolor{green}{\cmark} \\
|
||||
Ubuntu 20.04 & Chromium 91.0.4472.114 & \textcolor{green}{\cmark} \\
|
||||
Ubuntu 20.04 & Opera 77.0.4054.277 & \textcolor{red}{\xmark} Videos \\
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
|
||||
\section{Mobile}
|
||||
\section{Mobile}\label{sec:mobile}
|
||||
\begin{center}
|
||||
\begin{tabular}{ c c c }
|
||||
Browser & Version & funktioniert? \\
|
||||
Mozilla Firefox & & \\
|
||||
Google Chrome & & \\
|
||||
Safari & & \\
|
||||
Opera & &
|
||||
\begin{tabular}{ l l l }
|
||||
\bfseries{OS} & \bfseries{Browser} & \bfseries{funktioniert?} \\
|
||||
\hline
|
||||
Android 11 & Mozilla Firefox 90.1.2 & \textcolor{green}{\cmark} \\
|
||||
Android 11 & Google Chrome 92.0.4515.115 & \textcolor{green}{\cmark} \\
|
||||
Android 11 & Opera 64.2.3282.60128 & \textcolor{green}{\cmark} \\
|
||||
iOS 14.7.1 & Mozilla Firefox 35.0 & \textcolor{red}{\xmark} Scrollen \& Icons \\
|
||||
iOS 14.7.1 & Safari 14 & \textcolor{red}{\xmark} Scrollen \& Icons
|
||||
\end{tabular}
|
||||
\end{center}
|
@ -1,87 +1,167 @@
|
||||
\chapter{Anforderungen}\label{ch:anforderungen}
|
||||
|
||||
\section{Laufzeitumgebung}
|
||||
\subsection{Sprachen}
|
||||
\section{Laufzeitumgebung}\label{sec:laufzeitumgebung}
|
||||
|
||||
\subsection{Sprachen}\label{subsec:sprachen}
|
||||
Wie bereits erwähnt wurden bei diesem Projekt nur die Sprachen \gls{html}, \gls{css} und JavaScript verwendet
|
||||
|
||||
\subsection{Keine Bibliotheken}
|
||||
\subsection{Keine Bibliotheken}\label{subsec:keine-bibliotheken}
|
||||
Auf JavaScript Bibliotheken und Frameworks wie \glqq jQuery\grqq, \glqq React\grqq~oder \glqq Angular\grqq~wurde verzichtet.
|
||||
Stattdessen wurden native JavaScript-Funktionen verwendet.
|
||||
|
||||
Auch das \gls{html}- bezieziehungsweise \gls{css}-Framework \glqq Bootstrap\grqq~wurde nicht verwendet.
|
||||
Auch das \gls{html}- beziehungsweise \gls{css}-Framework \glqq Bootstrap\grqq~wurde nicht verwendet.
|
||||
|
||||
|
||||
\section{Sicherheit}
|
||||
\subsection{Authentifizierung}
|
||||
\section{Sicherheit}\label{sec:sicherheit}
|
||||
|
||||
\subsection{Authentifizierung}\label{subsec:authentifizierung}
|
||||
Damit nicht jede Person zugang zu den Daten hat, muss der Benutzer sich authentifizieren.
|
||||
Dafür wird beim starten der Webapp ein Login-Fenster angezeigt.
|
||||
Dafür wird beim Starten der Webapp ein Login-Fenster, wie in (Abbildung~\ref{fig:login}, angezeigt.
|
||||
Sollte der Login am Server erfolgreich sein, wird der generierte Token in Session Storage gespeichert.
|
||||
Das hat zur Folge, das der Login spätestens mit dem beenden der Browser-Session ungültig gemacht wird.
|
||||
Das hat zur Folge, dass der Login spätestens mit dem Beenden der Browser-Session ungültig gemacht wird.
|
||||
|
||||
\subsection{Logout}
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=0.4\textwidth]{images/login}
|
||||
\caption{Login-Fenster}
|
||||
\label{fig:login}
|
||||
\end{figure}
|
||||
|
||||
\subsection{Logout}\label{subsec:logout}
|
||||
Der Logout wird zum einen vom Server automatisch durchgeführt, wenn seit 600 Sekunden keine Aktivität mehr erkannt wurde.
|
||||
Des Weiteren wird im Browser beim Login und bei jeder Aktivität ein Timeout gesetzt, sodass der Token in Session Storage automatisch nach diesen 600 Sekunden gelöscht wird.
|
||||
Ein Logout-Button befindet sich oben rechts im Header (Abbildung~\ref{fig:logout}).
|
||||
|
||||
\section{Darstellung}
|
||||
\subsection{Anpassung an Browserfenstern}
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=0.2\textwidth]{images/logout}
|
||||
\caption{Logout-Button}
|
||||
\label{fig:logout}
|
||||
\end{figure}
|
||||
|
||||
\section{Darstellung}\label{sec:darstellung}
|
||||
|
||||
\subsection{Anpassung an Browserfenstern}\label{subsec:anpassung-an-browserfenstern}
|
||||
Da es unterschiedliche Bildschirme gibt, ist der Inhalt der App nicht überall gut lesbar.
|
||||
Deshalb wurde mittels \gls{css} \glqq Media queries\grqq~dafür gesorgt, dass bei schmalen Geräten die Baum-Ansicht unter der Verzeichnis-Ansicht angezeigt wird.
|
||||
Dadurch wird sichergestellt, dass auf Smartphones, die sowieso schon wenig Platz in der Breite haben, nicht noch mehr Platz \glqq verschwendet\grqq~wird.
|
||||
|
||||
\subsection{Usability}
|
||||
\subsection{Usability}\label{subsec:usability}
|
||||
Der Dateimanager ist von der Grundstruktur ähnlich aufgebaut wie der \glqq Windows Explorer\grqq~unter Windows oder \glqq Nautilus\grqq~unter Linux.
|
||||
Nutzer, die diese Dateimanager schon genutzt haben, finden sich in der Webapp schnell zurecht.
|
||||
|
||||
\subsection{Fehlererkennung}
|
||||
\subsection{Fehlererkennung}\label{subsec:fehlererkennung}
|
||||
Auch wenn es eigentlich nicht vorkommen sollte, kann es immer wieder zu Fehlern kommen, weil die angefragte Datei zum Beispiel gelöscht wurde.
|
||||
Die Fehlermeldungen des Servers werden von der App abgefangen und angezeigt.
|
||||
Die Fehlermeldungen des Servers werden von der App abgefangen und angezeigt (Siehe Abbildung~\ref{fig:error}).
|
||||
Eine Erfolgsmeldung (Abbildung~\ref{fig:success}) wird wie die Fehlermeldung angezeigt, aber mit grünem statt rotem Hintergrund.
|
||||
|
||||
\subsection{Verzeichnisse \& Dateitypen}
|
||||
Verzeichnisse und Dateitypen werden in der Verzeichnisansicht durch unterschiedliche Icons angezeigt.
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=\textwidth]{images/error}
|
||||
\caption{Fehlermeldung}
|
||||
\label{fig:error}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=\textwidth]{images/succes}
|
||||
\caption{Erfolgsmeldung}
|
||||
\label{fig:success}
|
||||
\end{figure}
|
||||
|
||||
\subsection{Verzeichnisse \& Dateitypen}\label{subsec:verzeichnisse-&-dateitypen}
|
||||
Verzeichnisse und Dateitypen werden in der Verzeichnis-Ansicht durch unterschiedliche Icons angezeigt (Abbildung~\ref{fig:files}).
|
||||
So wird sichergestellt, dass der Benutzer schnell herausfinden kann, um was es sich handelt.
|
||||
|
||||
\section{Navigation}
|
||||
Die Navigation ist entweder über den Verzeichnis-Baum links beziehungsweise unten oder über die Datei-Ansicht rechts oder oben möglich.
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=\textwidth]{images/files}
|
||||
\caption{Dateiansicht mit unterschiedlichen Icons}
|
||||
\label{fig:files}
|
||||
\end{figure}
|
||||
|
||||
\section{Navigation}\label{sec:navigation}
|
||||
Die Navigation ist entweder über den Verzeichnis-Baum links (Abbildung~\ref{fig:tree}) beziehungsweise unten oder über die Datei-Ansicht rechts oder oben möglich.
|
||||
Um sich ein Verzeichnis nach oben zu bewegen, kann \glqq ..\grqq~verwendet werden.
|
||||
Um ein oder mehrere Verzeichnisse nach oben zu gehen, kann der Pfad oberhalb der Dateien verwendet werden.
|
||||
Direkt über der Datei-Ansicht wird das aktuelle Verzeichnis angezeigt (Siehe Abbildung~\ref{fig:path}).
|
||||
|
||||
\subsection{Verzeichnis öffnen}
|
||||
Um ein Verzeichnis zu öffnen, kann das entsprechende Verzeichnis in der Verzeichnisansicht angeklickt werden.
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=0.4\textwidth]{images/tree}
|
||||
\caption{Verzeichnis-Baum}
|
||||
\label{fig:tree}
|
||||
\end{figure}
|
||||
|
||||
\section{Datei-Handling}
|
||||
\subsubsection{MP4-Video-Datei abspielen}
|
||||
Der Dateimanager kann mp4-Video-Dateien abspielen, indem diese in der Verzeichnisansicht angeklickt werden.
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=\textwidth]{images/path}
|
||||
\caption{Anzeige des aktuellen Verzeichnisses}
|
||||
\label{fig:path}
|
||||
\end{figure}
|
||||
|
||||
\subsection{Verzeichnis öffnen}\label{subsec:verzeichnis-oeffnen}
|
||||
Um ein Verzeichnis zu öffnen, kann das entsprechende Verzeichnis in der Verzeichnis-Ansicht angeklickt werden.
|
||||
|
||||
\section{Datei-Handling}\label{sec:datei-handling}
|
||||
|
||||
\subsection{MP4-Video-Datei abspielen}\label{subsec:mp4-video-datei-abspielen}
|
||||
Der Dateimanager kann mp4-Video-Dateien abspielen, indem diese in der Verzeichnis-Ansicht angeklickt werden.
|
||||
|
||||
\subsubsection{Audio-Datei abspielen}
|
||||
Der Dateimanager kann Audio-Dateien abspielen, indem diese in der Verzeichnisansicht angeklickt werden.
|
||||
Der Dateimanager kann Audio-Dateien abspielen, indem diese in der Verzeichnis-Ansicht angeklickt werden.
|
||||
|
||||
\subsubsection{Bild-Datei ansehen}
|
||||
Der Dateimanager kann Bild-Dateien anzeigen, indem diese in der Verzeichnisansicht angeklickt werden.
|
||||
Der Dateimanager kann Bild-Dateien anzeigen, indem diese in der Verzeichnis-Ansicht angeklickt werden.
|
||||
|
||||
\subsubsection{Text-Datei bearbeiten}
|
||||
Der Dateimanager kann Text-Dateien bearbeiten, indem diese in der Verzeichnisansicht angeklickt werden.
|
||||
Der Dateimanager kann Text-Dateien bearbeiten, indem diese in der Verzeichnis-Ansicht angeklickt werden.
|
||||
Im neuen Fenster kann der Inhalt der Datei bearbeitet werden und wird mit einem Klick auf \glqq Save\grqq~gespeichert.
|
||||
|
||||
\subsubsection{Datei herunterladen}
|
||||
Eine Datei kann heruntergeladen werden, indem in der Verzeichnisansicht das Kontextmenü mittels Rechtsklick geöffnet wird.
|
||||
Eine Datei kann heruntergeladen werden, indem in der Verzeichnis-Ansicht das Kontextmenü (Abbildung~\ref{fig:context}) mittels Rechtsklick geöffnet wird.
|
||||
Dann muss nur noch \glqq Herunterladen\grqq ausgewählt werden.
|
||||
|
||||
\subsubsection{Datei löschen}
|
||||
Eine Datei kann gelöscht werden, indem in der Verzeichnisansicht das Kontextmenü mittels Rechtsklick geöffnet wird.
|
||||
Eine Datei kann gelöscht werden, indem in der Verzeichnis-Ansicht das Kontextmenü (Abbildung~\ref{fig:context}) mittels Rechtsklick geöffnet wird.
|
||||
Dann muss nur noch \glqq Löschen\grqq ausgewählt werden.
|
||||
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=0.6\textwidth]{images/context}
|
||||
\caption{Kontextmenü}
|
||||
\label{fig:context}
|
||||
\end{figure}
|
||||
|
||||
\subsubsection{Text-Datei erstellen}
|
||||
Um eine Text-Datei zu erstellen muss unten rechts über das \glqq +\grqq-Icon gehovert werden.
|
||||
Um eine Text-Datei zu erstellen, muss unten rechts über das \glqq +\grqq-Icon gehovert werden (Abbildung~\ref{fig:hover}).
|
||||
Bei den neu angezeigten Icons das zweite von oben anklicken, um die Datei zu erstellen.
|
||||
Im Header des neuen Fensters kann der Dateiname festgelegt werden.
|
||||
Der Rest ist gleich, wie beim bearbeiten von Text-Dateien.
|
||||
Der Rest ist gleich wie beim Bearbeiten von Text-Dateien (Siehe Abbildung~\ref{fig:text}).
|
||||
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=\textwidth]{images/text}
|
||||
\caption{Textdatei erstellen}
|
||||
\label{fig:text}
|
||||
\end{figure}
|
||||
|
||||
\subsubsection{Datei hochladen}
|
||||
Um eine Datei hochzuladen muss unten rechts über das \glqq +\grqq-Icon gehovert werden.
|
||||
Um eine Datei hochzuladen muss unten rechts über das \glqq +\grqq-Icon gehovert werden (Abbildung~\ref{fig:hover}).
|
||||
Bei den neu angezeigten Icons das dritte von oben anklicken, um die Datei hochzuladen.
|
||||
|
||||
\section{Verzeichnis-Handling}
|
||||
\subsection{Verzeichnis löschen}
|
||||
Ein Verzeichnis kann gelöscht werden, indem in der Verzeichnisansicht das Kontextmenü mittels Rechtsklick geöffnet wird.
|
||||
\section{Verzeichnis-Handling}\label{sec:verzeichnis-handling}
|
||||
|
||||
\subsection{Verzeichnis erstellen}
|
||||
Um ein Verzeichnis zu erstellen, muss unten rechts über das \glqq +\grqq-Icon gehovert werden.
|
||||
\subsection{Verzeichnis löschen}\label{subsec:verzeichnis-loeschen}
|
||||
Ein Verzeichnis kann gelöscht werden, indem in der Verzeichnis-Ansicht das Kontextmenü mittels Rechtsklick geöffnet wird.
|
||||
|
||||
\subsection{Verzeichnis erstellen}\label{subsec:verzeichnis-erstellen}
|
||||
Um ein Verzeichnis zu erstellen, muss unten rechts über das \glqq +\grqq-Icon gehovert werden (Abbildung~\ref{fig:hover}).
|
||||
Bei den neu angezeigten Icons das oberste anklicken, um das Verzeichnis zu erstellen.
|
||||
|
||||
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=0.2\textwidth]{images/hover}
|
||||
\caption{Menü}
|
||||
\label{fig:hover}
|
||||
\end{figure}
|
BIN
Documentation/images/context.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
Documentation/images/error.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
Documentation/images/files.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
Documentation/images/hover.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
Documentation/images/login.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
Documentation/images/logout.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Documentation/images/path.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
Documentation/images/succes.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
Documentation/images/text.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
Documentation/images/tree.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
Documentation/images/upload.png
Normal file
After Width: | Height: | Size: 9.4 KiB |
@ -5,21 +5,22 @@
|
||||
\include{customization/text-variables}
|
||||
|
||||
% Packages
|
||||
\usepackage[ngerman]{babel} % for German language
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage[ngerman]{babel}
|
||||
\usepackage[autostyle=true,german=quotes]{csquotes}
|
||||
\usepackage{refcheck}
|
||||
\usepackage{float} % for placing images where I want them
|
||||
\usepackage{fontspec} % for using own font
|
||||
\usepackage{float}
|
||||
\usepackage{fontspec} % for using own font
|
||||
\usepackage{multicol}
|
||||
\usepackage[includefoot,left=\pageMarginLeft,right=\pageMarginRight,top=\pageMarginTop,bottom=\pageMarginBottom,headsep=\baselineskip,footskip=\dimexpr2\baselineskip+3mm\relax]{geometry}
|
||||
\usepackage{scrlayer-scrpage} % for header / footer
|
||||
\usepackage{graphicx} % for including images
|
||||
\usepackage[includeheadfoot,left=40mm,right=25mm,top=25mm,bottom=25mm,footskip=10mm]{geometry}
|
||||
\usepackage[singlespacing=true]{scrlayer-scrpage} % for header / footer
|
||||
\usepackage{graphicx}
|
||||
\usepackage[hidelinks,pdftitle={\paperName},pdfauthor={\author},pdfsubject={\title},pdfpagemode=UseOutlines,pdfdisplaydoctitle=true,pdflang=german]{hyperref}
|
||||
\usepackage{setspace} % for line spacing
|
||||
\usepackage{xcolor} % for defining colors
|
||||
\usepackage[acronym,toc]{glossaries} % for acronyms
|
||||
\usepackage{listings} % for listings
|
||||
\usepackage{parskip} % for no indent in each paragraph
|
||||
\usepackage{setspace}
|
||||
\usepackage{xcolor}
|
||||
\usepackage[acronym,toc]{glossaries}
|
||||
\usepackage{listings}
|
||||
\usepackage{anyfontsize}
|
||||
|
||||
\usepackage[backend=biber,bibwarn=true,bibencoding=utf8,sortlocale=de_DE,style=numeric-comp]{biblatex}
|
||||
\usepackage{amssymb}
|
||||
|
BIN
Filemanager_20C_9829423.zip
Normal file
@ -1,3 +1,4 @@
|
||||
// Error view
|
||||
function create_error_view(text) {
|
||||
let id = get_random_id();
|
||||
let error = document.createElement('div');
|
||||
@ -17,6 +18,8 @@ function create_error_view(text) {
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
|
||||
// Success view
|
||||
function create_success_view(text) {
|
||||
let id = get_random_id();
|
||||
let error = document.createElement('div');
|
||||
|
@ -18,6 +18,7 @@ function download_file(path, mimetype) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function remove_file(filename) {
|
||||
httpDeleteAsync(base_url + filename, null, function (response, code) {
|
||||
if (code === 200) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
let tree = {};
|
||||
|
||||
// Recursively create data
|
||||
function create_tree_data(curr_dir) {
|
||||
let url = base_url + curr_dir;
|
||||
|
||||
@ -27,6 +28,8 @@ function create_tree_data(curr_dir) {
|
||||
xmlHttp.send(null);
|
||||
}
|
||||
|
||||
|
||||
// Show tree
|
||||
function create_tree_view() {
|
||||
let html_tree = document.createElement('div');
|
||||
html_tree.innerHTML = `<ul id="tree_ul"></ul>`;
|
||||
@ -48,11 +51,14 @@ function create_tree_view() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Change directory
|
||||
function tree_onclick(url) {
|
||||
window.history.pushState('index', 'Filemanager', 'index.html?path=' + url);
|
||||
path_changed();
|
||||
}
|
||||
|
||||
|
||||
function create_list_view(dataRoot, elementRoot, url) {
|
||||
if (dataRoot) {
|
||||
const list = document.createElement('ul');
|
||||
@ -69,6 +75,7 @@ function create_list_view(dataRoot, elementRoot, url) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function addPath(pathcomponents, arr) {
|
||||
let component = pathcomponents.shift()
|
||||
let comp = arr.find(item => item.text === component)
|
||||
|
@ -1,4 +1,4 @@
|
||||
let base_url = 'http://localhost:8080'; //'http://192.168.178.98:8080';
|
||||
let base_url = 'http://192.168.178.98:8080'; //'http://localhost:8080';
|
||||
let file_path = [];
|
||||
let timeout = null;
|
||||
|
||||
@ -15,15 +15,21 @@ window.addEventListener('load', function () {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// For / back buttons
|
||||
window.addEventListener('popstate', function () {
|
||||
path_changed();
|
||||
});
|
||||
|
||||
|
||||
// Function that is used to load content
|
||||
function path_changed() {
|
||||
let curr_dir = get_curr_path();
|
||||
httpGetAsync(base_url + curr_dir, null, show_files);
|
||||
}
|
||||
|
||||
|
||||
// Login
|
||||
function login() {
|
||||
let username = document.getElementById("username").value;
|
||||
let password = document.getElementById("password").value;
|
||||
@ -46,6 +52,8 @@ function login() {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Show content
|
||||
function show_files(response, code) {
|
||||
if (code === 200) {
|
||||
// OK
|
||||
@ -60,6 +68,8 @@ function show_files(response, code) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Go one dir up
|
||||
function one_dir_back() {
|
||||
let curr_dir = get_curr_path();
|
||||
|
||||
@ -74,17 +84,21 @@ function one_dir_back() {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
// Save textfile
|
||||
function save_file(filename, content) {
|
||||
remove_modal();
|
||||
httpPostAsync(base_url + filename, 'content=' + btoa(content), function (response, code) {
|
||||
if (code === 200) {
|
||||
create_success_view("Saved file successfully");
|
||||
path_changed();
|
||||
} else {
|
||||
try_to_parse_error(response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function add_folder() {
|
||||
let content = `<input id="input" placeholder="Name" style="width: 100%; margin: 10px 0 10px 0;">`;
|
||||
let footer = `<button onclick="api_create_folder(document.getElementById('input').value.trim())" type="button" value="Save">Save</button>
|
||||
@ -92,6 +106,7 @@ function add_folder() {
|
||||
create_modal('Create Folder', content, footer);
|
||||
}
|
||||
|
||||
|
||||
function add_file() {
|
||||
let content = `<div style="width: 100%; height: max-content;">
|
||||
<input id="input" placeholder="Name" style="width: calc(100% - 8px); margin: 10px 0 10px 0;">
|
||||
@ -102,6 +117,7 @@ function add_file() {
|
||||
create_modal('Create File', content, footer);
|
||||
}
|
||||
|
||||
|
||||
function upload_file() {
|
||||
let content = `<form enctype="multipart/form-data"><input type="file" id="newFile" name="newFile" style="width: 100%; margin: 10px 0 10px 0;"></form><progress style="width: 100%;" min=0 max=100 value="0" id="upload_progress"/>`;
|
||||
let footer = `<button onclick="api_upload_file();" type="button" value="Save">Save</button>
|
||||
@ -109,6 +125,7 @@ function upload_file() {
|
||||
create_modal('Upload File', content, footer);
|
||||
}
|
||||
|
||||
|
||||
function api_create_folder(name) {
|
||||
httpPostAsync(base_url + get_curr_path() + '/' + name, 'type=dir', function (response, code) {
|
||||
remove_modal();
|
||||
@ -122,6 +139,7 @@ function api_create_folder(name) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function api_upload_file() {
|
||||
let formData = new FormData(document.getElementById('modal_content').children[0]);
|
||||
let filename = document.getElementById('modal_content').children[0].children[0].files[0].name;
|
||||
@ -131,6 +149,8 @@ function api_upload_file() {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Get current path from url
|
||||
function get_curr_path() {
|
||||
let curr_dir = findGetParameter('path');
|
||||
if (curr_dir === null) {
|
||||
@ -142,7 +162,7 @@ function get_curr_path() {
|
||||
curr_dir = '/' + curr_dir;
|
||||
}
|
||||
|
||||
if(curr_dir === '') curr_dir = '/';
|
||||
if (curr_dir === '') curr_dir = '/';
|
||||
|
||||
return curr_dir;
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
// open modal
|
||||
function create_modal(title, content, footer) {
|
||||
let div = document.createElement('div');
|
||||
div.innerHTML = `<div id="modal">
|
||||
@ -23,10 +24,13 @@ function create_modal(title, content, footer) {
|
||||
document.body.appendChild(div.firstChild);
|
||||
}
|
||||
|
||||
|
||||
// remove modal
|
||||
function remove_modal() {
|
||||
document.getElementById('modal').remove();
|
||||
}
|
||||
|
||||
// change content
|
||||
function change_modal_content(content) {
|
||||
document.getElementById("modal_content").innerHTML = content;
|
||||
}
|
@ -8,20 +8,21 @@ function httpGetAsync(url, data, callback) {
|
||||
}
|
||||
callback(xmlHttp.responseText, xmlHttp.status);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xmlHttp.open("GET", url, true);
|
||||
xmlHttp.setRequestHeader('Authorization', 'Basic ' + sessionStorage.getItem('authorization'));
|
||||
xmlHttp.send(null);
|
||||
xmlHttp.send();
|
||||
}
|
||||
|
||||
|
||||
function httpPostAsync(url, data, callback) {
|
||||
const xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.onreadystatechange = function () {
|
||||
if (this.readyState === 4) {
|
||||
callback(xmlHttp.responseText, xmlHttp.status);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xmlHttp.open("POST", url, true);
|
||||
xmlHttp.setRequestHeader('Authorization', 'Basic ' + sessionStorage.getItem('authorization'));
|
||||
@ -29,19 +30,20 @@ function httpPostAsync(url, data, callback) {
|
||||
xmlHttp.send(data);
|
||||
}
|
||||
|
||||
|
||||
function httpUploadAsync(url, data, callback) {
|
||||
const xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.onreadystatechange = function () {
|
||||
if (this.readyState === 4) {
|
||||
callback(xmlHttp.responseText, xmlHttp.status);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xmlHttp.upload.addEventListener("progress",function(event){
|
||||
xmlHttp.upload.addEventListener("progress", function (event) {
|
||||
let progressBar = document.getElementById("upload_progress");
|
||||
let progress = (event.loaded/event.total)*100;
|
||||
let progress = (event.loaded / event.total) * 100;
|
||||
progressBar.value = progress;
|
||||
console.log(progress)
|
||||
console.log(progress);
|
||||
});
|
||||
|
||||
xmlHttp.open("POST", url, true);
|
||||
@ -49,19 +51,22 @@ function httpUploadAsync(url, data, callback) {
|
||||
xmlHttp.send(data);
|
||||
}
|
||||
|
||||
|
||||
function httpDeleteAsync(url, data, callback) {
|
||||
const xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.onreadystatechange = function () {
|
||||
if (this.readyState === 4) {
|
||||
callback(xmlHttp.responseText, xmlHttp.status);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xmlHttp.open("DELETE", url, true);
|
||||
xmlHttp.setRequestHeader('Authorization', 'Basic ' + sessionStorage.getItem('authorization'));
|
||||
xmlHttp.send();
|
||||
}
|
||||
|
||||
|
||||
// Timeout for logout
|
||||
function startTimeout() {
|
||||
return setTimeout(function () {
|
||||
sessionStorage.removeItem('authorization');
|
||||
@ -71,6 +76,8 @@ function startTimeout() {
|
||||
}, 600000);
|
||||
}
|
||||
|
||||
|
||||
// Find get parameter in url
|
||||
function findGetParameter(parameterName) {
|
||||
let result = null,
|
||||
tmp = [];
|
||||
@ -84,16 +91,20 @@ function findGetParameter(parameterName) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Generate random id
|
||||
function get_random_id() {
|
||||
let s4 = function () {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
}
|
||||
};
|
||||
|
||||
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
|
||||
}
|
||||
|
||||
|
||||
// Parse error
|
||||
function try_to_parse_error(message) {
|
||||
try {
|
||||
message = JSON.parse(message);
|
||||
|
@ -1,3 +1,4 @@
|
||||
// Show base after login
|
||||
function create_base_view() {
|
||||
let tmp;
|
||||
tmp = document.createElement('div');
|
||||
@ -20,10 +21,12 @@ function create_base_view() {
|
||||
<button class="material-icon" onclick="add_file();" type="button">description</button>
|
||||
<button class="material-icon" onclick="upload_file();" type="button">file_upload</button>
|
||||
</div>
|
||||
</div>`
|
||||
</div>`;
|
||||
document.getElementsByTagName('main')[0].appendChild(tmp);
|
||||
}
|
||||
|
||||
|
||||
// Show login
|
||||
function create_login_view() {
|
||||
let tmp = document.createElement('div');
|
||||
tmp.innerHTML = `<div id="login">
|
||||
@ -32,11 +35,11 @@ function create_login_view() {
|
||||
<span id="error"></span>
|
||||
<div>
|
||||
<label for="username"></label>
|
||||
<input type="text" name="username" id="username" placeholder="Username" value="admin">
|
||||
<input type="text" name="username" id="username" placeholder="Username">
|
||||
</div>
|
||||
<div>
|
||||
<label for="password"></label>
|
||||
<input type="password" name="password" id="password" placeholder="Password" value="admin">
|
||||
<input type="password" name="password" id="password" placeholder="Password">
|
||||
</div>
|
||||
<div>
|
||||
<button type="button" value="Login" onclick="login();">Login</button>
|
||||
@ -46,6 +49,8 @@ function create_login_view() {
|
||||
document.getElementById("wrapper").innerHTML = tmp.innerHTML;
|
||||
}
|
||||
|
||||
|
||||
// Add logout button
|
||||
function create_logout_view() {
|
||||
let logout = document.createElement('div');
|
||||
logout.id = 'logout';
|
||||
@ -61,10 +66,12 @@ function create_logout_view() {
|
||||
try_to_parse_error(response);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
document.getElementsByClassName('app-header')[0].appendChild(logout);
|
||||
}
|
||||
|
||||
|
||||
// Get icon for filetype
|
||||
function get_icon(type) {
|
||||
switch (type.split('/')[0]) {
|
||||
case 'application':
|
||||
@ -88,6 +95,8 @@ function get_icon(type) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create content
|
||||
function create_main_view(data) {
|
||||
let curr_dir = get_curr_path();
|
||||
|
||||
@ -118,7 +127,7 @@ function create_main_view(data) {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i]['Type'] === 'dir') {
|
||||
files.getElementsByTagName('tbody')[0].appendChild(add_table_row("folder", data[i]['Name'], "directory", curr_dir, true, function () {
|
||||
let url = ''
|
||||
let url;
|
||||
if (curr_dir === '/') {
|
||||
url = 'index.html?path=' + curr_dir + data[i]['Name'];
|
||||
} else {
|
||||
@ -134,7 +143,7 @@ function create_main_view(data) {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i]['Type'] !== 'dir') {
|
||||
files.getElementsByTagName('tbody')[0].appendChild(add_table_row(get_icon(data[i]['Type']), data[i]['Name'], data[i]['Type'], curr_dir, true, function () {
|
||||
let url = ''
|
||||
let url;
|
||||
if (curr_dir === '/') {
|
||||
url = '/' + data[i]['Name'];
|
||||
} else {
|
||||
@ -165,6 +174,8 @@ function create_main_view(data) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Create table row
|
||||
function add_table_row(icon, name, type, path, context, click_function) {
|
||||
let tr = document.createElement('tr');
|
||||
|
||||
@ -188,13 +199,15 @@ function add_table_row(icon, name, type, path, context, click_function) {
|
||||
return tr;
|
||||
}
|
||||
|
||||
|
||||
// Open file
|
||||
function show_file_view(data, type) {
|
||||
switch (type.split('/')[0]) {
|
||||
case 'audio':
|
||||
create_modal(`File: <span>${data}</span>`, ``);
|
||||
httpGetAsync(base_url + data + '?format=base64', null, function (response, code) {
|
||||
if (code === 200) {
|
||||
change_modal_content(`<audio controls><source src="data:audio;base64, ${response}">Your browser does not support the audio element.</audio>`);
|
||||
change_modal_content(`<audio controls><source src="data:${type};base64, ${response}">Your browser does not support the audio element.</audio>`);
|
||||
} else {
|
||||
try_to_parse_error(response);
|
||||
}
|
||||
@ -204,7 +217,7 @@ function show_file_view(data, type) {
|
||||
create_modal(`File: <span>${data}</span>`, ``);
|
||||
httpGetAsync(base_url + data + '?format=base64', null, function (response, code) {
|
||||
if (code === 200) {
|
||||
change_modal_content(`<img style="width: 100%" src="data:image/png;base64, ${response}" alt="Image">`); /* TODO */
|
||||
change_modal_content(`<img style="width: 100%" src="data:${type};base64, ${response}" alt="Image">`);
|
||||
} else {
|
||||
try_to_parse_error(response);
|
||||
}
|
||||
@ -224,7 +237,7 @@ function show_file_view(data, type) {
|
||||
create_modal(`File: <span>${data}</span>`, ``);
|
||||
httpGetAsync(base_url + data + '?format=base64', null, function (response, code) {
|
||||
if (code === 200) {
|
||||
change_modal_content(`<video controls style="width: 100%; height: 100%;"><source src="data:video;base64, ${response}">Your browser does not support the audio element.</video>`);
|
||||
change_modal_content(`<video controls style="width: 100%; height: 100%;"><source src="data:${type};base64, ${response}">Your browser does not support the audio element.</video>`);
|
||||
} else {
|
||||
try_to_parse_error(response);
|
||||
}
|
||||
|
24
create_zip.sh
Normal file
@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
# Remove old file
|
||||
rm Filemanager_20C_9829423.zip
|
||||
|
||||
# Create doc
|
||||
cd Documentation/ || exit
|
||||
mkdir -p out
|
||||
mkdir -p out/content
|
||||
mkdir -p out/customization
|
||||
mkdir -p out/images
|
||||
mkdir -p out/includes
|
||||
xelatex -file-line-error -interaction=nonstopmode -synctex=1 -output-directory=out main.tex
|
||||
biber out/main
|
||||
xelatex -file-line-error -interaction=nonstopmode -synctex=1 -output-directory=out main.tex
|
||||
|
||||
cd .. || exit
|
||||
|
||||
# Create zip
|
||||
cp Documentation/out/main.pdf Documentation/out/documentation.pdf
|
||||
cd Documentation/out/ && zip ../../Filemanager_20C_9829423.zip documentation.pdf && cd ../../
|
||||
cd Frontend && zip -r ../Filemanager_20C_9829423.zip . && cd ../
|
||||
|
||||
# Clean up
|
||||
rm -rf Documentation/out
|