Path: blob/master/src/packages/frontend/app/query-params.ts
5711 views
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45// Initialize various things related to the overall page and query params (e.g., fullscreen).6import { redux } from "@cocalc/frontend/app-framework";7import target from "@cocalc/frontend/client/handle-target";8import { appBasePath } from "@cocalc/frontend/customize/app-base-path";9import { COCALC_FULLSCREEN } from "@cocalc/frontend/fullscreen";10import { parse_target } from "@cocalc/frontend/history";11import {12get_local_storage,13set_local_storage,14} from "@cocalc/frontend/misc/local-storage";15import { QueryParams } from "@cocalc/frontend/misc/query-params";16import { A11Y } from "@cocalc/util/consts/ui";17import { is_valid_uuid_string } from "@cocalc/util/misc";1819function init_fullscreen_mode(): void {20const actions = redux.getActions("page");21// enable fullscreen mode upon loading a URL like /app?fullscreen and22// additionally kiosk-mode upon /app?fullscreen=kiosk23if (COCALC_FULLSCREEN === "kiosk") {24actions.set_fullscreen("kiosk");25// We also check if user is loading a specific project in kiosk mode26// (which is the only thing they should ever do!), and in that27// case we record the project_id, so that we can make various28// query optimizations elsewhere.29const x = parse_target(target);30if (x.page === "project" && x.target != null) {31const kiosk_project_id = x.target.slice(0, 36);32if (is_valid_uuid_string(kiosk_project_id)) {33actions.setState({ kiosk_project_id });34}35}36} else if (COCALC_FULLSCREEN === "default") {37actions.set_fullscreen("default");38// We no longer need fullscreen in the query parameter:39QueryParams.remove("fullscreen");40} else if (COCALC_FULLSCREEN === "project") {41actions.set_fullscreen("project");42}43}4445function init_api_key(): void {46const actions = redux.getActions("page");47const get_api_key_query_value = QueryParams.get("get_api_key");48if (get_api_key_query_value) {49actions.set_get_api_key(get_api_key_query_value);50actions.set_fullscreen("project");51}52}5354function init_session(): void {55const actions = redux.getActions("page");56// configure the session57// This makes it so the default session is 'default' and there is no58// way to NOT have a session, except via session=, which is treated59// as "no session" (also no session for kiosk mode).60// Note that we never have a session in kiosk mode, since you can't61// access the other files.62// If click on link with ?session=, then you get no session, e.g,. this63// is used for doing a pop-out of a single file. Should have no impact64// on sessions at all.65if (COCALC_FULLSCREEN === "kiosk") {66actions.set_session(""); // no session67} else {68const key = `session${appBasePath}`;69const querySession = QueryParams.get("session");70let session: any = querySession ?? get_local_storage(key) ?? "default";7172if (typeof session != "string") {73// should never happen, but of course it could since user could put anything in URL query params74// We just reset to default in this case.75session = "default";76}77actions.set_session(session);78if (session) {79// So when you don't give session= param in this browser in the future80// it defaults to the one you did use (or "default").81set_local_storage(key, session);82}83}84// Do not need or want it in our URL once we've consumed it. Critical to85// not have session in the URL, so we can share url's without infected86// other user's session.87QueryParams.remove("session");88}8990function parse_accessibility_param(param: string): boolean | null {91if (param === "true" || param === "on" || param === "1") {92return true;93}94if (param === "false" || param === "off" || param === "0") {95return false;96}97return null;98}99100async function init_accessibility(): Promise<void> {101// Handle accessibility query parameter102// If ?accessibility=true or =on, enable accessibility mode permanently103// If ?accessibility=false or =off, disable it permanently104// This allows sharing URLs that automatically enable accessibility105const accessibilityParam = QueryParams.get(A11Y);106if (accessibilityParam == null) {107return;108}109110const enabled = parse_accessibility_param(accessibilityParam);111QueryParams.remove(A11Y);112113if (enabled == null) {114return;115}116117try {118// Wait for account store to be ready before setting accessibility119const store = redux.getStore("account");120if (!store || typeof store.async_wait !== "function") {121console.warn("Account store not ready");122return;123}124125await store.async_wait({126until: () => store.get_account_id() != null,127timeout: 0,128});129130// Preserve existing accessibility settings131const existingSettingsStr = store.getIn(["other_settings", A11Y]);132let existingSettings = { enabled: false };133if (existingSettingsStr) {134try {135existingSettings = JSON.parse(existingSettingsStr);136} catch {137// Ignore parse errors, use default138}139}140141// Merge with new enabled value142const settings = { ...existingSettings, enabled };143const accountActions = redux.getActions("account");144accountActions.set_other_settings(A11Y, JSON.stringify(settings));145} catch (err) {146console.warn("Failed to set accessibility from query param:", err);147}148}149150export function init_query_params(): void {151init_fullscreen_mode();152init_api_key();153init_session();154// Run accessibility init in background without blocking155// to avoid delaying other store initializations156init_accessibility();157}158159160