mirror of
https://github.com/mickael-kerjean/filestash
synced 2026-01-06 15:55:30 +01:00
chore (rewrite): improve user experience
This commit is contained in:
parent
3c47bb15ac
commit
591e50053c
8 changed files with 43 additions and 20 deletions
|
|
@ -45,7 +45,10 @@ class Loader extends window.HTMLElement {
|
|||
|
||||
customElements.define("component-loader", Loader);
|
||||
export function createLoader($parent, opts = {}) {
|
||||
const { wait = 250 } = opts;
|
||||
const {
|
||||
wait = 250,
|
||||
append = ($loader) => $parent.appendChild($loader),
|
||||
} = opts;
|
||||
const $icon = createElement(`
|
||||
<div class="component_loader">
|
||||
<style>
|
||||
|
|
@ -58,16 +61,13 @@ export function createLoader($parent, opts = {}) {
|
|||
<component-icon name="loading"></component-icon>
|
||||
</div>
|
||||
`);
|
||||
let $cache = null;
|
||||
const id = window.setTimeout(() => {
|
||||
$cache = $parent;
|
||||
$parent.appendChild($icon);
|
||||
append($icon);
|
||||
animate($icon, { time: 750, keyframes: opacityIn() });
|
||||
}, wait);
|
||||
|
||||
const cancel = () => {
|
||||
clearTimeout(id);
|
||||
if(!$cache) return;
|
||||
$icon.remove();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -33,17 +33,22 @@
|
|||
margin-left: -3px;
|
||||
margin-right: -3px;
|
||||
}
|
||||
.touch-yes [is="component_submenu"] .component_submenu .action button img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
[is="component_submenu"] .component_submenu .action.left {
|
||||
margin-right: 2px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
display: flex;
|
||||
}
|
||||
[is="component_submenu"] .component_submenu .action.right:hover,
|
||||
.touch-no [is="component_submenu"] .component_submenu .action.right:hover,
|
||||
[is="component_submenu"] .component_submenu .action.right.hover{
|
||||
background: var(--border);
|
||||
}
|
||||
[is="component_submenu"] .component_submenu .action button:hover {
|
||||
.touch-no [is="component_submenu"] .component_submenu .action button:hover {
|
||||
filter: brightness(0.9);
|
||||
background: var(--border);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,10 +104,13 @@ export function createThing({
|
|||
$placeholder.classList.add("placeholder");
|
||||
$placeholder.setAttribute("src", IMAGE.THUMBNAIL_PLACEHOLDER);
|
||||
$img.parentElement.appendChild($placeholder);
|
||||
$img.setAttribute("src", "api/files/cat?path=" + encodeURIComponent(path) + "&thumbnail=true");
|
||||
|
||||
$img.src = "api/files/cat?path=" + encodeURIComponent(path) + "&thumbnail=true";
|
||||
$img.loaded = false;
|
||||
const t = new Date();
|
||||
$img.onload = async () => {
|
||||
const duration = new Date() - t;
|
||||
$img.loaded = true;
|
||||
await Promise.all([
|
||||
animate($img, {
|
||||
keyframes: opacityIn(),
|
||||
|
|
@ -120,6 +123,15 @@ export function createThing({
|
|||
]);
|
||||
$placeholder.remove();
|
||||
};
|
||||
const id = setInterval(() => { // cancellation when image is outside the viewport
|
||||
if ($img.loaded === true) return clearInterval(id);
|
||||
else if (typeof $thing.checkVisibility !== "function") return clearInterval(id);
|
||||
else if ($thing.checkVisibility() === false) {
|
||||
$img.src = "";
|
||||
clearInterval(id);
|
||||
return;
|
||||
}
|
||||
}, 250);
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ export default function(render) {
|
|||
|
||||
// feature1: setup the dom
|
||||
const $epub = qs($page, `[data-bind="epub"]`);
|
||||
const removeLoader = createLoader($page);
|
||||
const removeLoader = createLoader($page, {
|
||||
append: ($loader) => $page.insertBefore($loader, qs($page, ".ebookviewer_container")),
|
||||
});
|
||||
const setup$ = rxjs.of($epub).pipe(
|
||||
rxjs.mergeMap(async($epub) => {
|
||||
const book = new window.ePub.Book({
|
||||
|
|
@ -42,12 +44,10 @@ export default function(render) {
|
|||
rendition.destroy();
|
||||
});
|
||||
book.open(getDownloadUrl());
|
||||
await new Promise((done) => {
|
||||
rendition.hooks.render.register(() => {
|
||||
rendition$.next(rendition);
|
||||
done();
|
||||
});
|
||||
});
|
||||
await new Promise((done) => rendition.hooks.render.register(() => {
|
||||
rendition$.next(rendition);
|
||||
done();
|
||||
}));
|
||||
}),
|
||||
removeLoader,
|
||||
rxjs.catchError(ctrlError()),
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export default function(render) {
|
|||
<component-menubar></component-menubar>
|
||||
<div class="component_image_container">
|
||||
<div class="images_wrapper">
|
||||
<img class="photo idle hidden" draggable="true" src="${getDownloadUrl()}">
|
||||
<img class="photo idle hidden" src="${getDownloadUrl()}&size=${window.innerWidth}">
|
||||
</div>
|
||||
<div class="images_aside scroll-y"></div>
|
||||
<div class="component_pager hidden"></div>
|
||||
|
|
|
|||
|
|
@ -27,12 +27,14 @@
|
|||
}
|
||||
.component_menubar .action-item {
|
||||
padding-right: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.component_menubar .action-item .component_icon {
|
||||
height: 19px;
|
||||
width: 19px;
|
||||
cursor: pointer;
|
||||
padding: 9px 2px 0px 2px;
|
||||
padding: 0 2px;
|
||||
}
|
||||
.component_menubar .action-item .download-button .component_icon {
|
||||
padding-right: 1px;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ export const options = () => ajax({
|
|||
method: "OPTIONS",
|
||||
}).pipe(rxjs.map((res) => res.responseHeaders.allow.replace(/\r/, "").split(", ")));
|
||||
|
||||
export const cat = () => ajax(getDownloadUrl()).pipe(
|
||||
export const cat = () => ajax({
|
||||
url: getDownloadUrl(),
|
||||
method: "GET",
|
||||
}).pipe(
|
||||
rxjs.map(({ response }) => response),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -34,12 +34,13 @@ func init() {
|
|||
Hooks.Register.ProcessFileContentBeforeSend(func(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
|
||||
if GetMimeType(req.URL.Query().Get("path")) != "image/svg+xml" {
|
||||
return reader, nil
|
||||
} else if disable_svg() == true {
|
||||
return reader, ErrNotAllowed
|
||||
} else if disable_svg() == false {
|
||||
return reader, nil
|
||||
}
|
||||
|
||||
// XSS
|
||||
(*res).Header().Set("Content-Security-Policy", "script-src 'none'; default-src 'none'; img-src 'self'")
|
||||
(*res).Header().Set("Content-Type", "text/plain")
|
||||
// XML bomb
|
||||
txt, _ := ioutil.ReadAll(reader)
|
||||
if regexp.MustCompile("(?is)entity").Match(txt) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue