mobile bunch of updayes

Former-commit-id: 28552c1940
This commit is contained in:
Henrique Dias 2017-01-01 22:40:12 +00:00
parent 9d9f02fbc9
commit 7fade4e2c5
8 changed files with 340 additions and 122 deletions

View File

@ -53,6 +53,10 @@ button:hover {
background-color: #1E88E5; background-color: #1E88E5;
} }
.mobile-only {
display: none !important;
}
.container { .container {
width: 95%; width: 95%;
max-width: 960px; max-width: 960px;
@ -366,6 +370,7 @@ header>div {
display: flex; display: flex;
width: 100%; width: 100%;
padding: 0.5em 0.5em 0.5em 1em; padding: 0.5em 0.5em 0.5em 1em;
align-items: center;
} }
header p { header p {
@ -387,12 +392,12 @@ header>div div {
vertical-align: middle; vertical-align: middle;
position: relative; position: relative;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; /* overflow: hidden; */
white-space: nowrap; white-space: nowrap;
} }
header .actions { header .actions {
margin-left: auto; /* margin-left: auto; */
} }
#logout { #logout {
@ -401,6 +406,20 @@ header .actions {
padding: .15em; padding: .15em;
} }
#click-overlay {
display: none;
position: fixed;
cursor: pointer;
top: 0;
left: 0;
height: 100%;
width: 100%;
}
#click-overlay.active {
display: block;
}
/* * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * *
* TOP BAR * * TOP BAR *
@ -559,7 +578,7 @@ header .actions {
height: 3.8em; height: 3.8em;
} }
#bottom-bar div:first-child>* { #bottom-bar>div:first-child>* {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
} }
@ -568,6 +587,14 @@ header .actions {
margin-right: .3em; margin-right: .3em;
} }
#bottom-bar>*:first-child {
margin-right: auto;
}
#more {
display: none;
}
#file-only { #file-only {
display: inline-block; display: inline-block;
border-right: 1px solid rgba(0, 0, 0, 0.075); border-right: 1px solid rgba(0, 0, 0, 0.075);
@ -584,55 +611,79 @@ header .actions {
/* * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * *
* BREADCRUMBS * * DROPDOWN *
* * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * */
#breadcrumbs-button { .dropdown {
padding: .4em 0.3em; position: fixed;
border-radius: .1em; top: -100%;
cursor: pointer; right: -100%;
transition: .1s ease all; visibility: hidden;
} display: flex;
#breadcrumbs-button.active,
#breadcrumbs-button:hover {
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
background: #fff;
}
#current-file {
line-height: 2.7em;
}
#breadcrumbs {
transition: .1s ease all;
padding: 0;
margin: 0;
list-style: none;
display: inline-flex;
flex-direction: column; flex-direction: column;
border-radius: 2px; border-radius: .1em;
border-top-left-radius: 0; border-top-left-radius: 0;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
background: #fff; background: #fff;
z-index: 9999999;
}
.dropdown.active {
right: .5em;
top: 4.5em;
visibility: visible;
}
.dropdown .action {
padding: .7em;
}
.dropdown i {
padding: 0;
vertical-align: middle;
}
.dropdown span {
display: inline-block;
margin-left: .5em;
font-size: .9em;
}
/* * * * * * * * * * * * * * * *
* BREADCRUMBS *
* * * * * * * * * * * * * * * */
#previous {
margin-left: -.5em;
}
#breadcrumbs {
list-style: none;
display: flex;
flex-direction: column;
position: absolute; position: absolute;
left: 0; margin: 0;
top: 2.3em; padding: 0;
min-width: 7em; min-width: 7em;
z-index: 999;
opacity: 0;
visibility: hidden;
color: #656565;
} }
#breadcrumbs.active { #breadcrumbs.active {
opacity: 1; opacity: 1;
visibility: visible; visibility: visible;
top: 0;
left: 0;
right: auto;
} }
#breadcrumbs li { #breadcrumbs li {
line-height: 1.5em; line-height: 1;
padding: .3em; padding: .7em;
transition: .1s ease all;
}
#breadcrumbs li:hover {
background-color: rgba(0, 0, 0, 0.04);
} }
@ -859,6 +910,39 @@ header .actions {
} }
/* * * * * * * * * * * * * * * *
* MULTIPLE SELECTION DIALOG *
* * * * * * * * * * * * * * * */
#multiple-selection {
position: fixed;
bottom: -4em;
left: 0;
z-index: 99999999;
width: 100%;
background-color: #2196f3;
height: 4em;
display: flex !important;
padding: 0.5em 0.5em 0.5em 1em;
justify-content: space-between;
align-items: center;
transition: .2s ease all;
}
#multiple-selection.active {
bottom: 0;
}
#multiple-selection * {
margin: 0;
}
#multiple-selection p,
#multiple-selection i {
color: #fff;
}
/* * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * *
* PROMPT * * PROMPT *
* * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * */
@ -992,6 +1076,12 @@ footer a:hover {
* * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * */
@media screen and (max-width: 650px) { @media screen and (max-width: 650px) {
body {
transition: .2s ease padding;
}
.mobile-only {
display: inherit !important;
}
#top-bar>div:nth-child(1) { #top-bar>div:nth-child(1) {
display: none; display: none;
} }
@ -1008,6 +1098,44 @@ footer a:hover {
width: calc(100% - 10em); width: calc(100% - 10em);
padding: .5em; padding: .5em;
} }
#main-actions {
position: fixed;
top: -100%;
right: -100%;
visibility: hidden;
display: flex;
flex-direction: column;
border-radius: .1em;
border-top-left-radius: 0;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
background: #fff;
z-index: 9999999;
}
#main-actions.active {
right: .5em;
top: 4.5em;
visibility: visible;
}
#main-actions .action {
padding: .7em;
border-radius: 0;
}
#main-actions .action:hover {
background-color: rgba(0, 0, 0, 0.04);
}
#main-actions i {
padding: 0;
vertical-align: middle;
}
#main-actions .action:hover i {
padding: 0;
background-color: transparent;
}
#main-actions span {
display: inline-block;
margin-left: .5em;
font-size: .9em;
}
} }

