From 9a45dc000a7b021cc4b4e80d0358cc01769cd49a Mon Sep 17 00:00:00 2001 From: MickaelK Date: Fri, 19 Jul 2024 01:21:22 +1000 Subject: [PATCH] chore (tsc): tsc checks --- public/assets/components/breadcrumb.js | 14 ++++------ .../components/decorator_shell_filemanager.js | 7 +++-- public/assets/components/dropdown.js | 5 ++-- public/assets/components/fab.js | 3 +- public/assets/components/modal.js | 6 ++-- public/assets/components/sidebar.js | 2 +- public/assets/helpers/loader.d.ts | 10 ++++--- public/assets/helpers/loader.js | 4 +-- public/assets/lib/animate.d.ts | 6 ++++ public/assets/lib/assert.js | 9 +++--- public/assets/lib/chromecast.js | 2 +- public/assets/lib/dom.d.ts | 4 +-- public/assets/lib/random.d.ts | 2 ++ public/assets/lib/rx.d.ts | 20 ++++++++++--- public/assets/lib/skeleton/index.d.ts | 2 ++ public/assets/lib/store.js | 4 +-- public/assets/lib/vendor/hlsjs/hls.js | 1 + public/assets/lib/vendor/three/3DMLoader.js | 1 + public/assets/lib/vendor/three/EXRLoader.js | 1 + public/assets/lib/vendor/three/FBXLoader.js | 1 + public/assets/lib/vendor/three/GLTFLoader.js | 1 + public/assets/lib/vendor/three/OBJLoader.js | 1 + .../assets/lib/vendor/three/OrbitControls.js | 1 + public/assets/lib/vendor/three/STLLoader.js | 1 + .../lib/vendor/three/curves/NURBSCurve.js | 1 + .../lib/vendor/three/curves/NURBSUtils.js | 1 + .../lib/vendor/three/libs/fflate.module.js | 1 + .../assets/lib/vendor/three/three.module.js | 1 + .../vendor/three/utils/BufferGeometryUtils.js | 1 + public/assets/locales/index.js | 4 +-- public/assets/pages/connectpage/ctrl_form.js | 4 +-- public/assets/pages/ctrl_sharepage.js | 6 ++-- public/assets/pages/ctrl_viewerpage.js | 2 +- public/assets/pages/filespage/cache.js | 16 +++++------ .../assets/pages/filespage/ctrl_filesystem.js | 12 +++++--- public/assets/pages/filespage/ctrl_newitem.js | 2 +- public/assets/pages/filespage/ctrl_submenu.js | 14 +++++----- public/assets/pages/filespage/ctrl_upload.css | 2 +- public/assets/pages/filespage/ctrl_upload.js | 28 +++++++++---------- public/assets/pages/filespage/modal_delete.js | 4 +-- public/assets/pages/filespage/modal_rename.js | 2 +- public/assets/pages/filespage/modal_share.js | 19 +++++++------ public/assets/pages/filespage/model_files.js | 4 +-- .../pages/filespage/model_virtual_layer.js | 9 ++---- public/assets/pages/filespage/thing.js | 5 ++-- .../pages/viewerpage/application_audio.d.ts | 5 ++++ .../pages/viewerpage/application_audio.js | 2 +- .../viewerpage/application_downloader.js | 2 +- .../pages/viewerpage/application_ebook.d.ts | 5 ++++ .../pages/viewerpage/application_ebook.js | 5 ++-- .../pages/viewerpage/application_editor.d.ts | 9 ++++++ .../pages/viewerpage/application_editor.js | 22 ++++++++------- .../pages/viewerpage/application_form.js | 2 +- .../viewerpage/application_image_metadata.js | 3 +- .../pages/viewerpage/application_pdf.d.ts | 11 ++++++++ .../pages/viewerpage/application_video.js | 9 +++--- .../assets/pages/viewerpage/common_player.js | 4 +-- .../pages/viewerpage/component_menubar.js | 7 +++-- public/global.d.ts | 12 ++++++++ public/tsconfig.json | 11 ++++---- 60 files changed, 220 insertions(+), 135 deletions(-) create mode 100644 public/assets/pages/viewerpage/application_audio.d.ts create mode 100644 public/assets/pages/viewerpage/application_ebook.d.ts create mode 100644 public/assets/pages/viewerpage/application_editor.d.ts create mode 100644 public/assets/pages/viewerpage/application_pdf.d.ts create mode 100644 public/global.d.ts diff --git a/public/assets/components/breadcrumb.js b/public/assets/components/breadcrumb.js index 31403042..d390523b 100644 --- a/public/assets/components/breadcrumb.js +++ b/public/assets/components/breadcrumb.js @@ -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 { + 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 decodeURIComponent(pathname.split("/").filter((chunk, i) => i !== 1).join("/")); + const urlToPath = (pathname = "") => decodeURIComponent(pathname.split("/").filter((_, i) => i !== 1).join("/")); const $page = createElement(`
@@ -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(); diff --git a/public/assets/components/dropdown.js b/public/assets/components/dropdown.js index 5e384987..83d3bed2 100644 --- a/public/assets/components/dropdown.js +++ b/public/assets/components/dropdown.js @@ -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), }); diff --git a/public/assets/components/fab.js b/public/assets/components/fab.js index f9e4f14c..731d79c3 100644 --- a/public/assets/components/fab.js +++ b/public/assets/components/fab.js @@ -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); } } diff --git a/public/assets/components/modal.js b/public/assets/components/modal.js index 4eedcd5c..5b40e7ec 100644 --- a/public/assets/components/modal.js +++ b/public/assets/components/modal.js @@ -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) { diff --git a/public/assets/components/sidebar.js b/public/assets/components/sidebar.js index 4ce5c771..098f6e7e 100644 --- a/public/assets/components/sidebar.js +++ b/public/assets/components/sidebar.js @@ -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(` diff --git a/public/assets/helpers/loader.d.ts b/public/assets/helpers/loader.d.ts index afeea96e..63768217 100644 --- a/public/assets/helpers/loader.d.ts +++ b/public/assets/helpers/loader.d.ts @@ -1,9 +1,11 @@ export function loadScript(url: string): Promise; -export function CSS(baseURL: string, ...arrayOfFilenames: string[]): Promise; - -export function loadSingleCSS(baseURL: string, filename: string): Promise; - export function loadJS(baseURL: string, path: string, opts?: object): Promise; +export function loadCSS(baseURL: string, ...arrayOfFilenames: string[]): Promise; + +export function loadCSSInline(baseURL: string, filename: string): Promise; + +export function CSS(baseURL: string, ...arrayOfFilenames: string[]): Promise; + export function init(): Promise; \ No newline at end of file diff --git a/public/assets/helpers/loader.js b/public/assets/helpers/loader.js index ab811ecb..bf9a7a8a 100644 --- a/public/assets/helpers/loader.js +++ b/public/assets/helpers/loader.js @@ -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(); }); } diff --git a/public/assets/lib/animate.d.ts b/public/assets/lib/animate.d.ts index e0796906..4ec6de94 100644 --- a/public/assets/lib/animate.d.ts +++ b/public/assets/lib/animate.d.ts @@ -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; export function slideXIn(dist: number): AnimationFrames[]; diff --git a/public/assets/lib/assert.js b/public/assets/lib/assert.js index aa13e955..5727dd44 100644 --- a/public/assets/lib/assert.js +++ b/public/assets/lib/assert.js @@ -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}`); } } diff --git a/public/assets/lib/chromecast.js b/public/assets/lib/chromecast.js index 3847e488..35b57d48 100644 --- a/public/assets/lib/chromecast.js +++ b/public/assets/lib/chromecast.js @@ -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 diff --git a/public/assets/lib/dom.d.ts b/public/assets/lib/dom.d.ts index b8249709..c0845b11 100644 --- a/public/assets/lib/dom.d.ts +++ b/public/assets/lib/dom.d.ts @@ -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; diff --git a/public/assets/lib/random.d.ts b/public/assets/lib/random.d.ts index f6ca8fd9..c29afeb8 100644 --- a/public/assets/lib/random.d.ts +++ b/public/assets/lib/random.d.ts @@ -1 +1,3 @@ export function gid(prefix: string): string; + +export function randomString(size: number): string; diff --git a/public/assets/lib/rx.d.ts b/public/assets/lib/rx.d.ts index 027ce8a4..7ae72561 100644 --- a/public/assets/lib/rx.d.ts +++ b/public/assets/lib/rx.d.ts @@ -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; \ No newline at end of file diff --git a/public/assets/lib/skeleton/index.d.ts b/public/assets/lib/skeleton/index.d.ts index 596e5e39..ea4a64ee 100644 --- a/public/assets/lib/skeleton/index.d.ts +++ b/public/assets/lib/skeleton/index.d.ts @@ -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 diff --git a/public/assets/lib/store.js b/public/assets/lib/store.js index c5050188..61fc9247 100644 --- a/public/assets/lib/store.js +++ b/public/assets/lib/store.js @@ -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]; diff --git a/public/assets/lib/vendor/hlsjs/hls.js b/public/assets/lib/vendor/hlsjs/hls.js index 427e8b88..b4e9fcfb 100644 --- a/public/assets/lib/vendor/hlsjs/hls.js +++ b/public/assets/lib/vendor/hlsjs/hls.js @@ -1,3 +1,4 @@ +// @ts-nocheck function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } diff --git a/public/assets/lib/vendor/three/3DMLoader.js b/public/assets/lib/vendor/three/3DMLoader.js index fe08015c..2c7cd4c2 100644 --- a/public/assets/lib/vendor/three/3DMLoader.js +++ b/public/assets/lib/vendor/three/3DMLoader.js @@ -1,3 +1,4 @@ +// @ts-nocheck import { BufferGeometryLoader, FileLoader, diff --git a/public/assets/lib/vendor/three/EXRLoader.js b/public/assets/lib/vendor/three/EXRLoader.js index 2f6721b0..deb77553 100644 --- a/public/assets/lib/vendor/three/EXRLoader.js +++ b/public/assets/lib/vendor/three/EXRLoader.js @@ -1,3 +1,4 @@ +// @ts-nocheck import { DataTextureLoader, DataUtils, diff --git a/public/assets/lib/vendor/three/FBXLoader.js b/public/assets/lib/vendor/three/FBXLoader.js index e51a2c94..4436dac5 100644 --- a/public/assets/lib/vendor/three/FBXLoader.js +++ b/public/assets/lib/vendor/three/FBXLoader.js @@ -1,3 +1,4 @@ +// @ts-nocheck import { AmbientLight, AnimationClip, diff --git a/public/assets/lib/vendor/three/GLTFLoader.js b/public/assets/lib/vendor/three/GLTFLoader.js index 17c20af7..68c38ccc 100644 --- a/public/assets/lib/vendor/three/GLTFLoader.js +++ b/public/assets/lib/vendor/three/GLTFLoader.js @@ -1,3 +1,4 @@ +// @ts-nocheck import { AnimationClip, Bone, diff --git a/public/assets/lib/vendor/three/OBJLoader.js b/public/assets/lib/vendor/three/OBJLoader.js index 47587fda..dd64ad94 100644 --- a/public/assets/lib/vendor/three/OBJLoader.js +++ b/public/assets/lib/vendor/three/OBJLoader.js @@ -1,3 +1,4 @@ +// @ts-nocheck import { BufferGeometry, FileLoader, diff --git a/public/assets/lib/vendor/three/OrbitControls.js b/public/assets/lib/vendor/three/OrbitControls.js index bb9ed676..384751f6 100644 --- a/public/assets/lib/vendor/three/OrbitControls.js +++ b/public/assets/lib/vendor/three/OrbitControls.js @@ -1,3 +1,4 @@ +// @ts-nocheck import { EventDispatcher, MOUSE, diff --git a/public/assets/lib/vendor/three/STLLoader.js b/public/assets/lib/vendor/three/STLLoader.js index d86e9802..21c57eea 100644 --- a/public/assets/lib/vendor/three/STLLoader.js +++ b/public/assets/lib/vendor/three/STLLoader.js @@ -1,3 +1,4 @@ +// @ts-nocheck import { BufferAttribute, BufferGeometry, diff --git a/public/assets/lib/vendor/three/curves/NURBSCurve.js b/public/assets/lib/vendor/three/curves/NURBSCurve.js index de6c75ec..237a76cd 100644 --- a/public/assets/lib/vendor/three/curves/NURBSCurve.js +++ b/public/assets/lib/vendor/three/curves/NURBSCurve.js @@ -1,3 +1,4 @@ +// @ts-nocheck import { Curve, Vector3, diff --git a/public/assets/lib/vendor/three/curves/NURBSUtils.js b/public/assets/lib/vendor/three/curves/NURBSUtils.js index 372d83d5..1696fda4 100644 --- a/public/assets/lib/vendor/three/curves/NURBSUtils.js +++ b/public/assets/lib/vendor/three/curves/NURBSUtils.js @@ -1,3 +1,4 @@ +// @ts-nocheck import { Vector3, Vector4 diff --git a/public/assets/lib/vendor/three/libs/fflate.module.js b/public/assets/lib/vendor/three/libs/fflate.module.js index 808000a5..ca63a2da 100644 --- a/public/assets/lib/vendor/three/libs/fflate.module.js +++ b/public/assets/lib/vendor/three/libs/fflate.module.js @@ -1,3 +1,4 @@ +// @ts-nocheck /*! fflate - fast JavaScript compression/decompression diff --git a/public/assets/lib/vendor/three/three.module.js b/public/assets/lib/vendor/three/three.module.js index 0bcc7a28..59ca0014 100644 --- a/public/assets/lib/vendor/three/three.module.js +++ b/public/assets/lib/vendor/three/three.module.js @@ -1,3 +1,4 @@ +// @ts-nocheck /** * @license * Copyright 2010-2023 Three.js Authors diff --git a/public/assets/lib/vendor/three/utils/BufferGeometryUtils.js b/public/assets/lib/vendor/three/utils/BufferGeometryUtils.js index f3450242..8cf87421 100644 --- a/public/assets/lib/vendor/three/utils/BufferGeometryUtils.js +++ b/public/assets/lib/vendor/three/utils/BufferGeometryUtils.js @@ -1,3 +1,4 @@ +// @ts-nocheck import { BufferAttribute, BufferGeometry, diff --git a/public/assets/locales/index.js b/public/assets/locales/index.js index 28f0b6a1..a1059643 100644 --- a/public/assets/locales/index.js +++ b/public/assets/locales/index.js @@ -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; } diff --git a/public/assets/pages/connectpage/ctrl_form.js b/public/assets/pages/connectpage/ctrl_form.js index d4c0f078..56a24411 100644 --- a/public/assets/pages/connectpage/ctrl_form.js +++ b/public/assets/pages/connectpage/ctrl_form.js @@ -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(``))), 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 diff --git a/public/assets/pages/ctrl_sharepage.js b/public/assets/pages/ctrl_sharepage.js index 37165e85..ef9caf4f 100644 --- a/public/assets/pages/ctrl_sharepage.js +++ b/public/assets/pages/ctrl_sharepage.js @@ -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": diff --git a/public/assets/pages/ctrl_viewerpage.js b/public/assets/pages/ctrl_viewerpage.js index 38bb9876..95314ffb 100644 --- a/public/assets/pages/ctrl_viewerpage.js +++ b/public/assets/pages/ctrl_viewerpage.js @@ -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"; diff --git a/public/assets/pages/filespage/cache.js b/public/assets/pages/filespage/cache.js index 102e2512..17cf5448 100644 --- a/public/assets/pages/filespage/cache.js +++ b/public/assets/pages/filespage/cache.js @@ -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; }); } diff --git a/public/assets/pages/filespage/ctrl_filesystem.js b/public/assets/pages/filespage/ctrl_filesystem.js index 8b7e861c..b2b83859 100644 --- a/public/assets/pages/filespage/ctrl_filesystem.js +++ b/public/assets/pages/filespage/ctrl_filesystem.js @@ -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) {

${t("There is nothing here")}

`); - animate(render($page), { keyframes: slideYIn(5) }); + animate(render($page), { time: 250, keyframes: slideYIn(5) }); } export function init() { diff --git a/public/assets/pages/filespage/ctrl_newitem.js b/public/assets/pages/filespage/ctrl_newitem.js index b70776a2..83496bd6 100644 --- a/public/assets/pages/filespage/ctrl_newitem.js +++ b/public/assets/pages/filespage/ctrl_newitem.js @@ -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 = ""; diff --git a/public/assets/pages/filespage/ctrl_submenu.js b/public/assets/pages/filespage/ctrl_submenu.js index 883c2015..a305ff75 100644 --- a/public/assets/pages/filespage/ctrl_submenu.js +++ b/public/assets/pages/filespage/ctrl_submenu.js @@ -169,7 +169,7 @@ function componentLeft(render, { $scroll }) { )); effect(getSelection$().pipe( - rxjs.filter((selections) => lengthSelection() > 1), + rxjs.filter(() => lengthSelection() > 1), rxjs.map(() => render(createFragment(` `))), - 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))), )), diff --git a/public/assets/pages/filespage/ctrl_upload.css b/public/assets/pages/filespage/ctrl_upload.css index 1c077027..8a64a8c8 100644 --- a/public/assets/pages/filespage/ctrl_upload.css +++ b/public/assets/pages/filespage/ctrl_upload.css @@ -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 { diff --git a/public/assets/pages/filespage/ctrl_upload.js b/public/assets/pages/filespage/ctrl_upload.js index 599e9bdf..7bf2a4c3 100644 --- a/public/assets/pages/filespage/ctrl_upload.js +++ b/public/assets/pages/filespage/ctrl_upload.js @@ -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(`
`); - 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))); diff --git a/public/assets/pages/filespage/modal_delete.js b/public/assets/pages/filespage/modal_delete.js index 81fa0246..5e0f7364 100644 --- a/public/assets/pages/filespage/modal_delete.js +++ b/public/assets/pages/filespage/modal_delete.js @@ -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); }); } diff --git a/public/assets/pages/filespage/modal_rename.js b/public/assets/pages/filespage/modal_rename.js index 9a542b70..8786a0bc 100644 --- a/public/assets/pages/filespage/modal_rename.js +++ b/public/assets/pages/filespage/modal_rename.js @@ -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) { diff --git a/public/assets/pages/filespage/modal_share.js b/public/assets/pages/filespage/modal_share.js index e2a7e6d0..26441e9b 100644 --- a/public/assets/pages/filespage/modal_share.js +++ b/public/assets/pages/filespage/modal_share.js @@ -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("
"), - renderLeaf: ({ format, label, type }) => { + renderLeaf: ({ label, type }) => { if (type !== "enable") return createElement(""); 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,10 +281,11 @@ 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]) => { - if (value && key.slice(-7) !== "_enable") acc[key] = value; - return acc; - }, { id }); + 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 }); $copy.setAttribute("src", IMAGE.LOADING); const link = location.origin + forwardURLParams(toHref(`/s/${id}`), ["share"]); await save(body); diff --git a/public/assets/pages/filespage/model_files.js b/public/assets/pages/filespage/model_files.js index ed485c27..ba4e6323 100644 --- a/public/assets/pages/filespage/model_files.js +++ b/public/assets/pages/filespage/model_files.js @@ -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( diff --git a/public/assets/pages/filespage/model_virtual_layer.js b/public/assets/pages/filespage/model_virtual_layer.js index 6479a680..60b2a54e 100644 --- a/public/assets/pages/filespage/model_virtual_layer.js +++ b/public/assets/pages/filespage/model_virtual_layer.js @@ -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), diff --git a/public/assets/pages/filespage/thing.js b/public/assets/pages/filespage/thing.js index e4b61287..ce569b0c 100644 --- a/public/assets/pages/filespage/thing.js +++ b/public/assets/pages/filespage/thing.js @@ -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. diff --git a/public/assets/pages/viewerpage/application_audio.d.ts b/public/assets/pages/viewerpage/application_audio.d.ts new file mode 100644 index 00000000..1a2161ff --- /dev/null +++ b/public/assets/pages/viewerpage/application_audio.d.ts @@ -0,0 +1,5 @@ +interface Window { + WaveSurfer: { + create: (options: any) => any; + }; +} \ No newline at end of file diff --git a/public/assets/pages/viewerpage/application_audio.js b/public/assets/pages/viewerpage/application_audio.js index 90e4387a..572bccd3 100644 --- a/public/assets/pages/viewerpage/application_audio.js +++ b/public/assets/pages/viewerpage/application_audio.js @@ -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(`
diff --git a/public/assets/pages/viewerpage/application_downloader.js b/public/assets/pages/viewerpage/application_downloader.js index a1e687fd..6918d6e0 100644 --- a/public/assets/pages/viewerpage/application_downloader.js +++ b/public/assets/pages/viewerpage/application_downloader.js @@ -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)), diff --git a/public/assets/pages/viewerpage/application_ebook.d.ts b/public/assets/pages/viewerpage/application_ebook.d.ts new file mode 100644 index 00000000..3a7f695f --- /dev/null +++ b/public/assets/pages/viewerpage/application_ebook.d.ts @@ -0,0 +1,5 @@ +interface Window { + ePub: { + Book: new (options: any) => any; + }; +} \ No newline at end of file diff --git a/public/assets/pages/viewerpage/application_ebook.js b/public/assets/pages/viewerpage/application_ebook.js index d2fd8e6c..f665164d 100644 --- a/public/assets/pages/viewerpage/application_ebook.js +++ b/public/assets/pages/viewerpage/application_ebook.js @@ -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) { diff --git a/public/assets/pages/viewerpage/application_editor.d.ts b/public/assets/pages/viewerpage/application_editor.d.ts new file mode 100644 index 00000000..183a146d --- /dev/null +++ b/public/assets/pages/viewerpage/application_editor.d.ts @@ -0,0 +1,9 @@ +interface Window { + CodeMirror: { + (element: HTMLElement, options: any): any; + __mode: string; + commands: { + save: (editor: any) => void; + }; + }; +} \ No newline at end of file diff --git a/public/assets/pages/viewerpage/application_editor.js b/public/assets/pages/viewerpage/application_editor.js index e8f647e6..e9a9ca2f 100644 --- a/public/assets/pages/viewerpage/application_editor.js +++ b/public/assets/pages/viewerpage/application_editor.js @@ -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) { diff --git a/public/assets/pages/viewerpage/application_form.js b/public/assets/pages/viewerpage/application_form.js index be021e81..3235a785 100644 --- a/public/assets/pages/viewerpage/application_form.js +++ b/public/assets/pages/viewerpage/application_form.js @@ -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) => { diff --git a/public/assets/pages/viewerpage/application_image_metadata.js b/public/assets/pages/viewerpage/application_image_metadata.js index 5e11ba39..bf853003 100644 --- a/public/assets/pages/viewerpage/application_image_metadata.js +++ b/public/assets/pages/viewerpage/application_image_metadata.js @@ -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")), )); } diff --git a/public/assets/pages/viewerpage/application_pdf.d.ts b/public/assets/pages/viewerpage/application_pdf.d.ts new file mode 100644 index 00000000..f5249404 --- /dev/null +++ b/public/assets/pages/viewerpage/application_pdf.d.ts @@ -0,0 +1,11 @@ +interface Window { + pdfjsLib: { + getDocument: (url: string) => { promise: Promise }; + GlobalWorkerOptions: { + workerSrc: string; + }; + // Add other properties and methods of pdfjsLib as needed + }; + env?: string; + chrome: object; +} \ No newline at end of file diff --git a/public/assets/pages/viewerpage/application_video.js b/public/assets/pages/viewerpage/application_video.js index 8a97124b..32339967 100644 --- a/public/assets/pages/viewerpage/application_video.js +++ b/public/assets/pages/viewerpage/application_video.js @@ -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(`
`))); diff --git a/public/assets/pages/viewerpage/common_player.js b/public/assets/pages/viewerpage/common_player.js index ce476f95..ff970fcb 100644 --- a/public/assets/pages/viewerpage/common_player.js +++ b/public/assets/pages/viewerpage/common_player.js @@ -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 diff --git a/public/assets/pages/viewerpage/component_menubar.js b/public/assets/pages/viewerpage/component_menubar.js index 6b87a8f5..57057143 100644 --- a/public/assets/pages/viewerpage/component_menubar.js +++ b/public/assets/pages/viewerpage/component_menubar.js @@ -20,12 +20,13 @@ export default class ComponentMenubar extends window.HTMLElement {
`; 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]); } diff --git a/public/global.d.ts b/public/global.d.ts new file mode 100644 index 00000000..ebfbba74 --- /dev/null +++ b/public/global.d.ts @@ -0,0 +1,12 @@ +interface Window { + overrides: { + [key: string]: any; + "xdg-open"?: (mime: string) => void; + }; + CONFIG: Config; +} + +interface Config { + [key: string]: any; + thumbnailer: string[]; +} \ No newline at end of file diff --git a/public/tsconfig.json b/public/tsconfig.json index e7ebecf2..2f4b9354 100644 --- a/public/tsconfig.json +++ b/public/tsconfig.json @@ -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" ] }