mirror of
				https://github.com/mickael-kerjean/filestash.git
				synced 2025-11-04 13:35:46 +08:00 
			
		
		
		
	chore (rewrite): get config at page init
This commit is contained in:
		@ -3,27 +3,27 @@ import { toHref } from "../lib/skeleton/router.js";
 | 
				
			|||||||
// import { setup_cache } from "../helpers/cache.js";
 | 
					// import { setup_cache } from "../helpers/cache.js";
 | 
				
			||||||
import { init as setup_loader, loadJS } from "../helpers/loader.js";
 | 
					import { init as setup_loader, loadJS } from "../helpers/loader.js";
 | 
				
			||||||
import { init as setup_translation } from "../locales/index.js";
 | 
					import { init as setup_translation } from "../locales/index.js";
 | 
				
			||||||
 | 
					import { init as setup_config } from "../model/config.js";
 | 
				
			||||||
 | 
					import { init as setup_chromecast } from "../model/chromecast.js";
 | 
				
			||||||
import { report } from "../helpers/log.js";
 | 
					import { report } from "../helpers/log.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default async function main() {
 | 
					export default async function main() {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
        let config = {};
 | 
					 | 
				
			||||||
        // await Config.refresh()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await Promise.all([ // procedure with no outside dependencies
 | 
					        await Promise.all([ // procedure with no outside dependencies
 | 
				
			||||||
 | 
					            setup_config(),
 | 
				
			||||||
            setup_translation(),
 | 
					            setup_translation(),
 | 
				
			||||||
            setup_xdg_open(),
 | 
					            setup_xdg_open(),
 | 
				
			||||||
            // setup_cache(), // TODO: dependency on session
 | 
					            // setup_cache(), // TODO: dependency on session
 | 
				
			||||||
            setup_device(),
 | 
					            setup_device(),
 | 
				
			||||||
            // setup_sw(), // TODO
 | 
					            setup_sw(),
 | 
				
			||||||
            setup_blue_death_screen(),
 | 
					            setup_blue_death_screen(),
 | 
				
			||||||
            setup_loader(),
 | 
					            setup_loader(),
 | 
				
			||||||
            setup_history(),
 | 
					            setup_history(),
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await Promise.all([ // procedure with dependency on config
 | 
					        await Promise.all([ // procedure with dependency on config
 | 
				
			||||||
            // setup_chromecast() // TODO
 | 
					            setup_chromecast(),
 | 
				
			||||||
            setup_base(config),
 | 
					            setup_title(),
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        window.dispatchEvent(new window.Event("pagechange"));
 | 
					        window.dispatchEvent(new window.Event("pagechange"));
 | 
				
			||||||
@ -72,30 +72,23 @@ async function setup_device() {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function setup_base(config) {
 | 
					async function setup_sw() {
 | 
				
			||||||
    // TODO: base as config in admin
 | 
					    if (!("serviceWorker" in window.navigator)) return;
 | 
				
			||||||
    const $meta = document.createElement("base");
 | 
					
 | 
				
			||||||
    $meta.setAttribute("href", location.origin);
 | 
					    if (window.navigator.userAgent.indexOf("Mozilla/") !== -1 &&
 | 
				
			||||||
    document.head.appendChild($meta);
 | 
					        window.navigator.userAgent.indexOf("Firefox/") !== -1 &&
 | 
				
			||||||
 | 
					        window.navigator.userAgent.indexOf("Gecko/") !== -1) {
 | 
				
			||||||
 | 
					        // Firefox was acting weird with service worker so we disabled it
 | 
				
			||||||
 | 
					        // see: https://github.com/mickael-kerjean/filestash/issues/255
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        // await window.navigator.serviceWorker.register("/sw_cache.js");
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					        report("ServiceWorker registration failed", err);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// async function setup_sw() {
 | 
					 | 
				
			||||||
//     if (!("serviceWorker" in window.navigator)) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//     if (window.navigator.userAgent.indexOf("Mozilla/") !== -1 &&
 | 
					 | 
				
			||||||
//         window.navigator.userAgent.indexOf("Firefox/") !== -1 &&
 | 
					 | 
				
			||||||
//         window.navigator.userAgent.indexOf("Gecko/") !== -1) {
 | 
					 | 
				
			||||||
//         // Firefox was acting weird with service worker so we disabled it
 | 
					 | 
				
			||||||
//         // see: https://github.com/mickael-kerjean/filestash/issues/255
 | 
					 | 
				
			||||||
//         return;
 | 
					 | 
				
			||||||
//     }
 | 
					 | 
				
			||||||
//     try {
 | 
					 | 
				
			||||||
//         await window.navigator.serviceWorker.register("/sw_cache.js");
 | 
					 | 
				
			||||||
//     } catch (err) {
 | 
					 | 
				
			||||||
//         report("ServiceWorker registration failed", err);
 | 
					 | 
				
			||||||
//     }
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function setup_blue_death_screen() {
 | 
					async function setup_blue_death_screen() {
 | 
				
			||||||
    window.onerror = function(msg, url, lineNo, colNo, error) {
 | 
					    window.onerror = function(msg, url, lineNo, colNo, error) {
 | 
				
			||||||
        report(msg, error, url, lineNo, colNo);
 | 
					        report(msg, error, url, lineNo, colNo);
 | 
				
			||||||
@ -117,3 +110,7 @@ async function setup_blue_death_screen() {
 | 
				
			|||||||
async function setup_history() {
 | 
					async function setup_history() {
 | 
				
			||||||
    window.history.replaceState({}, "");
 | 
					    window.history.replaceState({}, "");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async function setup_title() {
 | 
				
			||||||
 | 
					    document.title = CONFIG.name || "Filestash";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -72,7 +72,7 @@ class ComponentBreadcrumb extends window.HTMLElement {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // STEP2: setup the actual content
 | 
					        // STEP2: setup the actual content
 | 
				
			||||||
        this.querySelector(`[data-bind="path"]`).innerHTML = pathChunks.map((chunk, idx) => {
 | 
					        this.querySelector(`[data-bind="path"]`).innerHTML = pathChunks.map((chunk, idx) => {
 | 
				
			||||||
            const label = idx === 0 ? "Filestash" : chunk;
 | 
					            const label = idx === 0 ? (window.CONFIG.name || "Filestash") : chunk;
 | 
				
			||||||
            const link = pathChunks.slice(0, idx + 1).join("/") + "/";
 | 
					            const link = pathChunks.slice(0, idx + 1).join("/") + "/";
 | 
				
			||||||
            const limitSize = (word, highlight = false) => {
 | 
					            const limitSize = (word, highlight = false) => {
 | 
				
			||||||
                if (highlight === true && word.length > 30) {
 | 
					                if (highlight === true && word.length > 30) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										81
									
								
								public/assets/model/chromecast.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								public/assets/model/chromecast.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
				
			|||||||
 | 
					export async function init() {
 | 
				
			||||||
 | 
					    if (!CONFIG.enable_chromecast) {
 | 
				
			||||||
 | 
					        return Promise.resolve();
 | 
				
			||||||
 | 
					    } else if (!("chrome" in window)) {
 | 
				
			||||||
 | 
					        return Promise.resolve();
 | 
				
			||||||
 | 
						} else if (location.hostname === "localhost" || location.hostname === "127.0.0.1") {
 | 
				
			||||||
 | 
					        return Promise.resolve();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // return Chromecast.init();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// import { Session } from "./session";
 | 
				
			||||||
 | 
					// import { currentShare, objectGet } from "../helpers/";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// class ChromecastManager {
 | 
				
			||||||
 | 
					//     init() {
 | 
				
			||||||
 | 
					//         return new Promise((done) => {
 | 
				
			||||||
 | 
					//             const script = document.createElement("script");
 | 
				
			||||||
 | 
					//             script.src = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1";
 | 
				
			||||||
 | 
					//             script.onerror = () => done()
 | 
				
			||||||
 | 
					//             window["__onGCastApiAvailable"] = function(isAvailable) {
 | 
				
			||||||
 | 
					//                 if (isAvailable) cast.framework.CastContext.getInstance().setOptions({
 | 
				
			||||||
 | 
					//                     receiverApplicationId: chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID,
 | 
				
			||||||
 | 
					//                     autoJoinPolicy: chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED,
 | 
				
			||||||
 | 
					//                 });
 | 
				
			||||||
 | 
					//                 done();
 | 
				
			||||||
 | 
					//             };
 | 
				
			||||||
 | 
					//             document.head.appendChild(script)
 | 
				
			||||||
 | 
					//         });
 | 
				
			||||||
 | 
					//     }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//     origin() {
 | 
				
			||||||
 | 
					//         return location.origin;
 | 
				
			||||||
 | 
					//     };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//     createLink(apiPath) {
 | 
				
			||||||
 | 
					//         const shareID = currentShare();
 | 
				
			||||||
 | 
					//         if (shareID) {
 | 
				
			||||||
 | 
					//             const target = new URL(this.origin() + apiPath);
 | 
				
			||||||
 | 
					//             target.searchParams.append("share", shareID);
 | 
				
			||||||
 | 
					//             return target.toString();
 | 
				
			||||||
 | 
					//         }
 | 
				
			||||||
 | 
					//         const target = new URL(this.origin() + apiPath)
 | 
				
			||||||
 | 
					//         return target.toString();
 | 
				
			||||||
 | 
					//     }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//     createRequest(mediaInfo) {
 | 
				
			||||||
 | 
					//         let prior = Promise.resolve();
 | 
				
			||||||
 | 
					//         if (!Session.authorization) prior = Session.currentUser();
 | 
				
			||||||
 | 
					//         return prior.then(() => {
 | 
				
			||||||
 | 
					//             if (!Session.authorization) throw new Error("Invalid account");
 | 
				
			||||||
 | 
					//             // TODO: it would be much much nicer to set the authorization from an HTTP header
 | 
				
			||||||
 | 
					//             // but this would require to create a custom web receiver app, setup accounts on
 | 
				
			||||||
 | 
					//             // google, etc,... Until that happens, we're setting the authorization within the
 | 
				
			||||||
 | 
					//             // url. Once we have that app, the authorisation will come from a customData field
 | 
				
			||||||
 | 
					//             // of a chrome.cast.media.LoadRequest
 | 
				
			||||||
 | 
					//             const target = new URL(mediaInfo.contentId);
 | 
				
			||||||
 | 
					//             target.searchParams.append("authorization", Session.authorization);
 | 
				
			||||||
 | 
					//             mediaInfo.contentId = target.toString();
 | 
				
			||||||
 | 
					//             return new chrome.cast.media.LoadRequest(mediaInfo);
 | 
				
			||||||
 | 
					//         });
 | 
				
			||||||
 | 
					//     }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//     context() {
 | 
				
			||||||
 | 
					//         if (!objectGet(window.chrome, ["cast", "isAvailable"])) {
 | 
				
			||||||
 | 
					//             return;
 | 
				
			||||||
 | 
					//         }
 | 
				
			||||||
 | 
					//         return cast.framework.CastContext.getInstance();
 | 
				
			||||||
 | 
					//     }
 | 
				
			||||||
 | 
					//     session() {
 | 
				
			||||||
 | 
					//         const context = this.context();
 | 
				
			||||||
 | 
					//         if (!context) return;
 | 
				
			||||||
 | 
					//         return context.getCurrentSession();
 | 
				
			||||||
 | 
					//     }
 | 
				
			||||||
 | 
					//     media() {
 | 
				
			||||||
 | 
					//         const session = this.session();
 | 
				
			||||||
 | 
					//         if (!session) return;
 | 
				
			||||||
 | 
					//         return session.getMediaSession();
 | 
				
			||||||
 | 
					//     }
 | 
				
			||||||
 | 
					// }
 | 
				
			||||||
 | 
					// export const Chromecast = new ChromecastManager();
 | 
				
			||||||
@ -9,6 +9,7 @@ const config$ = ajax({
 | 
				
			|||||||
    rxjs.map(({ responseJSON }) => responseJSON.result),
 | 
					    rxjs.map(({ responseJSON }) => responseJSON.result),
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function get() {
 | 
					export async function init() {
 | 
				
			||||||
    return config$;
 | 
					    let config = await config$.toPromise();
 | 
				
			||||||
 | 
					    window.CONFIG = config;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -9,7 +9,6 @@ import componentFilesystem, { init as initFilesystem } from "./filespage/ctrl_fi
 | 
				
			|||||||
import componentSubmenu, { init as initSubmenu } from "./filespage/ctrl_submenu.js";
 | 
					import componentSubmenu, { init as initSubmenu } from "./filespage/ctrl_submenu.js";
 | 
				
			||||||
import componentNewItem, { init as initNewItem } from "./filespage/ctrl_newitem.js";
 | 
					import componentNewItem, { init as initNewItem } from "./filespage/ctrl_newitem.js";
 | 
				
			||||||
import componentUpload, { init as initUpload } from "./filespage/ctrl_upload.js";
 | 
					import componentUpload, { init as initUpload } from "./filespage/ctrl_upload.js";
 | 
				
			||||||
import { get as getConfig } from "./filespage/model_config.js";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "../components/breadcrumb.js";
 | 
					import "../components/breadcrumb.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -44,7 +43,7 @@ export default WithShell(function(render) {
 | 
				
			|||||||
export function init() {
 | 
					export function init() {
 | 
				
			||||||
    return Promise.all([
 | 
					    return Promise.all([
 | 
				
			||||||
        loadCSS(import.meta.url, "ctrl_filespage.css"),
 | 
					        loadCSS(import.meta.url, "ctrl_filespage.css"),
 | 
				
			||||||
        initShell(), initFilesystem(), getConfig().toPromise(),
 | 
					        initShell(), initFilesystem(),
 | 
				
			||||||
        initSubmenu(), initNewItem(), initUpload(),
 | 
					        initSubmenu(), initNewItem(), initUpload(),
 | 
				
			||||||
    ]);
 | 
					    ]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -5,11 +5,13 @@ import rxjs, { effect } from "../lib/rx.js";
 | 
				
			|||||||
import { deleteSession } from "../model/session.js";
 | 
					import { deleteSession } from "../model/session.js";
 | 
				
			||||||
import ctrlError from "./ctrl_error.js";
 | 
					import ctrlError from "./ctrl_error.js";
 | 
				
			||||||
import $loader from "../components/loader.js";
 | 
					import $loader from "../components/loader.js";
 | 
				
			||||||
 | 
					import { init as setup_config } from "../model/config.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function(render) {
 | 
					export default function(render) {
 | 
				
			||||||
    render($loader);
 | 
					    render($loader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    effect(deleteSession().pipe(
 | 
					    effect(deleteSession().pipe(
 | 
				
			||||||
 | 
					        rxjs.mergeMap(setup_config),
 | 
				
			||||||
        rxjs.tap(() => navigate(toHref("/"))),
 | 
					        rxjs.tap(() => navigate(toHref("/"))),
 | 
				
			||||||
        rxjs.catchError(ctrlError(render)),
 | 
					        rxjs.catchError(ctrlError(render)),
 | 
				
			||||||
    ));
 | 
					    ));
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,6 @@ import { ApplicationError } from "../lib/error.js";
 | 
				
			|||||||
import { basename } from "../lib/path.js";
 | 
					import { basename } from "../lib/path.js";
 | 
				
			||||||
import { loadCSS } from "../helpers/loader.js";
 | 
					import { loadCSS } from "../helpers/loader.js";
 | 
				
			||||||
import WithShell, { init as initShell } from "../components/decorator_shell_filemanager.js";
 | 
					import WithShell, { init as initShell } from "../components/decorator_shell_filemanager.js";
 | 
				
			||||||
import { get as getConfig } from "../model/config.js";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import ctrlError from "./ctrl_error.js";
 | 
					import ctrlError from "./ctrl_error.js";
 | 
				
			||||||
import { opener } from "./viewerpage/mimetype.js";
 | 
					import { opener } from "./viewerpage/mimetype.js";
 | 
				
			||||||
@ -12,11 +11,6 @@ import { getCurrentPath } from "./viewerpage/common.js";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import "../components/breadcrumb.js";
 | 
					import "../components/breadcrumb.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mime$ = getConfig().pipe(
 | 
					 | 
				
			||||||
    rxjs.map((config) => config.mime),
 | 
					 | 
				
			||||||
    rxjs.shareReplay(),
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function loadModule(appName) {
 | 
					function loadModule(appName) {
 | 
				
			||||||
    switch (appName) {
 | 
					    switch (appName) {
 | 
				
			||||||
    case "editor":
 | 
					    case "editor":
 | 
				
			||||||
@ -48,7 +42,7 @@ export default WithShell(async function(render) {
 | 
				
			|||||||
    const $page = createElement(`<div class="component_page_viewerpage"></div>`);
 | 
					    const $page = createElement(`<div class="component_page_viewerpage"></div>`);
 | 
				
			||||||
    render($page);
 | 
					    render($page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    effect(mime$.pipe(
 | 
					    effect(rxjs.of(CONFIG.mime || {}).pipe(
 | 
				
			||||||
        rxjs.map((mimes) => opener(basename(getCurrentPath()), mimes)),
 | 
					        rxjs.map((mimes) => opener(basename(getCurrentPath()), mimes)),
 | 
				
			||||||
        rxjs.mergeMap(([opener, options]) => rxjs.from(loadModule(opener)).pipe(
 | 
					        rxjs.mergeMap(([opener, options]) => rxjs.from(loadModule(opener)).pipe(
 | 
				
			||||||
            rxjs.map((module) => module.default(createRender($page), options)),
 | 
					            rxjs.map((module) => module.default(createRender($page), options)),
 | 
				
			||||||
@ -61,7 +55,7 @@ export async function init() {
 | 
				
			|||||||
    return Promise.all([
 | 
					    return Promise.all([
 | 
				
			||||||
        loadCSS(import.meta.url, "./ctrl_viewerpage.css"),
 | 
					        loadCSS(import.meta.url, "./ctrl_viewerpage.css"),
 | 
				
			||||||
        initShell(),
 | 
					        initShell(),
 | 
				
			||||||
        mime$.pipe(
 | 
					        rxjs.of(CONFIG.mime || {}).pipe(
 | 
				
			||||||
            rxjs.map((mimes) => opener(basename(getCurrentPath()), mimes)),
 | 
					            rxjs.map((mimes) => opener(basename(getCurrentPath()), mimes)),
 | 
				
			||||||
            rxjs.mergeMap(([opener]) => loadModule(opener)),
 | 
					            rxjs.mergeMap(([opener]) => loadModule(opener)),
 | 
				
			||||||
            rxjs.mergeMap((module) => typeof module.init === "function"? module.init() : rxjs.EMPTY),
 | 
					            rxjs.mergeMap((module) => typeof module.init === "function"? module.init() : rxjs.EMPTY),
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,10 @@
 | 
				
			|||||||
    border-top-left-radius: 15px;
 | 
					    border-top-left-radius: 15px;
 | 
				
			||||||
    border-top-right-radius: 15px;
 | 
					    border-top-right-radius: 15px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					.dark-mode .component_upload {
 | 
				
			||||||
 | 
					    color: var(--bg-color);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.component_upload h2 {
 | 
					.component_upload h2 {
 | 
				
			||||||
    padding: 20px 20px 5px 20px;
 | 
					    padding: 20px 20px 5px 20px;
 | 
				
			||||||
    margin: 0 0 5px 0;
 | 
					    margin: 0 0 5px 0;
 | 
				
			||||||
@ -28,13 +32,13 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
.component_upload h2 .count_block span.grandTotal {
 | 
					.component_upload h2 .count_block span.grandTotal {
 | 
				
			||||||
    font-size: 0.8em;
 | 
					    font-size: 0.8em;
 | 
				
			||||||
    color: var(--emphasis-secondary);
 | 
					    opacity: 0.8;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.component_upload h2 .count_block span.grandTotal:before {
 | 
					.component_upload h2 .count_block span.grandTotal:before {
 | 
				
			||||||
    content: "/";
 | 
					    content: "/";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.component_upload h2 .count_block span.completed {
 | 
					.component_upload h2 .count_block span.completed {
 | 
				
			||||||
    color: var(--emphasis-secondary);
 | 
					    opacity: 0.8;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.component_upload h2 .component_icon {
 | 
					.component_upload h2 .component_icon {
 | 
				
			||||||
    cursor: pointer;
 | 
					    cursor: pointer;
 | 
				
			||||||
@ -66,7 +70,7 @@
 | 
				
			|||||||
    color: var(--error);
 | 
					    color: var(--error);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.component_upload .stats_content .todo_color {
 | 
					.component_upload .stats_content .todo_color {
 | 
				
			||||||
    color: var(--light);
 | 
					    opacity: 0.7;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.component_upload .stats_content .file_row {
 | 
					.component_upload .stats_content .file_row {
 | 
				
			||||||
    display: flex;
 | 
					    display: flex;
 | 
				
			||||||
 | 
				
			|||||||
@ -89,13 +89,15 @@ function componentFilezone(render, { workers$ }) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const MAX_WORKERS = 4;
 | 
					const MAX_WORKERS = 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: calculate total
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function componentUploadQueue(render, { workers$ }) {
 | 
					function componentUploadQueue(render, { workers$ }) {
 | 
				
			||||||
    const $page = createElement(`
 | 
					    const $page = createElement(`
 | 
				
			||||||
        <div class="component_upload hidden">
 | 
					        <div class="component_upload hidden">
 | 
				
			||||||
            <h2 class="no-select">${t("Current Upload")}
 | 
					            <h2 class="no-select">${t("Current Upload")}
 | 
				
			||||||
                <div class="count_block">
 | 
					                <div class="count_block">
 | 
				
			||||||
                    <span class="completed">24</span>
 | 
					                    <span class="completed">0</span>
 | 
				
			||||||
                    <span class="grandTotal">24</span>
 | 
					                    <span class="grandTotal">0</span>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <img class="component_icon" draggable="false" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MS45NzYgNTEuOTc2Ij4KICA8cGF0aCBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eTowLjUzMzMzMjg1O3N0cm9rZS13aWR0aDoxLjQ1NjgxMTE5IiBkPSJtIDQxLjAwNTMxLDQwLjg0NDA2MiBjIC0xLjEzNzc2OCwxLjEzNzc2NSAtMi45ODIwODgsMS4xMzc3NjUgLTQuMTE5ODYxLDAgTCAyNi4wNjg2MjgsMzAuMDI3MjM0IDE0LjczNzU1MSw0MS4zNTgzMSBjIC0xLjEzNzc3MSwxLjEzNzc3MSAtMi45ODIwOTMsMS4xMzc3NzEgLTQuMTE5ODYxLDAgLTEuMTM3NzcyMiwtMS4xMzc3NjggLTEuMTM3NzcyMiwtMi45ODIwODggMCwtNC4xMTk4NjEgTCAyMS45NDg3NjYsMjUuOTA3MzcyIDExLjEzMTkzOCwxNS4wOTA1NTEgYyAtMS4xMzc3NjQ3LC0xLjEzNzc3MSAtMS4xMzc3NjQ3LC0yLjk4MzU1MyAwLC00LjExOTg2MSAxLjEzNzc3NCwtMS4xMzc3NzIxIDIuOTgyMDk4LC0xLjEzNzc3MjEgNC4xMTk4NjUsMCBMIDI2LjA2ODYyOCwyMS43ODc1MTIgMzYuMzY5NzM5LDExLjQ4NjM5OSBjIDEuMTM3NzY4LC0xLjEzNzc2OCAyLjk4MjA5MywtMS4xMzc3NjggNC4xMTk4NjIsMCAxLjEzNzc2NywxLjEzNzc2OSAxLjEzNzc2NywyLjk4MjA5NCAwLDQuMTE5ODYyIEwgMzAuMTg4NDg5LDI1LjkwNzM3MiA0MS4wMDUzMSwzNi43MjQxOTcgYyAxLjEzNzc3MSwxLjEzNzc2NyAxLjEzNzc3MSwyLjk4MjA5MSAwLDQuMTE5ODY1IHoiIC8+Cjwvc3ZnPgo=" alt="close">
 | 
					                <img class="component_icon" draggable="false" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MS45NzYgNTEuOTc2Ij4KICA8cGF0aCBzdHlsZT0iZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eTowLjUzMzMzMjg1O3N0cm9rZS13aWR0aDoxLjQ1NjgxMTE5IiBkPSJtIDQxLjAwNTMxLDQwLjg0NDA2MiBjIC0xLjEzNzc2OCwxLjEzNzc2NSAtMi45ODIwODgsMS4xMzc3NjUgLTQuMTE5ODYxLDAgTCAyNi4wNjg2MjgsMzAuMDI3MjM0IDE0LjczNzU1MSw0MS4zNTgzMSBjIC0xLjEzNzc3MSwxLjEzNzc3MSAtMi45ODIwOTMsMS4xMzc3NzEgLTQuMTE5ODYxLDAgLTEuMTM3NzcyMiwtMS4xMzc3NjggLTEuMTM3NzcyMiwtMi45ODIwODggMCwtNC4xMTk4NjEgTCAyMS45NDg3NjYsMjUuOTA3MzcyIDExLjEzMTkzOCwxNS4wOTA1NTEgYyAtMS4xMzc3NjQ3LC0xLjEzNzc3MSAtMS4xMzc3NjQ3LC0yLjk4MzU1MyAwLC00LjExOTg2MSAxLjEzNzc3NCwtMS4xMzc3NzIxIDIuOTgyMDk4LC0xLjEzNzc3MjEgNC4xMTk4NjUsMCBMIDI2LjA2ODYyOCwyMS43ODc1MTIgMzYuMzY5NzM5LDExLjQ4NjM5OSBjIDEuMTM3NzY4LC0xLjEzNzc2OCAyLjk4MjA5MywtMS4xMzc3NjggNC4xMTk4NjIsMCAxLjEzNzc2NywxLjEzNzc2OSAxLjEzNzc2NywyLjk4MjA5NCAwLDQuMTE5ODYyIEwgMzAuMTg4NDg5LDI1LjkwNzM3MiA0MS4wMDUzMSwzNi43MjQxOTcgYyAxLjEzNzc3MSwxLjEzNzc2NyAxLjEzNzc3MSwyLjk4MjA5MSAwLDQuMTE5ODY1IHoiIC8+Cjwvc3ZnPgo=" alt="close">
 | 
				
			||||||
            </h2>
 | 
					            </h2>
 | 
				
			||||||
@ -112,13 +114,28 @@ function componentUploadQueue(render, { workers$ }) {
 | 
				
			|||||||
            <div class="file_control no-select"></div>
 | 
					            <div class="file_control no-select"></div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
   `);
 | 
					   `);
 | 
				
			||||||
 | 
					    const updateTotal = {
 | 
				
			||||||
 | 
					        reset: () => {
 | 
				
			||||||
 | 
					            qs($page, ".grandTotal").innerText = 0;
 | 
				
			||||||
 | 
					            qs($page, ".completed").innerText = 0;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        addToTotal: (n) => {
 | 
				
			||||||
 | 
					            const $total = qs($page, ".grandTotal");
 | 
				
			||||||
 | 
					            $total.innerText = parseInt($total.innerText) + n;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        incrementCompleted: () => {
 | 
				
			||||||
 | 
					            const $completed = qs($page, ".completed");
 | 
				
			||||||
 | 
					            $completed.innerText = parseInt($completed.innerText) + 1;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // feature1: close the queue
 | 
					    // feature1: close the queue
 | 
				
			||||||
    onClick(qs($page, `img[alt="close"]`)).pipe(
 | 
					    onClick(qs($page, `img[alt="close"]`)).pipe(
 | 
				
			||||||
        rxjs.tap(async (cancel) => {
 | 
					        rxjs.tap(async (cancel) => {
 | 
				
			||||||
            const cleanup = await animate($page, { time: 200, keyframes: slideYOut(50) });
 | 
					            const cleanup = await animate($page, { time: 200, keyframes: slideYOut(50) });
 | 
				
			||||||
            qs($page, ".stats_content").innerHTML = "";
 | 
					            $content.innerHTML = "";
 | 
				
			||||||
            $page.classList.add("hidden");
 | 
					            $page.classList.add("hidden");
 | 
				
			||||||
 | 
					            updateTotal.reset();
 | 
				
			||||||
            cleanup();
 | 
					            cleanup();
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
    ).subscribe();
 | 
					    ).subscribe();
 | 
				
			||||||
@ -126,6 +143,7 @@ function componentUploadQueue(render, { workers$ }) {
 | 
				
			|||||||
    // feature2: setup the task queue in the dom
 | 
					    // feature2: setup the task queue in the dom
 | 
				
			||||||
    workers$.subscribe(({ tasks }) => {
 | 
					    workers$.subscribe(({ tasks }) => {
 | 
				
			||||||
        if (tasks.length === 0) return;
 | 
					        if (tasks.length === 0) return;
 | 
				
			||||||
 | 
					        updateTotal.addToTotal(tasks.length);
 | 
				
			||||||
        const $fragment = document.createDocumentFragment();
 | 
					        const $fragment = document.createDocumentFragment();
 | 
				
			||||||
        for (let i = 0; i<tasks.length; i++) {
 | 
					        for (let i = 0; i<tasks.length; i++) {
 | 
				
			||||||
            const $task = $file.cloneNode(true);
 | 
					            const $task = $file.cloneNode(true);
 | 
				
			||||||
@ -230,6 +248,7 @@ function componentUploadQueue(render, { workers$ }) {
 | 
				
			|||||||
            } catch(err) {
 | 
					            } catch(err) {
 | 
				
			||||||
                updateDOMWithStatus($task, { exec, status: "error", nworker });
 | 
					                updateDOMWithStatus($task, { exec, status: "error", nworker });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            updateTotal.incrementCompleted(1);
 | 
				
			||||||
            task.done = true;
 | 
					            task.done = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (tasks.length === 0 // no remaining tasks
 | 
					            if (tasks.length === 0 // no remaining tasks
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +0,0 @@
 | 
				
			|||||||
import rxjs from "../../lib/rx.js";
 | 
					 | 
				
			||||||
import { get as getConfig } from "../../model/config.js";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const config$ = getConfig().pipe(rxjs.shareReplay(1));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function get() {
 | 
					 | 
				
			||||||
    return config$;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,23 +1,16 @@
 | 
				
			|||||||
import { onDestroy } from "../../lib/skeleton/index.js";
 | 
					import { onDestroy } from "../../lib/skeleton/index.js";
 | 
				
			||||||
import rxjs, { effect, preventDefault } from "../../lib/rx.js";
 | 
					import rxjs, { effect, preventDefault } from "../../lib/rx.js";
 | 
				
			||||||
import { settingsGet, settingsSave } from "../../lib/store.js";
 | 
					import { settingsGet, settingsSave } from "../../lib/store.js";
 | 
				
			||||||
import { get as getConfig } from "./model_config.js";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const state$ = new rxjs.BehaviorSubject(null);
 | 
					const state$ = new rxjs.BehaviorSubject(settingsGet({
 | 
				
			||||||
 | 
					    view: window.CONFIG.default_view || "grid",
 | 
				
			||||||
 | 
					    show_hidden: window.CONFIG.display_hidden || false,
 | 
				
			||||||
 | 
					    sort: window.CONFIG.default_sort || "type",
 | 
				
			||||||
 | 
					    order: null,
 | 
				
			||||||
 | 
					    search: "",
 | 
				
			||||||
 | 
					}, "filespage"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
getConfig().subscribe((config) => {
 | 
					export const getState$ = () => state$.asObservable();
 | 
				
			||||||
    state$.next(settingsGet({
 | 
					 | 
				
			||||||
        view: config.default_view || "grid",
 | 
					 | 
				
			||||||
        show_hidden: config.display_hidden || false,
 | 
					 | 
				
			||||||
        sort: config.default_sort || "type",
 | 
					 | 
				
			||||||
        order: null,
 | 
					 | 
				
			||||||
        search: "",
 | 
					 | 
				
			||||||
    }, "filespage"));
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const getState$ = () => state$.asObservable().pipe(
 | 
					 | 
				
			||||||
    rxjs.filter((state) => state !== null),
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const setState = (...args) => {
 | 
					export const setState = (...args) => {
 | 
				
			||||||
    const obj = { ...state$.value };
 | 
					    const obj = { ...state$.value };
 | 
				
			||||||
 | 
				
			|||||||
@ -5,7 +5,6 @@ import { animate, opacityIn } from "../../lib/animate.js";
 | 
				
			|||||||
import assert from "../../lib/assert.js";
 | 
					import assert from "../../lib/assert.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { extractPath, isDir, isNativeFileUpload } from "./helper.js";
 | 
					import { extractPath, isDir, isNativeFileUpload } from "./helper.js";
 | 
				
			||||||
import { get as getConfig } from "./model_config.js";
 | 
					 | 
				
			||||||
import { files$ } from "./ctrl_filesystem.js";
 | 
					import { files$ } from "./ctrl_filesystem.js";
 | 
				
			||||||
import { addSelection, isSelected, clearSelection } from "./state_selection.js";
 | 
					import { addSelection, isSelected, clearSelection } from "./state_selection.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -26,15 +25,15 @@ const IMAGE = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let TYPES = {
 | 
					let TYPES = {
 | 
				
			||||||
    MIME: {},
 | 
					    MIME: window.CONFIG.mime,
 | 
				
			||||||
    THUMBNAILER: new Set(),
 | 
					    THUMBNAILER: (function() {
 | 
				
			||||||
 | 
					        const set = new Set();
 | 
				
			||||||
 | 
					        for (let i=0; i<window.CONFIG.thumbnailer.length; i++) {
 | 
				
			||||||
 | 
					            set.add(window.CONFIG.thumbnailer[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return set;
 | 
				
			||||||
 | 
					    })(),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
getConfig().subscribe((config) => {
 | 
					 | 
				
			||||||
    TYPES.MIME = config.mime;
 | 
					 | 
				
			||||||
    for (let i=0; i<config.thumbnailer.length; i++) {
 | 
					 | 
				
			||||||
        TYPES.THUMBNAILER.add(config.thumbnailer[i]);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const $tmpl = createElement(`
 | 
					const $tmpl = createElement(`
 | 
				
			||||||
    <a href="__TEMPLATE__" class="component_thing no-select" draggable="false" data-link>
 | 
					    <a href="__TEMPLATE__" class="component_thing no-select" draggable="false" data-link>
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,6 @@ import { createModal, MODAL_RIGHT_BUTTON } from "../../components/modal.js";
 | 
				
			|||||||
import { loadCSS, loadJS } from "../../helpers/loader.js";
 | 
					import { loadCSS, loadJS } from "../../helpers/loader.js";
 | 
				
			||||||
import ajax from "../../lib/ajax.js";
 | 
					import ajax from "../../lib/ajax.js";
 | 
				
			||||||
import { extname } from "../../lib/path.js";
 | 
					import { extname } from "../../lib/path.js";
 | 
				
			||||||
import { get as getConfig } from "../../model/config.js";
 | 
					 | 
				
			||||||
import t from "../../locales/index.js";
 | 
					import t from "../../locales/index.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import ctrlError from "../ctrl_error.js";
 | 
					import ctrlError from "../ctrl_error.js";
 | 
				
			||||||
@ -38,7 +37,6 @@ export default async function(render) {
 | 
				
			|||||||
    render($page);
 | 
					    render($page);
 | 
				
			||||||
    renderMenubar($dom.menubar(), buttonDownload(getFilename(), getDownloadUrl()));
 | 
					    renderMenubar($dom.menubar(), buttonDownload(getFilename(), getDownloadUrl()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const getConfig$ = getConfig().pipe(rxjs.shareReplay(1));
 | 
					 | 
				
			||||||
    const content$ = new rxjs.ReplaySubject(1);
 | 
					    const content$ = new rxjs.ReplaySubject(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // feature1: setup the dom
 | 
					    // feature1: setup the dom
 | 
				
			||||||
@ -59,7 +57,7 @@ export default async function(render) {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            return rxjs.of(content);
 | 
					            return rxjs.of(content);
 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        rxjs.mergeMap((content) => getConfig$.pipe(
 | 
					        rxjs.mergeMap((content) => rxjs.of(window.CONFIG).pipe(
 | 
				
			||||||
            rxjs.mergeMap((config) => rxjs.from(loadKeybinding(config.editor)).pipe(rxjs.mapTo(config))),
 | 
					            rxjs.mergeMap((config) => rxjs.from(loadKeybinding(config.editor)).pipe(rxjs.mapTo(config))),
 | 
				
			||||||
            rxjs.map((config) => [content, config]),
 | 
					            rxjs.map((config) => [content, config]),
 | 
				
			||||||
            rxjs.mergeMap((arr) => rxjs.from(loadMode(extname(getFilename()))).pipe(
 | 
					            rxjs.mergeMap((arr) => rxjs.from(loadMode(extname(getFilename()))).pipe(
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user