View File

@ -3,7 +3,8 @@
var tempID = "_fm_internal_temporary_id", var tempID = "_fm_internal_temporary_id",
buttons = {}, buttons = {},
templates = {}, templates = {},
selectedItems = []; selectedItems = [],
overlay, clickOverlay;
// Removes an element, if exists, from an array // Removes an element, if exists, from an array
Array.prototype.removeElement = function(element) { Array.prototype.removeElement = function(element) {
@ -36,7 +37,8 @@ Element.prototype.changeToLoading = function() {
element.style.opacity = 0; element.style.opacity = 0;
setTimeout(function() { setTimeout(function() {
element.innerHTML = '<i class="material-icons spin">autorenew</i>'; element.classList.add('spin');
element.innerHTML = 'autorenew';
element.style.opacity = 1; element.style.opacity = 1;
}, 200); }, 200);
@ -60,13 +62,9 @@ Element.prototype.changeToDone = function(error, html) {
} }
let firstStep = () => { let firstStep = () => {
this.innerHTML = '<i class="material-icons">done</i>'; this.classList.remove('spin');
if (error) { this.innerHTML = error ? 'close' : 'done';
this.innerHTML = '<i class="material-icons">close</i>';
}
this.style.opacity = 1; this.style.opacity = 1;
setTimeout(secondStep, 1000); setTimeout(secondStep, 1000);
} }
@ -123,6 +121,7 @@ function closePrompt(event) {
function notImplemented(event) { function notImplemented(event) {
event.preventDefault(); event.preventDefault();
clickOverlay.click();
let clone = document.importNode(templates.info.content, true); let clone = document.importNode(templates.info.content, true);
clone.querySelector('h3').innerHTML = 'Not implemented'; clone.querySelector('h3').innerHTML = 'Not implemented';
@ -172,7 +171,7 @@ function deleteSelected(single) {
Array.from(selectedItems).forEach(id => { Array.from(selectedItems).forEach(id => {
let request = new XMLHttpRequest(), let request = new XMLHttpRequest(),
html = buttons.delete.changeToLoading(), html = buttons.delete.querySelector('i').changeToLoading(),
el, url; el, url;
if (single) { if (single) {
@ -194,7 +193,7 @@ function deleteSelected(single) {
} }
} }
buttons.delete.changeToDone(request.status != 204, html); buttons.delete.querySelector('i').changeToDone(request.status != 204, html);
} }
} }
@ -396,10 +395,13 @@ window.addEventListener('keydown', (event) => {
* * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * */
document.addEventListener("DOMContentLoaded", function(event) { document.addEventListener("DOMContentLoaded", function(event) {
overlay = document.querySelector('.overlay');
clickOverlay = document.querySelector('#click-overlay');
buttons.logout = document.getElementById("logout"); buttons.logout = document.getElementById("logout");
buttons.open = document.getElementById("open"); buttons.open = document.getElementById("open");
buttons.delete = document.getElementById("delete"); buttons.delete = document.getElementById("delete");
buttons.breadcrumbs = document.getElementById("breadcrumbs-button"); buttons.previous = document.getElementById("previous");
// Attach event listeners // Attach event listeners
buttons.logout.addEventListener("click", logoutEvent); buttons.logout.addEventListener("click", logoutEvent);
@ -412,14 +414,20 @@ document.addEventListener("DOMContentLoaded", function(event) {
buttons.delete.addEventListener("click", deleteEvent); buttons.delete.addEventListener("click", deleteEvent);
} }
if (buttons.breadcrumbs) { if (buttons.previous) {
buttons.breadcrumbs.addEventListener("click", event => { buttons.previous.addEventListener("click", event => {
event.currentTarget.classList.toggle("active");
document.getElementById("breadcrumbs").classList.toggle("active"); document.getElementById("breadcrumbs").classList.toggle("active");
clickOverlay.classList.add('active');
clickOverlay.addEventListener('click', event => {
document.getElementById("breadcrumbs").classList.remove("active");
clickOverlay.classList.remove('active');
})
}); });
} }
document.querySelector('.overlay').addEventListener('click', event => { overlay.addEventListener('click', event => {
if (document.querySelector('.help.active')) { if (document.querySelector('.help.active')) {
closeHelp(event); closeHelp(event);
return; return;
@ -428,6 +436,21 @@ document.addEventListener("DOMContentLoaded", function(event) {
closePrompt(event); closePrompt(event);
}) })
let mainActions = document.getElementById('main-actions');
document.getElementById('more').addEventListener('click', event => {
event.preventDefault();
event.stopPropagation();
clickOverlay.classList.add('active');
mainActions.classList.add('active');
clickOverlay.addEventListener('click', event => {
mainActions.classList.remove('active');
clickOverlay.classList.remove('active');
})
})
setupSearch(); setupSearch();
return false; return false;
}); });

View File

@ -209,7 +209,7 @@ document.addEventListener("DOMContentLoaded", (event) => {
data.content = data.content.toString(); data.content = data.content.toString();
} }
let html = button.changeToLoading(), let html = button.querySelector('i').changeToLoading(),
request = new XMLHttpRequest(); request = new XMLHttpRequest();
request.open("PUT", toWebDavURL(window.location.pathname)); request.open("PUT", toWebDavURL(window.location.pathname));
@ -217,7 +217,7 @@ document.addEventListener("DOMContentLoaded", (event) => {
request.send(JSON.stringify(data)); request.send(JSON.stringify(data));
request.onreadystatechange = function() { request.onreadystatechange = function() {
if (request.readyState == 4) { if (request.readyState == 4) {
button.changeToDone((request.status != 201), html); button.querySelector('i').changeToDone((request.status != 201), html);
} }
} }
} }

View File

@ -1,6 +1,8 @@
'use strict'; 'use strict';
var listing = {}; var listing = {
selectMultiple: false
};
listing.reload = function(callback) { listing.reload = function(callback) {
let request = new XMLHttpRequest(); let request = new XMLHttpRequest();
@ -126,7 +128,7 @@ listing.rename = function(event) {
let newName = event.currentTarget.querySelector('input').value, let newName = event.currentTarget.querySelector('input').value,
newLink = removeLastDirectoryPartOf(toWebDavURL(link)) + "/" + newName, newLink = removeLastDirectoryPartOf(toWebDavURL(link)) + "/" + newName,
html = buttons.rename.changeToLoading(), html = buttons.rename.querySelector('i').changeToLoading(),
request = new XMLHttpRequest(); request = new XMLHttpRequest();
request.open('MOVE', toWebDavURL(link)); request.open('MOVE', toWebDavURL(link));
@ -147,7 +149,7 @@ listing.rename = function(event) {
}); });
} }
buttons.rename.changeToDone((request.status != 201 && request.status != 204), html); buttons.rename.querySelector('i').changeToDone((request.status != 201 && request.status != 204), html);
} }
} }
@ -169,7 +171,7 @@ listing.rename = function(event) {
listing.handleFiles = function(files, base) { listing.handleFiles = function(files, base) {
let button = document.getElementById("upload"), let button = document.getElementById("upload"),
html = button.changeToLoading(); html = button.querySelector('i').changeToLoading();
for (let i = 0; i < files.length; i++) { for (let i = 0; i < files.length; i++) {
let request = new XMLHttpRequest(); let request = new XMLHttpRequest();
@ -182,7 +184,7 @@ listing.handleFiles = function(files, base) {
listing.reload(); listing.reload();
} }
button.changeToDone((request.status != 201), html); button.querySelector('i').changeToDone((request.status != 201), html);
} }
} }
} }
@ -259,7 +261,7 @@ listing.selectItem = function(event) {
if (selectedItems.length != 0) event.preventDefault(); if (selectedItems.length != 0) event.preventDefault();
if (selectedItems.indexOf(el.id) == -1) { if (selectedItems.indexOf(el.id) == -1) {
if (!event.ctrlKey) listing.unselectAll(); if (!event.ctrlKey && !listing.selectMultiple) listing.unselectAll();
el.setAttribute("aria-selected", true); el.setAttribute("aria-selected", true);
selectedItems.push(el.id); selectedItems.push(el.id);
@ -290,7 +292,7 @@ listing.newFilePrompt = function(event) {
event.preventDefault(); event.preventDefault();
let button = document.getElementById('new'), let button = document.getElementById('new'),
html = button.changeToLoading(), html = button.querySelector('i').changeToLoading(),
request = new XMLHttpRequest(), request = new XMLHttpRequest(),
name = event.currentTarget.querySelector('input').value; name = event.currentTarget.querySelector('input').value;
@ -298,7 +300,7 @@ listing.newFilePrompt = function(event) {
request.send(); request.send();
request.onreadystatechange = function() { request.onreadystatechange = function() {
if (request.readyState == 4) { if (request.readyState == 4) {
button.changeToDone((request.status != 201), html); button.querySelector('i').changeToDone((request.status != 201), html);
listing.reload(); listing.reload();
} }
} }
@ -322,7 +324,6 @@ window.addEventListener('keydown', (event) => {
if (document.querySelectorAll('.prompt').length) { if (document.querySelectorAll('.prompt').length) {
closePrompt(event); closePrompt(event);
} }
} }
if (event.keyCode == 113) { if (event.keyCode == 113) {
@ -351,10 +352,27 @@ document.addEventListener('DOMContentLoaded', event => {
buttons.new = document.getElementById('new'); buttons.new = document.getElementById('new');
buttons.download = document.getElementById('download'); buttons.download = document.getElementById('download');
document.getElementById('multiple-selection-activate').addEventListener('click', event => {
listing.selectMultiple = true;
clickOverlay.click();
document.getElementById('multiple-selection').classList.add('active');
document.querySelector('body').style.paddingBottom = "4em";
})
document.getElementById('multiple-selection-cancel').addEventListener('click', event => {
listing.selectMultiple = false;
document.querySelector('body').style.paddingBottom = "0";
document.getElementById('multiple-selection').classList.remove('active');
})
if (user.AllowEdit) { if (user.AllowEdit) {
buttons.rename.addEventListener("click", listing.rename); buttons.rename.addEventListener("click", listing.rename);
} }
let items = document.getElementsByClassName('item');
if (user.AllowNew) { if (user.AllowNew) {
buttons.upload.addEventListener("click", (event) => { buttons.upload.addEventListener("click", (event) => {
document.getElementById("upload-input").click(); document.getElementById("upload-input").click();
@ -363,7 +381,6 @@ document.addEventListener('DOMContentLoaded', event => {
buttons.new.addEventListener('click', listing.newFileButton); buttons.new.addEventListener('click', listing.newFileButton);
// Drag and Drop // Drag and Drop
let items = document.getElementsByClassName('item');
document.addEventListener("dragover", function(event) { document.addEventListener("dragover", function(event) {
event.preventDefault(); event.preventDefault();
}, false); }, false);
@ -382,4 +399,26 @@ document.addEventListener('DOMContentLoaded', event => {
document.addEventListener("drop", listing.documentDrop, false); document.addEventListener("drop", listing.documentDrop, false);
} }
let touches = {
id: '',
count: 0
};
Array.from(items).forEach(file => {
file.addEventListener('touchstart', event => {
if (touches.id != file.id) {
touches.id = file.id;
touches.count = 1;
return;
}
touches.count++;
if (touches.count > 1) {
window.location = file.dataset.url;
}
});
});
}); });

View File

@ -3,7 +3,7 @@
{{ $absURL := .Config.AbsoluteURL }} {{ $absURL := .Config.AbsoluteURL }}
<head> <head>
<title>{{.Name}}</title> <title>{{.Name}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="token" content="{{ .Token }}"> <meta name="token" content="{{ .Token }}">
<link rel="stylesheet" href="{{ .Config.AbsoluteURL }}/_filemanagerinternal/css/normalize.css"> <link rel="stylesheet" href="{{ .Config.AbsoluteURL }}/_filemanagerinternal/css/normalize.css">
@ -48,18 +48,25 @@
<div id="bottom-bar"> <div id="bottom-bar">
<div> <div>
{{- if ne .Name "/"}} {{- if ne .Name "/"}}
<p id="breadcrumbs-button">Previous</p> <div class="action" id="previous">
<ul id="breadcrumbs"> <i class="material-icons">subdirectory_arrow_left</i>
</div>
<ul class="dropdown" id="breadcrumbs">
{{- range $item := .BreadcrumbMap }} {{- range $item := .BreadcrumbMap }}
<a href="{{ $absURL }}{{ $item.URL }}"><li>{{ $item.Name }}</li></a> <a href="{{ $absURL }}{{ $item.URL }}"><li>{{ $item.Name }}</li></a>
{{- end }} {{- end }}
</ul><i class="material-icons">keyboard_arrow_right</i> </ul>
{{- end }} {{- end }}
<p id="current-file">{{ if ne .Name "/"}}{{ .Name }}{{ else }}Root{{ end }}</p>
<p>{{ if ne .Name "/"}}{{ .Name }}{{ else }}Root{{ end }}</p>
</div> </div>
<div class="actions"> <div class="action mobile-only" id="more">
<div id="file-only" {{ if .IsDir }}class="disabled"{{ end }}> <i class="material-icons">more_vert</i>
</div>
<div class="actions{{ if .IsDir }} disabled{{ end }}" id="file-only">
{{- if and (not .IsDir) (.User.AllowEdit) }} {{- if and (not .IsDir) (.User.AllowEdit) }}
{{- if .Editor}} {{- if .Editor}}
{{- if eq .Data.Mode "markdown" }} {{- if eq .Data.Mode "markdown" }}
@ -86,30 +93,35 @@
{{- if .User.AllowEdit }} {{- if .User.AllowEdit }}
<div class="action" id="delete"> <div class="action" id="delete">
<i class="material-icons" title="Delete">delete</i> <span>Delete</span> <i class="material-icons" title="Delete">delete</i><span>Delete</span>
</div> </div>
{{- end }} {{- end }}
</div> </div>
<div class="actions" id="main-actions">
{{- if .IsDir }} {{- if .IsDir }}
<div class="action" id="view"> <div class="action" id="view">
{{- if eq .Display "mosaic" }} {{- if eq .Display "mosaic" }}
<a href="?display=list"><i class="material-icons" title="Switch View">view_list</i></a> <a href="?display=list"><i class="material-icons" title="Switch View">view_list</i><span>Switch view</span></a>
{{- else }} {{- else }}
<a href="?display=mosaic"><i class="material-icons" title="Switch View">view_module</i></a> <a href="?display=mosaic"><i class="material-icons" title="Switch View">view_module</i><span>Switch view</span></a>
{{- end }} {{- end }}
</div> </div>
<div class="action mobile-only" id="multiple-selection-activate">
<i class="material-icons">check_circle</i><span>Select</span>
</div>
{{- end }} {{- end }}
{{- if and (.User.AllowNew) (.IsDir) }} {{- if and (.User.AllowNew) (.IsDir) }}
<div class="action" id="upload"> <div class="action" id="upload">
<i class="material-icons" title="Upload">file_upload</i> <span>Upload</span> <i class="material-icons" title="Upload">file_upload</i><span>Upload</span>
</div> </div>
{{- end }} {{- end }}
<div class="action" id="download"> <div class="action" id="download">
<a href="?download=true"> <a href="?download=true">
<i class="material-icons" title="Download">file_download</i> <span>Download</span> <i class="material-icons" title="Download">file_download</i><span>Download</span>
</a> </a>
{{- if .IsDir }} {{- if .IsDir }}
<ul class="prev-links"> <ul class="prev-links">
@ -122,12 +134,21 @@
</div> </div>
<div class="action" id="info" onclick="notImplemented(event);"> <div class="action" id="info" onclick="notImplemented(event);">
<i class="material-icons" title="Info">info</i> <i class="material-icons" title="Info">info</i><span>Info</span>
</div> </div>
</div> </div>
</div> </div>
<div id="click-overlay"></div>
</header> </header>
<div id="multiple-selection" class="mobile-only">
<p>Multiple selection enabled</p>
<div class="action" id="multiple-selection-cancel">
<i class="material-icons" title="Clear">clear</i>
</div>
</div>
<main> <main>
{{- template "content" . }} {{- template "content" . }}
</main> </main>

View File

@ -36,7 +36,7 @@
<h2>Folders</h2> <h2>Folders</h2>
<div> <div>
{{- range .Items }} {{- range .Items }}
{{- if and (.UserAllowed) (.IsDir) }} {{- if (.IsDir) }}
{{ template "item" .}} {{ template "item" .}}
{{- end }} {{- end }}
{{- end }} {{- end }}
@ -47,7 +47,7 @@
<h2>Files</h2> <h2>Files</h2>
<div> <div>
{{- range .Items }} {{- range .Items }}
{{- if and (.UserAllowed) (not .IsDir) }} {{- if (not .IsDir) }}
{{ template "item" .}} {{ template "item" .}}
{{- end }} {{- end }}
{{- end }} {{- end }}
@ -55,7 +55,7 @@
{{- end }} {{- end }}
</div> </div>
<input style="display:none" type="file" id="upload-input" onchange="handleFiles(this.files, '')" value="Upload" multiple> <input style="display:none" type="file" id="upload-input" onchange="listing.handleFiles(this.files, '')" value="Upload" multiple>
{{- end -}} {{- end -}}
{{- end -}} {{- end -}}

View File

@ -57,6 +57,11 @@ func GetListing(u *config.User, filePath string, baseURL string) (*Listing, erro
for _, f := range files { for _, f := range files {
name := f.Name() name := f.Name()
allowed := u.Allowed("/" + name)
if !allowed {
continue
}
if f.IsDir() { if f.IsDir() {
name += "/" name += "/"
@ -71,7 +76,7 @@ func GetListing(u *config.User, filePath string, baseURL string) (*Listing, erro
i := Info{ i := Info{
FileInfo: f, FileInfo: f,
URL: url.String(), URL: url.String(),
UserAllowed: u.Allowed("/" + name), UserAllowed: allowed,
} }
i.RetrieveFileType() i.RetrieveFileType()

View File

@ -10,6 +10,8 @@ const errTemplate = `<!DOCTYPE html>
<html> <html>
<head> <head>
<title>TITLE</title> <title>TITLE</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<style> <style>
html { html {
background-color: #2196f3; background-color: #2196f3;