mirror of
https://github.com/mickael-kerjean/filestash
synced 2025-12-06 08:22:24 +01:00
chore (tsc): tsc checks
This commit is contained in:
parent
8332752838
commit
9a45dc000a
60 changed files with 220 additions and 135 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import { toHref } from "../lib/skeleton/router.js";
|
||||
import { animate, slideYOut, slideYIn, opacityOut } from "../lib/animate.js";
|
||||
import { forwardURLParams } from "../lib/path.js";
|
||||
import assert from "../lib/assert.js";
|
||||
import { loadCSS } from "../helpers/loader.js";
|
||||
|
||||
import { extractPath, isDir, isNativeFileUpload } from "../pages/filespage/helper.js";
|
||||
|
|
@ -64,15 +65,14 @@ class ComponentBreadcrumb extends window.HTMLElement {
|
|||
const tasks = [];
|
||||
for (let i=0; i<nToAnimate; i++) {
|
||||
const n = previousChunks.length - i - 1;
|
||||
const $chunk = this.querySelector(`.component_path-element.n${n}`);
|
||||
if (!$chunk) throw new Error("component::breadcrumb.js - assertion failed - empty element");
|
||||
const $chunk = assert.type(this.querySelector(`.component_path-element.n${n}`), window.HTMLElement);
|
||||
tasks.push(animate($chunk, { time: 100, keyframes: slideYOut(-10) }));
|
||||
}
|
||||
await Promise.all(tasks);
|
||||
}
|
||||
|
||||
// STEP2: setup the actual content
|
||||
this.querySelector(`[data-bind="path"]`).innerHTML = pathChunks.map((chunk, idx) => {
|
||||
assert.type(this.querySelector(`[data-bind="path"]`), window.HTMLElement).innerHTML = pathChunks.map((chunk, idx) => {
|
||||
const label = idx === 0 ? (window.CONFIG.name || "Filestash") : chunk;
|
||||
const link = pathChunks.slice(0, idx + 1).join("/") + "/";
|
||||
const limitSize = (word, highlight = false) => {
|
||||
|
|
@ -130,8 +130,7 @@ class ComponentBreadcrumb extends window.HTMLElement {
|
|||
const nToAnimate = pathChunks.length - previousChunks.length;
|
||||
for (let i=0; i<nToAnimate; i++) {
|
||||
const n = pathChunks.length - i - 1;
|
||||
const $chunk = this.querySelector(`.component_path-element.n${n}`);
|
||||
if (!$chunk) throw new Error("component::breadcrumb.js - assertion failed - empty element");
|
||||
const $chunk = assert.type(this.querySelector(`.component_path-element.n${n}`), window.HTMLElement);
|
||||
await animate($chunk, { time: 100, keyframes: slideYIn(-5) });
|
||||
}
|
||||
}
|
||||
|
|
@ -141,9 +140,8 @@ class ComponentBreadcrumb extends window.HTMLElement {
|
|||
let state = this.hasAttribute("indicator");
|
||||
if (state && this.getAttribute("indicator") !== "false") state = true;
|
||||
|
||||
const $indicator = this.querySelector(`[data-bind="path"]`)
|
||||
.lastChild
|
||||
.querySelector("span");
|
||||
let $indicator = assert.type(this.querySelector(`[data-bind="path"]`), window.HTMLElement);
|
||||
$indicator = assert.type($indicator.lastChild.querySelector("span"), window.HTMLElement);
|
||||
|
||||
if (state) {
|
||||
$indicator.style.opacity = 1;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { createElement, createRender } from "../lib/skeleton/index.js";
|
||||
import { navigate, fromHref } from "../lib/skeleton/router.js";
|
||||
import rxjs, { effect } from "../lib/rx.js";
|
||||
import assert from "../lib/assert.js";
|
||||
import { onDestroy } from "../lib/skeleton/lifecycle.js";
|
||||
import { animate, slideYOut } from "../lib/animate.js";
|
||||
import { qs } from "../lib/dom.js";
|
||||
|
|
@ -9,7 +10,7 @@ import { init as initBreadcrumb } from "../components/breadcrumb.js";
|
|||
import ctrlSidebar, { init as initSidebar } from "./sidebar.js";
|
||||
|
||||
export default function(ctrl) {
|
||||
const urlToPath = (pathname = "") => decodeURIComponent(pathname.split("/").filter((chunk, i) => i !== 1).join("/"));
|
||||
const urlToPath = (pathname = "") => decodeURIComponent(pathname.split("/").filter((_, i) => i !== 1).join("/"));
|
||||
const $page = createElement(`
|
||||
<div class="component_filemanager_shell" style="flex-direction:row">
|
||||
<div data-bind="sidebar"></div>
|
||||
|
|
@ -42,7 +43,9 @@ export default function(ctrl) {
|
|||
// feature3: key shortcut
|
||||
const regexStartFiles = new RegExp("^/files/.+");
|
||||
effect(rxjs.fromEvent(window, "keydown").pipe(
|
||||
rxjs.filter((e) => regexStartFiles.test(fromHref(location.pathname)) && e.keyCode === 8 && document.activeElement.nodeName !== "INPUT"), // backspace in filemanager
|
||||
rxjs.filter((e) => regexStartFiles.test(fromHref(location.pathname)) &&
|
||||
e.keyCode === 8 &&
|
||||
assert.type(document.activeElement, window.HTMLElement).nodeName !== "INPUT"), // backspace in filemanager
|
||||
rxjs.tap(() => {
|
||||
const p = location.pathname.replace(new RegExp("/$"), "").split("/");
|
||||
p.pop();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { createFragment } from "../lib/skeleton/index.js";
|
||||
import { animate, slideYIn } from "../lib/animate.js";
|
||||
import assert from "../lib/assert.js";
|
||||
import { loadCSS } from "../helpers/loader.js";
|
||||
|
||||
await loadCSS(import.meta.url, "./dropdown.css");
|
||||
|
|
@ -75,9 +76,9 @@ export default class ComponentDropdown extends HTMLDivElement {
|
|||
`));
|
||||
|
||||
const setActive = () => this.classList.toggle("active");
|
||||
this.querySelector(".dropdown_button").onclick = () => {
|
||||
assert.type(this.querySelector(".dropdown_button"), window.HTMLElement).onclick = () => {
|
||||
setActive();
|
||||
animate(this.querySelector(".dropdown_container"), {
|
||||
animate(assert.type(this.querySelector(".dropdown_container"), window.HTMLElement), {
|
||||
time: 100,
|
||||
keyframes: slideYIn(2),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { loadCSS } from "../helpers/loader.js";
|
||||
import assert from "../lib/assert.js";
|
||||
|
||||
export default class ComponentFab extends window.HTMLButtonElement {
|
||||
constructor() {
|
||||
|
|
@ -9,7 +10,7 @@ export default class ComponentFab extends window.HTMLButtonElement {
|
|||
|
||||
async render($icon) {
|
||||
await loadCSS(import.meta.url, "./fab.css");
|
||||
this.querySelector(".content").replaceChildren($icon);
|
||||
assert.type(this.querySelector(".content"), window.HTMLElement).replaceChildren($icon);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { qs, qsa } from "../lib/dom.js";
|
|||
import { CSS } from "../helpers/loader.js";
|
||||
|
||||
export function createModal(opts) {
|
||||
const $dom = document.body.querySelector("component-modal");
|
||||
const $dom = assert.type(qs(document.body, "component-modal"), window.HTMLElement);
|
||||
assert.type($dom, ModalComponent);
|
||||
|
||||
return ($node, fn) => $dom.trigger($node, { onQuit: fn, ...opts });
|
||||
|
|
@ -35,14 +35,14 @@ const $modal = createElement(`
|
|||
`);
|
||||
|
||||
class ModalComponent extends window.HTMLElement {
|
||||
trigger($node, { withButtonsLeft = null, withButtonsRight = null, targetHeight = null, onQuit = (a) => Promise.resolve(a) }) {
|
||||
trigger($node, { withButtonsLeft = null, withButtonsRight = null, targetHeight = 0, onQuit = (a) => Promise.resolve(a) }) {
|
||||
const close$ = new rxjs.Subject();
|
||||
|
||||
// feature: build the dom
|
||||
qs($modal, `[data-bind="body"]`).replaceChildren($node);
|
||||
this.replaceChildren($modal);
|
||||
qsa($modal, ".component_popup > div.buttons > button").forEach(($button, i) => {
|
||||
assert.truthy(i >= 0 & i <= 2);
|
||||
assert.truthy(i >= 0 && i <= 2);
|
||||
let currentLabel = null;
|
||||
let buttonIndex = null;
|
||||
if (i === 0) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ const mv = (from, to) => withVirtualLayer(
|
|||
);
|
||||
|
||||
export default async function ctrlSidebar(render, nRestart = 0) {
|
||||
if (new URL(location).searchParams.get("nav") === "false") return;
|
||||
if (new URL(location.toString()).searchParams.get("nav") === "false") return;
|
||||
else if (document.body.clientWidth < 850) return;
|
||||
|
||||
const $page = render(createElement(`
|
||||
|
|
|
|||
10
public/assets/helpers/loader.d.ts
vendored
10
public/assets/helpers/loader.d.ts
vendored
|
|
@ -1,9 +1,11 @@
|
|||
export function loadScript(url: string): Promise<string>;
|
||||
|
||||
export function CSS(baseURL: string, ...arrayOfFilenames: string[]): Promise<string>;
|
||||
|
||||
export function loadSingleCSS(baseURL: string, filename: string): Promise<string>;
|
||||
|
||||
export function loadJS(baseURL: string, path: string, opts?: object): Promise<string>;
|
||||
|
||||
export function loadCSS(baseURL: string, ...arrayOfFilenames: string[]): Promise<string>;
|
||||
|
||||
export function loadCSSInline(baseURL: string, filename: string): Promise<string>;
|
||||
|
||||
export function CSS(baseURL: string, ...arrayOfFilenames: string[]): Promise<string>;
|
||||
|
||||
export function init(): Promise<void>;
|
||||
|
|
@ -12,8 +12,8 @@ export async function loadJS(baseURL, path, opts = {}) {
|
|||
if (document.head.querySelector(`[src="${link.toString()}"]`)) return Promise.resolve();
|
||||
document.head.appendChild($script);
|
||||
return new Promise((done) => {
|
||||
$script.onload = done;
|
||||
$script.onerror = done;
|
||||
$script.onload = () => done();
|
||||
$script.onerror = () => done();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
6
public/assets/lib/animate.d.ts
vendored
6
public/assets/lib/animate.d.ts
vendored
|
|
@ -10,6 +10,8 @@ type AnimationFrames = {
|
|||
transform?: string;
|
||||
opacity?: number;
|
||||
height?: string;
|
||||
width?: string;
|
||||
offset?: number;
|
||||
};
|
||||
|
||||
export function transition($node: HTMLElement, opts?: TransitionEnter | TransitionLeave): HTMLElement;
|
||||
|
|
@ -17,6 +19,10 @@ export function transition($node: HTMLElement, opts?: TransitionEnter | Transiti
|
|||
export function animate($node: HTMLElement | null, opts: {
|
||||
time: number;
|
||||
keyframes: AnimationFrames[];
|
||||
easing?: string;
|
||||
fill?: string;
|
||||
onExit?: () => void;
|
||||
onEnter?: () => void;
|
||||
}): Promise<void>;
|
||||
|
||||
export function slideXIn(dist: number): AnimationFrames[];
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
export default class assert {
|
||||
static type(object, type, msg) {
|
||||
if (object instanceof type) return;
|
||||
throw new Error(msg || `assertion failed - unexpected type for ${object.toString()}`);
|
||||
if (!(object instanceof type)) throw new TypeError(msg || `assertion failed - unexpected type for ${object.toString()}`);
|
||||
return object;
|
||||
}
|
||||
|
||||
static truthy(object, msg) {
|
||||
if (object) return;
|
||||
throw new Error(msg || `assertion failed - object is not truthy`);
|
||||
if (!object) throw new TypeError(msg || `assertion failed - object is not truthy`);
|
||||
}
|
||||
|
||||
static fail(object, msg) {
|
||||
throw new Error(msg || `assertion failed - ${object}`);
|
||||
throw new TypeError(msg || `assertion failed - ${object}`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class ChromecastManager {
|
|||
// }
|
||||
|
||||
createRequest(mediaInfo, authorization) {
|
||||
if (!authorization) Promise.error(new Error("Invalid account"));
|
||||
if (!authorization) Promise.reject(new Error("Invalid account"));
|
||||
|
||||
// TODO: it would be much much nicer to set the authorization in an HTTP header
|
||||
// but this would require to create a custom web receiver app, setup accounts on
|
||||
|
|
|
|||
4
public/assets/lib/dom.d.ts
vendored
4
public/assets/lib/dom.d.ts
vendored
|
|
@ -1,5 +1,5 @@
|
|||
export function qs($node: HTMLElement, selector: string);
|
||||
export function qs($node: HTMLElement | DocumentFragment, selector: string);
|
||||
|
||||
export function qsa($node: HTMLElement, selector: string);
|
||||
export function qsa($node: HTMLElement | DocumentFragment, selector: string);
|
||||
|
||||
export function safe(str: string): string;
|
||||
|
|
|
|||
2
public/assets/lib/random.d.ts
vendored
2
public/assets/lib/random.d.ts
vendored
|
|
@ -1 +1,3 @@
|
|||
export function gid(prefix: string): string;
|
||||
|
||||
export function randomString(size: number): string;
|
||||
|
|
|
|||
20
public/assets/lib/rx.d.ts
vendored
20
public/assets/lib/rx.d.ts
vendored
|
|
@ -7,11 +7,12 @@ import {
|
|||
switchMapTo, switchMap,
|
||||
BehaviorSubject, Subject, ReplaySubject,
|
||||
pipe, share, toArray, distinctUntilChanged, from,
|
||||
combineLatest, shareReplay, repeat, interval, merge,
|
||||
debounceTime, delay, concatMap, distinct, scan, throwError,
|
||||
} from "./vendor/rxjs.min.js";
|
||||
combineLatest, shareReplay, race, repeat, interval, merge,
|
||||
debounceTime, debounce, delay, concatMap, distinct, scan, throwError,
|
||||
zip, animationFrames, retry, forkJoin, skip, takeUntil, timer,
|
||||
} from "./vendor/rxjs/rxjs.min.js";
|
||||
|
||||
import * as rxajax from "./vendor/rxjs-ajax.min.js";
|
||||
import * as rxajax from "./vendor/rxjs/rxjs-ajax.min.js";
|
||||
|
||||
declare const rxjs: {
|
||||
of: typeof of,
|
||||
|
|
@ -31,6 +32,8 @@ declare const rxjs: {
|
|||
fromEvent: typeof fromEvent,
|
||||
delay: typeof delay,
|
||||
concatMap: typeof concatMap,
|
||||
animationFrames: typeof animationFrames,
|
||||
debounce: typeof debounce,
|
||||
debounceTime: typeof debounceTime,
|
||||
throwError: typeof throwError,
|
||||
interval: typeof interval,
|
||||
|
|
@ -48,6 +51,13 @@ declare const rxjs: {
|
|||
pipe: typeof pipe,
|
||||
share: typeof share,
|
||||
scan: typeof scan,
|
||||
race: typeof race,
|
||||
retry: typeof retry,
|
||||
zip: typeof zip,
|
||||
forkJoin: typeof forkJoin,
|
||||
skip: typeof skip,
|
||||
takeUntil: typeof takeUntil,
|
||||
timer: typeof timer,
|
||||
};
|
||||
|
||||
export default rxjs;
|
||||
|
|
@ -65,3 +75,5 @@ export function stateMutation($node: HTMLElement, attr: string);
|
|||
export function preventDefault(): typeof tap;
|
||||
|
||||
export function onClick($node: HTMLElement): typeof fromEvent;
|
||||
|
||||
export function onLoad($node: HTMLElement): typeof fromEvent;
|
||||
2
public/assets/lib/skeleton/index.d.ts
vendored
2
public/assets/lib/skeleton/index.d.ts
vendored
|
|
@ -5,6 +5,8 @@ export default function($root: HTMLElement | null, routes: object, opts: object)
|
|||
|
||||
export function createElement(str: string): HTMLElement;
|
||||
|
||||
export function createFragment(str: string): DocumentFragment;
|
||||
|
||||
export function createRender($parent: HTMLElement | null): (HTMLElement) => void;
|
||||
|
||||
export function nop(): void
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
export function settingsGet(initialValues, prefix = "") {
|
||||
const raw = JSON.parse(localStorage.getItem("settings")) || {};
|
||||
const raw = JSON.parse(localStorage.getItem("settings") || "{}") || {};
|
||||
const currentSettings = {};
|
||||
Object.keys(initialValues).forEach((key) => {
|
||||
const settingsKey = prefix ? `${prefix}_${key}` : key;
|
||||
|
|
@ -10,7 +10,7 @@ export function settingsGet(initialValues, prefix = "") {
|
|||
}
|
||||
|
||||
export function settingsSave(currentValues, prefix = "") {
|
||||
const raw = JSON.parse(localStorage.getItem("settings")) || {};
|
||||
const raw = JSON.parse(localStorage.getItem("settings") || "{}") || {};
|
||||
Object.keys(currentValues).forEach((key) => {
|
||||
const settingsKey = prefix ? `${prefix}_${key}` : key;
|
||||
raw[settingsKey] = currentValues[key];
|
||||
|
|
|
|||
1
public/assets/lib/vendor/hlsjs/hls.js
vendored
1
public/assets/lib/vendor/hlsjs/hls.js
vendored
|
|
@ -1,3 +1,4 @@
|
|||
// @ts-nocheck
|
||||
function getDefaultExportFromCjs (x) {
|
||||
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
||||
}
|
||||
|
|
|
|||
1
public/assets/lib/vendor/three/3DMLoader.js
vendored
1
public/assets/lib/vendor/three/3DMLoader.js
vendored
|
|
@ -1,3 +1,4 @@
|
|||
// @ts-nocheck
|
||||
import {
|
||||
BufferGeometryLoader,
|
||||
FileLoader,
|
||||
|
|
|
|||
1
public/assets/lib/vendor/three/EXRLoader.js
vendored
1
public/assets/lib/vendor/three/EXRLoader.js
vendored
|
|
@ -1,3 +1,4 @@
|
|||
// @ts-nocheck
|
||||
import {
|
||||
DataTextureLoader,
|
||||
DataUtils,
|
||||
|
|
|
|||
1
public/assets/lib/vendor/three/FBXLoader.js
vendored
1
public/assets/lib/vendor/three/FBXLoader.js
vendored
|
|
@ -1,3 +1,4 @@
|
|||
// @ts-nocheck
|
||||
import {
|
||||
AmbientLight,
|
||||
AnimationClip,
|
||||
|
|
|
|||
1
public/assets/lib/vendor/three/GLTFLoader.js
vendored
1
public/assets/lib/vendor/three/GLTFLoader.js
vendored
|
|
@ -1,3 +1,4 @@
|
|||
// @ts-nocheck
|
||||
import {
|
||||
AnimationClip,
|
||||
Bone,
|
||||
|
|
|
|||
1
public/assets/lib/vendor/three/OBJLoader.js
vendored
1
public/assets/lib/vendor/three/OBJLoader.js
vendored
|
|
@ -1,3 +1,4 @@
|
|||
// @ts-nocheck
|
||||
import {
|
||||
BufferGeometry,
|
||||
FileLoader,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// @ts-nocheck
|
||||
import {
|
||||
EventDispatcher,
|
||||
MOUSE,
|
||||
|
|
|
|||
1
public/assets/lib/vendor/three/STLLoader.js
vendored
1
public/assets/lib/vendor/three/STLLoader.js
vendored
|
|
@ -1,3 +1,4 @@
|
|||
// @ts-nocheck
|
||||
import {
|
||||
BufferAttribute,
|
||||
BufferGeometry,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// @ts-nocheck
|
||||
import {
|
||||
Curve,
|
||||
Vector3,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// @ts-nocheck
|
||||
import {
|
||||
Vector3,
|
||||
Vector4
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// @ts-nocheck
|
||||
/*!
|
||||
fflate - fast JavaScript compression/decompression
|
||||
<https://101arrowz.github.io/fflate>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// @ts-nocheck
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2010-2023 Three.js Authors
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// @ts-nocheck
|
||||
import {
|
||||
BufferAttribute,
|
||||
BufferGeometry,
|
||||
|
|
|
|||
|
|
@ -25,13 +25,13 @@ export async function init() {
|
|||
selectedLanguage = "zh_tw";
|
||||
break;
|
||||
default:
|
||||
const userLanguage = navigator.language.split("-")[0];
|
||||
const userLanguage = navigator.language.split("-")[0] || "";
|
||||
const idx = [
|
||||
"az", "be", "bg", "ca", "cs", "da", "de", "el", "es", "et",
|
||||
"eu", "fi", "fr", "gl", "hr", "hu", "id", "is", "it", "ja",
|
||||
"ka", "ko", "lt", "lv", "mn", "nb", "nl", "pl", "pt", "ro",
|
||||
"ru", "sk", "sl", "sr", "sv", "th", "tr", "uk", "vi", "zh",
|
||||
].indexOf(navigator.language.split("-")[0]);
|
||||
].indexOf(userLanguage);
|
||||
if (idx !== -1) {
|
||||
selectedLanguage = userLanguage;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { toHref } from "../../lib/skeleton/router.js";
|
|||
import rxjs, { effect, applyMutation, applyMutations, preventDefault, onClick } from "../../lib/rx.js";
|
||||
import ajax from "../../lib/ajax.js";
|
||||
import { qs, qsa, safe } from "../../lib/dom.js";
|
||||
import { animate, slideYIn, transition } from "../../lib/animate.js";
|
||||
import { animate, slideYIn, transition, opacityIn } from "../../lib/animate.js";
|
||||
import { createForm } from "../../lib/form.js";
|
||||
import { settings_get, settings_put } from "../../lib/settings.js";
|
||||
import t from "../../locales/index.js";
|
||||
|
|
@ -48,7 +48,7 @@ export default async function(render) {
|
|||
rxjs.map((conns) => conns.map(({ label, n }) => createElement(`<button data-current="${n}">${safe(label)}</button>`))),
|
||||
applyMutations($nav, "appendChild"),
|
||||
rxjs.tap((conns = []) => { if (conns.length > 1) $nav.classList.remove("hidden"); }),
|
||||
rxjs.tap(() => animate($nav)),
|
||||
rxjs.tap(() => animate($nav, { time: 250, keyframes: opacityIn() })),
|
||||
));
|
||||
|
||||
// feature2: select a default storage among all the available ones
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export default function(render) {
|
|||
const setState = (newState) => state$.next(newState);
|
||||
|
||||
effect(state$.asObservable().pipe(rxjs.mergeMap(({ step, ...state }) => {
|
||||
if (step === null) return verify(render, { shareID, setState });
|
||||
if (step === null) return verify(render, { shareID, setState, body: null });
|
||||
else if (step === "password") return ctrlPassword(render, { shareID, setState });
|
||||
else if (step === "email") return ctrlEmail(render, { shareID, setState });
|
||||
else if (step === "code") return ctrlEmailCodeVerification(render, { shareID, setState });
|
||||
|
|
@ -81,7 +81,7 @@ function ctrlEmailCodeVerification(render, { shareID, setState }) {
|
|||
return ctrlAbstract(render, { shareID, setState, $page });
|
||||
}
|
||||
|
||||
function verify(render, { shareID, setState, body }) {
|
||||
function verify(_, { shareID, setState, body }) {
|
||||
return ajax({
|
||||
method: "POST",
|
||||
url: `api/share/${shareID}/proof`,
|
||||
|
|
@ -115,7 +115,7 @@ function ctrlAbstract(render, { shareID, setState, $page }) {
|
|||
applyMutation(qs($page, "component-icon"), "setAttribute"),
|
||||
// STEP2: attempt to login
|
||||
rxjs.map(() => ({ type: qs($page, "input").name, value: qs($page, "input").value })),
|
||||
rxjs.switchMap((creds) => verify(render, { body: creds, shareID, setState }).pipe(rxjs.catchError((err) => {
|
||||
rxjs.switchMap((creds) => verify(render, { shareID, body: creds, setState }).pipe(rxjs.catchError((err) => {
|
||||
if (err instanceof AjaxError) {
|
||||
switch (err.code()) {
|
||||
case "INTERNAL_SERVER_ERROR":
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ export default WithShell(async function(render) {
|
|||
));
|
||||
|
||||
// feature: cleanup up the design when navbar is not there
|
||||
effect(rxjs.of(new URL(location).searchParams.get("nav")).pipe(
|
||||
effect(rxjs.of(new URL(location.toString()).searchParams.get("nav")).pipe(
|
||||
rxjs.filter((value) => value === "false"),
|
||||
rxjs.tap(() => {
|
||||
$page.parentElement.style.border = "none";
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { getSession } from "../../model/session.js";
|
||||
|
||||
class ICache {
|
||||
async get(path) { throw new Error("NOT_IMPLEMENTED"); }
|
||||
async get() { throw new Error("NOT_IMPLEMENTED"); }
|
||||
|
||||
async store(path) { throw new Error("NOT_IMPLEMENTED"); }
|
||||
async store() { throw new Error("NOT_IMPLEMENTED"); }
|
||||
|
||||
async remove(path, exact = true) { throw new Error("NOT_IMPLEMENTED"); }
|
||||
async remove() { throw new Error("NOT_IMPLEMENTED"); }
|
||||
|
||||
async update(path, fn) {
|
||||
const data = await this.get(path);
|
||||
|
|
@ -70,7 +70,7 @@ class IndexDBCache extends ICache {
|
|||
request.onsuccess = (e) => {
|
||||
done(e.target.result);
|
||||
};
|
||||
request.onerror = (e) => err(new Error("INDEXEDDB_NOT_SUPPORTED"));
|
||||
request.onerror = () => err(new Error("INDEXEDDB_NOT_SUPPORTED"));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -79,9 +79,9 @@ class IndexDBCache extends ICache {
|
|||
const tx = db.transaction(this.FILE_PATH, "readonly");
|
||||
const store = tx.objectStore(this.FILE_PATH);
|
||||
const query = store.get(this._key(path));
|
||||
return await new Promise((done, error) => {
|
||||
return await new Promise((done) => {
|
||||
query.onsuccess = (e) => done(query.result || null);
|
||||
query.onerror = () => done();
|
||||
query.onerror = () => done(null);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +123,7 @@ class IndexDBCache extends ICache {
|
|||
cursor.continue();
|
||||
return;
|
||||
}
|
||||
done();
|
||||
done(null);
|
||||
};
|
||||
request.onerror = err;
|
||||
});
|
||||
|
|
@ -131,7 +131,7 @@ class IndexDBCache extends ICache {
|
|||
|
||||
const req = store.delete(key);
|
||||
return await new Promise((done, err) => {
|
||||
req.onsuccess = () => done();
|
||||
req.onsuccess = () => done(null);
|
||||
req.onerror = err;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { createElement, createRender, onDestroy } from "../../lib/skeleton/index.js";
|
||||
import { animate, slideYIn } from "../../lib/animate.js";
|
||||
import rxjs, { effect, preventDefault } from "../../lib/rx.js";
|
||||
import assert from "../../lib/assert.js";
|
||||
import { loadCSS } from "../../helpers/loader.js";
|
||||
import { qs } from "../../lib/dom.js";
|
||||
import { ApplicationError } from "../../lib/error.js";
|
||||
|
|
@ -175,7 +176,7 @@ export default async function(render) {
|
|||
BLOCK_SIZE, COLUMN_PER_ROW, FILE_HEIGHT,
|
||||
MARGIN,
|
||||
currentState,
|
||||
height, setHeight,
|
||||
/* height, */ setHeight,
|
||||
$list,
|
||||
}) => rxjs.fromEvent($page.closest(".scroll-y"), "scroll", { passive: true }).pipe(
|
||||
rxjs.map((e) => {
|
||||
|
|
@ -261,7 +262,10 @@ export default async function(render) {
|
|||
rxjs.tap(() => clearSelection()),
|
||||
));
|
||||
effect(rxjs.fromEvent(window, "keydown").pipe(
|
||||
rxjs.filter((e) => e.key === "a" && (e.ctrlKey || e.metaKey) && (files$.value || []).length > 0 && document.activeElement.tagName !== "INPUT"),
|
||||
rxjs.filter((e) => e.key === "a" &&
|
||||
(e.ctrlKey || e.metaKey) &&
|
||||
(files$.value || []).length > 0 &&
|
||||
assert.type(document.activeElement, window.HTMLElement).tagName !== "INPUT"),
|
||||
preventDefault(),
|
||||
rxjs.tap(() => {
|
||||
clearSelection();
|
||||
|
|
@ -283,7 +287,7 @@ export default async function(render) {
|
|||
});
|
||||
}),
|
||||
));
|
||||
effect(getSelection$().pipe(rxjs.tap((a) => {
|
||||
effect(getSelection$().pipe(rxjs.tap(() => {
|
||||
for (const $thing of $page.querySelectorAll(".component_thing")) {
|
||||
const checked = isSelected(parseInt($thing.getAttribute("data-n")));
|
||||
$thing.classList.add(checked ? "selected" : "not-selected");
|
||||
|
|
@ -310,7 +314,7 @@ function renderEmpty(render, base64Icon) {
|
|||
<p class="label">${t("There is nothing here")}</p>
|
||||
</div>
|
||||
`);
|
||||
animate(render($page), { keyframes: slideYIn(5) });
|
||||
animate(render($page), { time: 250, keyframes: slideYIn(5) });
|
||||
}
|
||||
|
||||
export function init() {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export default async function(render) {
|
|||
return null;
|
||||
}),
|
||||
rxjs.filter((val) => val),
|
||||
rxjs.tap(async({ img, alt, targetName }) => {
|
||||
rxjs.tap(async({ img, alt }) => {
|
||||
$icon.setAttribute("src", `data:image/svg+xml;base64,${img}`);
|
||||
$icon.setAttribute("alt", alt);
|
||||
$input.value = "";
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ function componentLeft(render, { $scroll }) {
|
|||
));
|
||||
|
||||
effect(getSelection$().pipe(
|
||||
rxjs.filter((selections) => lengthSelection() > 1),
|
||||
rxjs.filter(() => lengthSelection() > 1),
|
||||
rxjs.map(() => render(createFragment(`
|
||||
<a target="_blank" ${generateLinkAttributes(expandSelection())}><button data-action="download">
|
||||
${t("Download")}
|
||||
|
|
@ -184,7 +184,7 @@ function componentLeft(render, { $scroll }) {
|
|||
return rxjs.from(componentDelete(
|
||||
createModal(modalOpt),
|
||||
"remove",
|
||||
)).pipe(rxjs.mergeMap((val) => {
|
||||
)).pipe(rxjs.mergeMap(() => {
|
||||
clearSelection();
|
||||
return rm(...paths);
|
||||
}));
|
||||
|
|
@ -217,8 +217,8 @@ function componentRight(render) {
|
|||
default: throw new Error("NOT_IMPLEMENTED");
|
||||
}
|
||||
};
|
||||
const defaultSort = () => {
|
||||
return `<img class="component_icon" draggable="false" src="data:image/svg+xml;base64,${ICONS.SORT}" alt="sort" />`;
|
||||
const defaultSort = (sort) => { // TODO
|
||||
return `<img class="component_icon" draggable="false" src="data:image/svg+xml;base64,${ICONS.SORT}" alt="${sort}" />`;
|
||||
};
|
||||
effect(getSelection$().pipe(
|
||||
rxjs.filter((selections) => selections.length === 0),
|
||||
|
|
@ -320,7 +320,7 @@ function componentRight(render) {
|
|||
rxjs.filter((e) => (e.ctrlKey || e.metaKey) && e.key === "f"),
|
||||
preventDefault(),
|
||||
),
|
||||
).pipe(rxjs.map(($el) => qs($page, "input").classList.contains("hidden"))),
|
||||
).pipe(rxjs.map(() => qs($page, "input").classList.contains("hidden"))),
|
||||
escape$.pipe(rxjs.mapTo(false)),
|
||||
).pipe(
|
||||
rxjs.takeUntil(getSelection$().pipe(rxjs.skip(1))),
|
||||
|
|
@ -379,12 +379,12 @@ function componentRight(render) {
|
|||
|
||||
effect(getSelection$().pipe(
|
||||
rxjs.filter((selections) => selections.length >= 1),
|
||||
rxjs.map((selections) => render(createFragment(`
|
||||
rxjs.map(() => render(createFragment(`
|
||||
<button data-bind="clear">
|
||||
${lengthSelection()} <component-icon name="close"></component-icon>
|
||||
</button>
|
||||
`))),
|
||||
rxjs.mergeMap(($page) => onClick($page, `[data-bind="clear"]`).pipe(
|
||||
rxjs.mergeMap(($page) => onClick(qs($page, `[data-bind="clear"]`)).pipe(
|
||||
rxjs.tap(() => clearSelection()),
|
||||
rxjs.takeUntil(getSelection$().pipe(rxjs.skip(1))),
|
||||
)),
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@
|
|||
content: ")";
|
||||
}
|
||||
.component_upload .stats_content .file_row .file_state {
|
||||
width: 40px;
|
||||
width: 50px;
|
||||
padding: 3px 0;
|
||||
}
|
||||
.component_upload .stats_content .file_row .file_control {
|
||||
|
|
|
|||
|
|
@ -21,13 +21,13 @@ export default async function(render) {
|
|||
|
||||
effect(getPermission().pipe(
|
||||
rxjs.filter(() => calculatePermission(currentPath(), "new-file")),
|
||||
rxjs.tap((a) => {
|
||||
rxjs.tap(() => {
|
||||
const $page = createFragment(`
|
||||
<div is="component_filezone"></div>
|
||||
<div is="component_upload_fab"></div>
|
||||
`);
|
||||
componentFilezone(createRender($page.children[0]), { workers$ });
|
||||
componentUploadFAB(createRender($page.children[1]), { workers$ });
|
||||
componentFilezone(createRender(assert.type($page.children[0], window.HTMLElement)), { workers$ });
|
||||
componentUploadFAB(createRender(assert.type($page.children[1], window.HTMLElement)), { workers$ });
|
||||
render($page);
|
||||
}),
|
||||
));
|
||||
|
|
@ -61,7 +61,7 @@ function componentUploadFAB(render, { workers$ }) {
|
|||
|
||||
function componentFilezone(render, { workers$ }) {
|
||||
const selector = `[data-bind="filemanager-children"]`;
|
||||
const $target = document.body.querySelector(selector);
|
||||
const $target = assert.type(document.body.querySelector(selector), window.HTMLElement);
|
||||
|
||||
$target.ondragenter = (e) => {
|
||||
if (!isNativeFileUpload(e)) return;
|
||||
|
|
@ -178,7 +178,7 @@ function componentUploadQueue(render, { workers$ }) {
|
|||
if (new Date() - last <= 500) return;
|
||||
last = new Date();
|
||||
const speed = workersSpeed.reduce((acc, el) => acc + el, 0);
|
||||
const $speed = $page.firstElementChild.nextElementSibling.firstElementChild;
|
||||
const $speed = assert.type($page.firstElementChild.nextElementSibling.firstElementChild, window.HTMLElement);
|
||||
$speed.textContent = formatSpeed(speed);
|
||||
};
|
||||
}(new Array(MAX_WORKERS).fill(0)));
|
||||
|
|
@ -207,7 +207,7 @@ function componentUploadQueue(render, { workers$ }) {
|
|||
$close.removeEventListener("click", cancel);
|
||||
break;
|
||||
case "error":
|
||||
const $retry = $iconRetry.cloneNode(true);
|
||||
const $retry = assert.type($iconRetry.cloneNode(true), window.HTMLElement);
|
||||
updateDOMGlobalTitle($page, t("Error"));
|
||||
updateDOMGlobalSpeed(nworker, 0);
|
||||
updateDOMTaskProgress($task, t("Error"));
|
||||
|
|
@ -237,7 +237,7 @@ function componentUploadQueue(render, { workers$ }) {
|
|||
}
|
||||
const $task = qs($page, `[data-path="${task.path}"]`);
|
||||
const exec = task.exec({
|
||||
error: (err) => updateDOMWithStatus($task, { status: "error", nworker }),
|
||||
error: () => updateDOMWithStatus($task, { status: "error", nworker, exec: null }),
|
||||
progress: (progress) => updateDOMTaskProgress($task, formatPercent(progress)),
|
||||
speed: (speed) => {
|
||||
updateDOMTaskSpeed($task, speed);
|
||||
|
|
@ -251,7 +251,7 @@ function componentUploadQueue(render, { workers$ }) {
|
|||
} catch (err) {
|
||||
updateDOMWithStatus($task, { exec, status: "error", nworker });
|
||||
}
|
||||
updateTotal.incrementCompleted(1);
|
||||
updateTotal.incrementCompleted();
|
||||
task.done = true;
|
||||
|
||||
if (tasks.length === 0 && // no remaining tasks
|
||||
|
|
@ -340,7 +340,7 @@ function workerImplFile({ error, progress, speed }) {
|
|||
return;
|
||||
}
|
||||
virtual.afterSuccess();
|
||||
done();
|
||||
done(null);
|
||||
};
|
||||
this.xhr.onerror = function(e) {
|
||||
err(new AjaxError("failed", e, "FAILED"));
|
||||
|
|
@ -360,7 +360,7 @@ function workerImplDirectory({ error, progress }) {
|
|||
}
|
||||
|
||||
cancel() {
|
||||
this.xhr.abort();
|
||||
if (this.xhr instanceof XMLHttpRequest) this.xhr.abort();
|
||||
}
|
||||
|
||||
run({ virtual, path }) {
|
||||
|
|
@ -397,7 +397,7 @@ function workerImplDirectory({ error, progress }) {
|
|||
return;
|
||||
}
|
||||
virtual.afterSuccess();
|
||||
done();
|
||||
done(null);
|
||||
};
|
||||
this.xhr.send(null);
|
||||
});
|
||||
|
|
@ -418,7 +418,7 @@ async function processFiles(filelist) {
|
|||
if (file.size % 4096 !== 0) {
|
||||
return Promise.resolve("file");
|
||||
}
|
||||
return new Promise((done, err) => {
|
||||
return new Promise((done) => {
|
||||
const reader = new window.FileReader();
|
||||
const tid = setTimeout(() => reader.abort(), 1000);
|
||||
reader.onload = () => done("file");
|
||||
|
|
@ -460,7 +460,7 @@ async function processFiles(filelist) {
|
|||
};
|
||||
break;
|
||||
default:
|
||||
assert.fail(`NOT_SUPPORTED type="${type}"`, type);
|
||||
assert.fail(type, `NOT_SUPPORTED type="${type}"`);
|
||||
}
|
||||
task.virtual.before();
|
||||
tasks.push(task);
|
||||
|
|
@ -476,7 +476,7 @@ async function processItems(itemList) {
|
|||
while (queue.length > 0) {
|
||||
const entry = queue.shift();
|
||||
const path = basepath + entry.fullPath.substring(1);
|
||||
let task = null;
|
||||
let task = {};
|
||||
if (entry === null) continue;
|
||||
else if (entry.isFile) {
|
||||
const entrySize = await new Promise((done) => entry.getMetadata(({ size }) => done(size)));
|
||||
|
|
|
|||
|
|
@ -44,12 +44,12 @@ function renderDesktop(render, removeLabel) {
|
|||
return ret.toPromise();
|
||||
}
|
||||
|
||||
function renderMobile(render, removeLabel) {
|
||||
function renderMobile(_, removeLabel) {
|
||||
return new Promise((done) => {
|
||||
const value = window.prompt(t("Confirm by typing") + ": " + removeLabel, "");
|
||||
if (value !== removeLabel) {
|
||||
return;
|
||||
}
|
||||
done();
|
||||
done(null);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ function renderDesktop(render, filename) {
|
|||
return ret.toPromise();
|
||||
}
|
||||
|
||||
function renderMobile(render, filename) {
|
||||
function renderMobile(_, filename) {
|
||||
return new Promise((done) => {
|
||||
const value = window.prompt(t("Rename as"), filename);
|
||||
if (!value || value === filename) {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export default function(render, { path }) {
|
|||
};
|
||||
|
||||
// feature: select
|
||||
const toggle = (val) => rxjs.mergeMap(($button) => {
|
||||
const toggle = (val) => rxjs.mergeMap(() => {
|
||||
state.form = {};
|
||||
role$.next(role$.value === val ? null : val);
|
||||
return rxjs.EMPTY;
|
||||
|
|
@ -150,7 +150,7 @@ async function ctrlExistingShare(render, { load, remove, all, formLinks }) {
|
|||
copyToClipboard(link);
|
||||
notification.info(t("The link was copied in the clipboard"));
|
||||
});
|
||||
qs($share, `[alt="delete"]`).onclick = async(e) => {
|
||||
qs($share, `[alt="delete"]`).onclick = async() => {
|
||||
$share.remove();
|
||||
length -= 1;
|
||||
if (length === 0) $content.replaceChildren(createElement(`
|
||||
|
|
@ -158,7 +158,7 @@ async function ctrlExistingShare(render, { load, remove, all, formLinks }) {
|
|||
`));
|
||||
await remove(shareObj);
|
||||
};
|
||||
qs($share, `[alt="edit"]`).onclick = (e) => load(shareObj);
|
||||
qs($share, `[alt="edit"]`).onclick = () => load(shareObj);
|
||||
$fragment.appendChild($share);
|
||||
});
|
||||
$content.replaceChildren($fragment);
|
||||
|
|
@ -229,7 +229,7 @@ async function ctrlCreateShare(render, { save, formState }) {
|
|||
};
|
||||
const tmpl = formTmpl({
|
||||
renderNode: () => createElement("<div></div>"),
|
||||
renderLeaf: ({ format, label, type }) => {
|
||||
renderLeaf: ({ label, type }) => {
|
||||
if (type !== "enable") return createElement("<label></label>");
|
||||
const title =
|
||||
label === "users_enable"
|
||||
|
|
@ -273,7 +273,7 @@ async function ctrlCreateShare(render, { save, formState }) {
|
|||
// sync editable custom link input with link id
|
||||
effect(rxjs.fromEvent(qs($form, `[name="url"]`), "keyup").pipe(rxjs.tap((e) => {
|
||||
id = e.target.value.replaceAll(" ", "-").replace(new RegExp("[^A-Za-z\-]"), "");
|
||||
qs($form.closest(".component_share"), `input[name="create"]`).value = `${location.origin}${toHref("/s/" + id)}`;
|
||||
qs(assert.type($form.closest(".component_share"), window.HTMLElement), `input[name="create"]`).value = `${location.origin}${toHref("/s/" + id)}`;
|
||||
})));
|
||||
|
||||
// feature: create a shared link
|
||||
|
|
@ -281,7 +281,8 @@ async function ctrlCreateShare(render, { save, formState }) {
|
|||
effect(onClick(qs($page, ".shared-link")).pipe(
|
||||
rxjs.first(),
|
||||
rxjs.switchMap(async() => {
|
||||
const body = [...new FormData(document.querySelector(".component_share form"))].reduce((acc, [key, value]) => {
|
||||
const body = [...new FormData(assert.type(qs(document.body, ".component_share form"), window.HTMLFormElement))]
|
||||
.reduce((acc, [key, value]) => {
|
||||
if (value && key.slice(-7) !== "_enable") acc[key] = value;
|
||||
return acc;
|
||||
}, { id });
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ export const mv = (from, to) => ajax({
|
|||
handleError,
|
||||
);
|
||||
|
||||
export const save = (path) => rxjs.of(null).pipe(rxjs.delay(1000));
|
||||
export const save = () => rxjs.of(null).pipe(rxjs.delay(1000));
|
||||
|
||||
export const ls = (path) => {
|
||||
const lsFromCache = (path) => rxjs.from(fscache().get(path));
|
||||
|
|
@ -101,7 +101,7 @@ export const ls = (path) => {
|
|||
rxjs.merge(
|
||||
rxjs.of(null),
|
||||
rxjs.merge(rxjs.of(null), rxjs.fromEvent(window, "keydown").pipe( // "r" shorcut
|
||||
rxjs.filter((e) => e.keyCode === 82 && document.activeElement.tagName !== "INPUT"),
|
||||
rxjs.filter((e) => e.keyCode === 82 && assert.type(document.activeElement, window.HTMLElement).tagName !== "INPUT"),
|
||||
)).pipe(rxjs.switchMap(() => lsFromHttp(path))),
|
||||
),
|
||||
).pipe(
|
||||
|
|
|
|||
|
|
@ -27,11 +27,6 @@ const mutationFiles$ = new rxjs.BehaviorSubject({
|
|||
// "/home/": [{ name: "test", fn: (file) => file, ...]
|
||||
});
|
||||
|
||||
window.debug = () => {
|
||||
console.log("VIRTUAL", JSON.stringify(virtualFiles$.value, null, 4));
|
||||
console.log("MUTATION", JSON.stringify(mutationFiles$.value));
|
||||
};
|
||||
|
||||
class IVirtualLayer {
|
||||
before() { throw new Error("NOT_IMPLEMENTED"); }
|
||||
async afterSuccess() { throw new Error("NOT_IMPLEMENTED"); }
|
||||
|
|
@ -73,7 +68,7 @@ export function touch(path) {
|
|||
hooks.mutation.emit({ op: "touch", path: basepath });
|
||||
}
|
||||
|
||||
async afterError(err, caught) {
|
||||
async afterError() {
|
||||
statePop(virtualFiles$, basepath, filename);
|
||||
return rxjs.of(fscache().remove(basepath)).pipe(
|
||||
rxjs.mergeMap(() => rxjs.EMPTY),
|
||||
|
|
@ -110,7 +105,7 @@ export function mkdir(path) {
|
|||
hooks.mutation.emit({ op: "mkdir", path: basepath });
|
||||
}
|
||||
|
||||
async afterError(err, caught) {
|
||||
async afterError() {
|
||||
statePop(virtualFiles$, basepath, dirname);
|
||||
return rxjs.of(fscache().remove(basepath)).pipe(
|
||||
rxjs.mergeMap(() => rxjs.EMPTY),
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export function createThing({
|
|||
name = "",
|
||||
type = "N/A",
|
||||
time = 0,
|
||||
path = null,
|
||||
path = "",
|
||||
size = 0,
|
||||
loading = false,
|
||||
link = "",
|
||||
|
|
@ -67,8 +67,7 @@ export function createThing({
|
|||
}) {
|
||||
const [, ext] = formatFile(name);
|
||||
const mime = TYPES.MIME[ext.toLowerCase()];
|
||||
const $thing = $tmpl.cloneNode(true);
|
||||
assert.type($thing, window.HTMLElement);
|
||||
const $thing = assert.type($tmpl.cloneNode(true), window.HTMLElement);
|
||||
|
||||
// you might wonder why don't we use querySelector to nicely get the dom nodes? Well,
|
||||
// we're in the hot path, better performance here is critical to get 60FPS.
|
||||
|
|
|
|||
5
public/assets/pages/viewerpage/application_audio.d.ts
vendored
Normal file
5
public/assets/pages/viewerpage/application_audio.d.ts
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
interface Window {
|
||||
WaveSurfer: {
|
||||
create: (options: any) => any;
|
||||
};
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ const STATUS_PLAYING = "PLAYING";
|
|||
const STATUS_PAUSED = "PAUSED";
|
||||
// const STATUS_BUFFERING = "BUFFERING";
|
||||
|
||||
export default function(render, { mime }) {
|
||||
export default function(render) {
|
||||
const $page = createElement(`
|
||||
<div class="component_audioplayer">
|
||||
<component-menubar></component-menubar>
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export default async function(render) {
|
|||
const id = setInterval(() => {
|
||||
if (/download=yes/.test(document.cookie)) return;
|
||||
clearInterval(id);
|
||||
done();
|
||||
done(null);
|
||||
}, 200);
|
||||
})),
|
||||
rxjs.tap(() => setLoading(false)),
|
||||
|
|
|
|||
5
public/assets/pages/viewerpage/application_ebook.d.ts
vendored
Normal file
5
public/assets/pages/viewerpage/application_ebook.d.ts
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
interface Window {
|
||||
ePub: {
|
||||
Book: new (options: any) => any;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import { createElement, onDestroy } from "../../lib/skeleton/index.js";
|
||||
import rxjs, { effect } from "../../lib/rx.js";
|
||||
import { qs } from "../../lib/dom.js";
|
||||
import assert from "../../lib/assert.js";
|
||||
import { loadJS, loadCSS } from "../../helpers/loader.js";
|
||||
import { createLoader } from "../../components/loader.js";
|
||||
import ctrlError from "../ctrl_error.js";
|
||||
|
|
@ -46,7 +47,7 @@ export default function(render) {
|
|||
book.open(getDownloadUrl());
|
||||
await new Promise((done) => rendition.hooks.render.register(() => {
|
||||
rendition$.next(rendition);
|
||||
done();
|
||||
done(null);
|
||||
}));
|
||||
}),
|
||||
removeLoader,
|
||||
|
|
@ -59,7 +60,7 @@ export default function(render) {
|
|||
effect(setup$.pipe(
|
||||
rxjs.mergeMap(() => rxjs.merge(
|
||||
rxjs.fromEvent(document, "keydown"),
|
||||
rendition$.pipe(rxjs.mergeMap(() => rxjs.fromEvent(qs(document, "iframe").contentDocument.body, "keydown"))),
|
||||
rendition$.pipe(rxjs.mergeMap(() => rxjs.fromEvent(assert.type(qs(document.body, "iframe"), window.HTMLElement).contentDocument.body, "keydown"))),
|
||||
)),
|
||||
rxjs.map((e) => {
|
||||
switch (e.code) {
|
||||
|
|
|
|||
9
public/assets/pages/viewerpage/application_editor.d.ts
vendored
Normal file
9
public/assets/pages/viewerpage/application_editor.d.ts
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
interface Window {
|
||||
CodeMirror: {
|
||||
(element: HTMLElement, options: any): any;
|
||||
__mode: string;
|
||||
commands: {
|
||||
save: (editor: any) => void;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -85,7 +85,7 @@ export default async function(render, { acl$ }) {
|
|||
editor.getWrapperElement().setAttribute("mode", mode);
|
||||
if (!("ontouchstart" in window)) editor.focus();
|
||||
if (config["editor"] === "emacs") editor.addKeyMap({
|
||||
"Ctrl-X Ctrl-C": (cm) => window.history.back(),
|
||||
"Ctrl-X Ctrl-C": () => window.history.back(),
|
||||
});
|
||||
onDestroy(() => editor.clearHistory());
|
||||
$dom.menubar().classList.remove("hidden");
|
||||
|
|
@ -133,7 +133,7 @@ export default async function(render, { acl$ }) {
|
|||
|
||||
// feature4: save
|
||||
effect(setup$.pipe(
|
||||
rxjs.mergeMap((editor) => new rxjs.Observable((observer) => {
|
||||
rxjs.mergeMap(() => new rxjs.Observable((observer) => {
|
||||
window.CodeMirror.commands.save = (cm) => observer.next(cm);
|
||||
})),
|
||||
rxjs.mergeMap((cm) => {
|
||||
|
|
@ -152,7 +152,7 @@ export default async function(render, { acl$ }) {
|
|||
|
||||
// feature5: save on exit
|
||||
effect(setup$.pipe(
|
||||
rxjs.tap((cm) => window.history.block = async(href) => {
|
||||
rxjs.tap((cm) => window.history.block = async() => {
|
||||
const block = qs(document.body, "component-breadcrumb").hasAttribute("indicator");
|
||||
if (block === false) return false;
|
||||
const userAction = await new Promise((done) => {
|
||||
|
|
@ -213,11 +213,13 @@ export function init() {
|
|||
|
||||
function loadMode(ext) {
|
||||
let mode = "text";
|
||||
let before = Promise.resolve();
|
||||
let before = Promise.resolve(null);
|
||||
|
||||
if (ext === "org" || ext === "org_archive") {
|
||||
mode = "orgmode";
|
||||
before = loadJS(import.meta.url, "../../lib/vendor/codemirror/addon/fold/xml-fold.js").then(() => loadJS(import.meta.url, "../../lib/vendor/codemirror/addon/edit/matchtags.js"));
|
||||
before = loadJS(import.meta.url, "../../lib/vendor/codemirror/addon/fold/xml-fold.js")
|
||||
.then(() => loadJS(import.meta.url, "../../lib/vendor/codemirror/addon/edit/matchtags.js"))
|
||||
.then(() => Promise.resolve(null));
|
||||
} else if (ext === "sh") mode = "shell";
|
||||
else if (ext === "py") mode = "python";
|
||||
else if (ext === "html" || ext === "htm") {
|
||||
|
|
@ -226,7 +228,7 @@ function loadMode(ext) {
|
|||
loadJS(import.meta.url, "../../lib/vendor/codemirror/mode/xml/xml.js"),
|
||||
loadJS(import.meta.url, "../../lib/vendor/codemirror/mode/javascript/javascript.js"),
|
||||
loadJS(import.meta.url, "../../lib/vendor/codemirror/mode/css/css.js"),
|
||||
]);
|
||||
]).then(() => Promise.resolve(null));
|
||||
} else if (ext === "css") mode = "css";
|
||||
else if (ext === "less" || ext === "scss" || ext === "sass") mode = "sass";
|
||||
else if (ext === "js" || ext === "json") mode = "javascript";
|
||||
|
|
@ -237,7 +239,7 @@ function loadMode(ext) {
|
|||
loadJS(import.meta.url, "../../lib/vendor/codemirror/mode/xml/xml.js"),
|
||||
loadJS(import.meta.url, "../../lib/vendor/codemirror/mode/javascript/javascript.js"),
|
||||
loadJS(import.meta.url, "../../lib/vendor/codemirror/mode/css/css.js"),
|
||||
]);
|
||||
]).then(() => Promise.resolve(null));
|
||||
} else if (ext === "elm") mode = "elm";
|
||||
else if (ext === "erl") mode = "erlang";
|
||||
else if (ext === "go") mode = "go";
|
||||
|
|
@ -248,14 +250,14 @@ function loadMode(ext) {
|
|||
loadJS(import.meta.url, "../../lib/vendor/codemirror/mode/gfm/gfm.js"),
|
||||
loadJS(import.meta.url, "../../lib/vendor/codemirror/mode/yaml/yaml.js"),
|
||||
loadJS(import.meta.url, "../../lib/vendor/codemirror/addon/mode/overlay.js"),
|
||||
]);
|
||||
]).then(() => Promise.resolve(null));
|
||||
} else if (ext === "pl" || ext === "pm") mode = "perl";
|
||||
else if (ext === "clj") mode = "clojure";
|
||||
else if (ext === "el" || ext === "lisp" || ext === "cl" ||
|
||||
ext === "emacs") mode = "commonlisp";
|
||||
else if (ext === "dockerfile") {
|
||||
mode = "dockerfile";
|
||||
before = loadJS(import.meta.url, "../../lib/vendor/codemirror/addon/mode/simple.js");
|
||||
before = loadJS(import.meta.url, "../../lib/vendor/codemirror/addon/mode/simple.js").then(() => Promise.resolve(null));
|
||||
} else if (ext === "R") mode = "r";
|
||||
else if (ext === "makefile") mode = "cmake";
|
||||
else if (ext === "rb") mode = "ruby";
|
||||
|
|
@ -275,7 +277,7 @@ function loadMode(ext) {
|
|||
|
||||
return before.then(() => loadJS(import.meta.url, `./application_editor/${mode}.js`, { type: "module" }))
|
||||
.catch(() => loadJS(import.meta.url, "./application_editor/text.js", { type: "module" }))
|
||||
.then((module) => Promise.resolve(mode));
|
||||
.then(() => Promise.resolve(mode));
|
||||
}
|
||||
|
||||
function loadKeybinding(editor) {
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ export default function(render) {
|
|||
),
|
||||
).pipe(
|
||||
rxjs.map((originalState) => {
|
||||
const smod = (key, value) => value || undefined;
|
||||
const smod = (_, value) => value || undefined;
|
||||
return JSON.stringify(formObjToJSON(originalState), smod) !== JSON.stringify(formState(), smod);
|
||||
}),
|
||||
rxjs.mergeMap(async(isSaveButtonVisible) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { createElement } from "../../lib/skeleton/index.js";
|
||||
import rxjs, { effect } from "../../lib/rx.js";
|
||||
import assert from "../../lib/assert.js";
|
||||
|
||||
export default function(render) {
|
||||
const $component = createElement(`
|
||||
|
|
@ -9,6 +10,6 @@ export default function(render) {
|
|||
|
||||
effect(rxjs.fromEvent(document, "keypress").pipe(
|
||||
rxjs.filter((e) => e.key === "i"),
|
||||
rxjs.tap(() => $component.parentElement.classList.toggle("open")),
|
||||
rxjs.tap(() => assert.type($component.parentElement, window.HTMLElement).classList.toggle("open")),
|
||||
));
|
||||
}
|
||||
|
|
|
|||
11
public/assets/pages/viewerpage/application_pdf.d.ts
vendored
Normal file
11
public/assets/pages/viewerpage/application_pdf.d.ts
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
interface Window {
|
||||
pdfjsLib: {
|
||||
getDocument: (url: string) => { promise: Promise<any> };
|
||||
GlobalWorkerOptions: {
|
||||
workerSrc: string;
|
||||
};
|
||||
// Add other properties and methods of pdfjsLib as needed
|
||||
};
|
||||
env?: string;
|
||||
chrome: object;
|
||||
}
|
||||
|
|
@ -4,9 +4,8 @@ import { animate, slideYIn } from "../../lib/animate.js";
|
|||
import { loadCSS, loadJS } from "../../helpers/loader.js";
|
||||
import { qs, qsa } from "../../lib/dom.js";
|
||||
import { settings_get, settings_put } from "../../lib/settings.js";
|
||||
import assert from "../../lib/assert.js";
|
||||
import { ApplicationError } from "../../lib/error.js";
|
||||
|
||||
import assert from "../../lib/assert.js";
|
||||
import Hls from "../../lib/vendor/hlsjs/hls.js";
|
||||
|
||||
import ctrlError from "../ctrl_error.js";
|
||||
|
|
@ -170,14 +169,14 @@ export default function(render, { mime }) {
|
|||
$video.appendChild($source);
|
||||
return [{ ...sources[i], type: "video/mp4" }];
|
||||
}
|
||||
hls.loadSource(sources[i].src, sources[i].type);
|
||||
hls.loadSource(sources[i].src);
|
||||
}
|
||||
hls.attachMedia($video);
|
||||
return sources;
|
||||
}),
|
||||
rxjs.mergeMap((sources) => rxjs.merge(
|
||||
rxjs.fromEvent($video, "loadeddata"),
|
||||
...[...qsa($page, "source")].map(($source) => rxjs.fromEvent($source, "error").pipe(rxjs.tap((err) => {
|
||||
...[...qsa($page, "source")].map(($source) => rxjs.fromEvent($source, "error").pipe(rxjs.tap(() => {
|
||||
throw new ApplicationError("NOT_SUPPORTED", JSON.stringify({ mime, sources }, null, 2));
|
||||
}))),
|
||||
)),
|
||||
|
|
@ -361,7 +360,7 @@ export default function(render, { mime }) {
|
|||
if ($video.buffered.length !== $container.children.length) {
|
||||
$container.innerHTML = "";
|
||||
const $fragment = document.createDocumentFragment();
|
||||
Array.apply(null, { length: $video.buffered.length })
|
||||
Array.from({ length: $video.buffered.length })
|
||||
.map(() => $fragment.appendChild(createElement(`
|
||||
<div className="progress-buffer" style=""></div>
|
||||
`)));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
export function formatTimecode(seconds) {
|
||||
return String(parseInt(seconds / 60)).padStart(2, "0") +
|
||||
return String(Math.floor(seconds / 60)).padStart(2, "0") +
|
||||
":" +
|
||||
String(parseInt(seconds % 60)).padStart(2, "0");
|
||||
String(Math.floor(seconds % 60)).padStart(2, "0");
|
||||
}
|
||||
|
||||
// TODO: abstract setVolume, setSeek and setStatus
|
||||
|
|
|
|||
|
|
@ -20,12 +20,13 @@ export default class ComponentMenubar extends window.HTMLElement {
|
|||
</div>
|
||||
`;
|
||||
if (new URLSearchParams(location.search).get("nav") === "false") {
|
||||
this.firstElementChild.classList.add("inherit-width");
|
||||
const $container = assert.type(this.firstElementChild, window.HTMLElement);
|
||||
$container.classList.add("inherit-width");
|
||||
}
|
||||
}
|
||||
|
||||
async connectedCallback() {
|
||||
const $title = this.querySelector(".titlebar");
|
||||
const $title = assert.type(this.querySelector(".titlebar"), window.HTMLElement);
|
||||
this.timeoutID = setTimeout(() => animate($title, {
|
||||
time: 250,
|
||||
keyframes: slideYIn(2),
|
||||
|
|
@ -38,7 +39,7 @@ export default class ComponentMenubar extends window.HTMLElement {
|
|||
}
|
||||
|
||||
render(buttons) {
|
||||
const $item = this.querySelector(".action-item");
|
||||
const $item = assert.type(this.querySelector(".action-item"), window.HTMLElement);
|
||||
for (let i=buttons.length-1; i>=0; i--) {
|
||||
$item.appendChild(buttons[i]);
|
||||
}
|
||||
|
|
|
|||
12
public/global.d.ts
vendored
Normal file
12
public/global.d.ts
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
interface Window {
|
||||
overrides: {
|
||||
[key: string]: any;
|
||||
"xdg-open"?: (mime: string) => void;
|
||||
};
|
||||
CONFIG: Config;
|
||||
}
|
||||
|
||||
interface Config {
|
||||
[key: string]: any;
|
||||
thumbnailer: string[];
|
||||
}
|
||||
|
|
@ -25,15 +25,16 @@
|
|||
"target": "es2022",
|
||||
"typeRoots": []
|
||||
},
|
||||
"include": ["assets/boot/*.js", "assets/pages/*.js"],
|
||||
"include": [
|
||||
"assets/boot/*.js",
|
||||
"assets/pages/*.js",
|
||||
"global.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"**/*.test.js",
|
||||
"assets/worker/sw_cache.js",
|
||||
"coverage",
|
||||
"vite.config.js",
|
||||
"jest.setup.js",
|
||||
"assets/lib/vendor/**",
|
||||
"assets/lib/vendor/hlsjs/hls.js",
|
||||
"assets/lib/vendor/three/*.js"
|
||||
"jest.setup.js"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue