license import React from "react" ; import ReactDOM from "react-dom" ; import App , { QUERY_PROP_KEYS , QueryProps , Song } from "./App" ; import { Auth , parseAuth } from "./auth" ; import { parseQuery , toQueryString } from "./util/queryString" ; import "./index.css" ; /**
 * Renders Hacklily, with props set.
 */ function render ( ) { ReactDOM . render ( < App { ... getQueryProps ( ) } dirtySongs = { getDirtySongs ( ) } auth = { getAuth ( ) } csrf = { localStorage . csrf || null } colourScheme = { localStorage . colourScheme || "vs-dark" } hideUnstableNotification = { getHideUnstableNotification ( ) } setQuery = { setQuery } editSong = { editSong } markSongClean = { markSongClean } setAuth = { setAuth } setColourScheme = { setColourScheme } setCSRF = { setCSRF } setHideUnstableNotification = { setHideUnstableNotification } / > , document . getElementById ( "root" ) ) ; } /**
 * Gets query props from the URL.
 *
 * If a hash string is present, it will be used instead of the query.
 */ function getQueryProps ( ) { const hash = window . location . hash . slice ( 1 ) ; const queryObj = parseQuery ( hash || window . location . search ) ; const query = { } ; Object . keys ( queryObj ) . forEach ( ( key ) => { if ( key === "src" && queryObj [ key ] === "<url" ) { setTimeout ( ( ) => { setQuery ( { src : undefined } , true ) ; } , 0 ) ; return ; } const queryPropIdx = ( QUERY_PROP_KEYS as string [ ] ) . indexOf ( key ) ; if ( queryPropIdx === - 1 ) { console . warn ( `Warning: unknown query property ${ key }. ` + "Please add it to QUERY_PROP_KEYS in App.tsx." ) ; return ; } const queryPropKey = QUERY_PROP_KEYS [ queryPropIdx ] ; query [ queryPropKey ] = queryObj [ key ] ; } ) ; return query ; } /**
 * Like React's setState, but for the URL query parameters.
 *
 * If the query string is too long, a hash ('#') will be used instead of a query to avoid needing
 * to pass the long URL to the server.
 */ function setQuery ( queryUpdates , replaceState = false ) { const query = getQueryProps ( ) ; ( Object . keys ( queryUpdates ) as Array < keyof QueryProps > ) . forEach ( ( key ) : void => { if ( key in queryUpdates ) { query [ key ] = queryUpdates [ key ] ; } } ) ; const origConnector = window . location . hash . length > 1 ? "#" : "?" ; const base = location . href . split ( origConnector ) [ 0 ] ; const queryString = toQueryString ( query as { [ key ] : string ; } ) ; const connector = base . length + queryString . length + 1 > 1024 ? "#" : "?" ; const newUrl = queryString . length ? `${ base }${ connector }${ queryString }` : base ; if ( replaceState ) { history . replaceState ( null , "" , newUrl ) ; } else { history . pushState ( null , "" , newUrl ) ; } render ( ) ; } function getDirtySongs ( ) { const songs = { } ; for ( let i = 0 ; i < localStorage . length ; i = i + 1 ) { const key = localStorage . key ( i ) ; if ( ! key ) { continue ; } const value = localStorage . getItem ( key ) ; if ( ! value ) { continue ; } if ( key . startsWith ( "dirtySong::" ) ) { songs [ key . split ( "::" ) [ 1 ] ] = JSON . parse ( value ) ; } } return songs ; } function getAuth ( ) { return parseAuth ( localStorage . auth ) ; } function getHideUnstableNotification ( ) { return localStorage . hideUnstableNotification || false ; } function editSong ( songID , song ) { localStorage [ `dirtySong::${ songID }` ] = JSON . stringify ( song ) ; render ( ) ; } function markSongClean ( song ) { delete localStorage [ `dirtySong::${ song }` ] ; render ( ) ; } function setAuth ( auth ) { if ( ! auth ) { delete localStorage . auth ; } else { localStorage . auth = JSON . stringify ( auth ) ; } render ( ) ; } function setColourScheme ( colourScheme ) { localStorage . colourScheme = colourScheme ; document . location . reload ( ) ; } function setHideUnstableNotification ( hideUnstableNotification ) { if ( hideUnstableNotification ) { localStorage . hideUnstableNotification = true ; } else { delete localStorage . hideUnstableNotification ; } render ( ) ; } function setCSRF ( csrf ) { if ( ! csrf ) { delete localStorage . csrf ; delete localStorage . csrfQueryParams ; } else { localStorage . csrf = csrf ; localStorage . csrfQueryParams = JSON . stringify ( getQueryProps ( ) , null , 2 ) ; } render ( ) ; } window . addEventListener ( "popstate" , ( _ev ) : void => { render ( ) ; } ) ; const queryProps = getQueryProps ( ) ; if ( queryProps . state === localStorage . csrf && localStorage . csrf && localStorage . csrfQueryParams ) { const newQuery = JSON . parse ( localStorage . csrfQueryParams ) ; setQuery ( newQuery , true ) ; } else { render ( ) ; }