2026-05-31 13:02:58 +03:00
( function ( ) {
2026-06-01 02:24:51 +03:00
document . querySelectorAll ( "[data-storage-delete-warning]" ) . forEach ( ( button ) => {
button . addEventListener ( "click" , ( event ) => {
const name = button . getAttribute ( "data-storage-delete-warning" ) || "this storage backend" ;
const confirmed = window . confirm (
` Delete ${ name } ? \n \n All boxes stored on this location will also be deleted. Any global defaults or user storage overrides pointing at it will be reset back to inherited local storage. `
) ;
if ( ! confirmed ) {
event . preventDefault ( ) ;
}
} ) ;
} ) ;
2026-05-31 19:52:46 +03:00
document . querySelectorAll ( "[data-storage-speed-open]" ) . forEach ( ( button ) => {
2026-05-31 13:02:58 +03:00
button . addEventListener ( "click" , ( ) => {
2026-05-31 19:52:46 +03:00
const modal = document . querySelector ( "[data-storage-speed-modal]" ) ;
if ( modal ) {
modal . hidden = false ;
2026-05-31 13:02:58 +03:00
}
} ) ;
} ) ;
2026-05-31 19:52:46 +03:00
document . querySelectorAll ( "[data-storage-modal-close]" ) . forEach ( ( button ) => {
2026-05-31 13:02:58 +03:00
button . addEventListener ( "click" , ( ) => {
2026-05-31 19:52:46 +03:00
const modal = button . closest ( ".storage-modal" ) ;
if ( modal ) {
modal . hidden = true ;
2026-05-31 13:02:58 +03:00
}
} ) ;
} ) ;
2026-05-31 19:52:46 +03:00
document . addEventListener ( "keydown" , ( event ) => {
if ( event . key !== "Escape" ) {
return ;
}
document . querySelectorAll ( ".storage-modal" ) . forEach ( ( modal ) => {
modal . hidden = true ;
} ) ;
} ) ;
2026-05-31 13:02:58 +03:00
2026-05-31 19:52:46 +03:00
document . querySelectorAll ( ".storage-speed-form" ) . forEach ( ( form ) => {
const customFields = form . querySelector ( "[data-storage-custom-fields]" ) ;
function syncCustomFields ( ) {
if ( ! customFields ) {
return ;
2026-05-31 13:02:58 +03:00
}
2026-05-31 19:52:46 +03:00
const customSelected = form . querySelector ( 'input[name="mode"]:checked' ) ? . value === "custom" ;
customFields . hidden = ! customSelected ;
customFields . querySelectorAll ( "input" ) . forEach ( ( input ) => {
input . disabled = ! customSelected ;
} ) ;
}
form . querySelectorAll ( 'input[name="mode"]' ) . forEach ( ( input ) => {
input . addEventListener ( "change" , syncCustomFields ) ;
2026-05-31 13:02:58 +03:00
} ) ;
2026-05-31 19:52:46 +03:00
syncCustomFields ( ) ;
} ) ;
2026-05-31 13:02:58 +03:00
2026-05-31 19:52:46 +03:00
const testList = document . querySelector ( "[data-storage-tests-page]" ) ;
if ( ! testList ) {
return ;
}
2026-05-31 13:02:58 +03:00
2026-05-31 19:52:46 +03:00
function escapeHTML ( value ) {
return String ( value || "" ) . replace ( /[&<>"']/g , ( char ) => ( {
"&" : "&" ,
"<" : "<" ,
">" : ">" ,
'"' : """ ,
"'" : "'" ,
} ) [ char ] ) ;
}
2026-05-31 13:02:58 +03:00
2026-05-31 19:52:46 +03:00
function renderTest ( test ) {
const progress = Math . max ( 0 , Math . min ( 100 , Number ( test . progress || 0 ) ) ) ;
const error = test . error
? ` <span class="storage-result-error"><strong>Error</strong> ${ escapeHTML ( test . error ) } </span> `
: "" ;
return `
< details class = "storage-result-row" data - storage - test - id = "${escapeHTML(test.id)}" >
< summary >
< span > $ { escapeHTML ( test . startedLabel ) } < / s p a n >
< span > $ { escapeHTML ( test . customLabel || test . modeLabel ) } < / s p a n >
< span class = "storage-result-status is-${escapeHTML(test.status)}" > $ { escapeHTML ( test . status ) } < / s p a n >
< / s u m m a r y >
< div class = "storage-test-progress" aria - label = "Test progress" >
< div class = "storage-test-progress-bar" > < span style = "width: ${progress}%" > < / s p a n > < / d i v >
< small > $ { progress } % $ { test . stage ? " · " + escapeHTML ( test . stage ) : "" } < / s m a l l >
< / d i v >
< div class = "storage-result-detail" >
< span > < strong > Finished < / s t r o n g > $ { e s c a p e H T M L ( t e s t . f i n i s h e d L a b e l ) } < / s p a n >
< span > < strong > Files < / s t r o n g > $ { e s c a p e H T M L ( t e s t . f i l e s ) } < / s p a n >
< span > < strong > Size < / s t r o n g > $ { e s c a p e H T M L ( t e s t . s i z e L a b e l ) } < / s p a n >
< span > < strong > Write < / s t r o n g > $ { e s c a p e H T M L ( t e s t . w r i t e S p e e d ) } < / s p a n >
< span > < strong > Read < / s t r o n g > $ { e s c a p e H T M L ( t e s t . r e a d S p e e d ) } < / s p a n >
$ { error }
< / d i v >
< / d e t a i l s > ` ;
2026-05-31 13:02:58 +03:00
}
2026-05-31 19:52:46 +03:00
async function refreshTests ( ) {
const url = testList . getAttribute ( "data-storage-tests-url" ) ;
if ( ! url ) {
return ;
2026-05-31 13:02:58 +03:00
}
2026-05-31 19:52:46 +03:00
const response = await fetch ( url , { headers : { Accept : "application/json" } } ) ;
if ( ! response . ok ) {
return ;
}
const payload = await response . json ( ) ;
const openIDs = new Set ( Array . from ( testList . querySelectorAll ( "details[open]" ) ) . map ( ( row ) => row . dataset . storageTestId ) ) ;
const tests = payload . tests || [ ] ;
if ( tests . length === 0 ) {
return ;
}
testList . innerHTML = tests . map ( renderTest ) . join ( "" ) ;
testList . querySelectorAll ( "details" ) . forEach ( ( row ) => {
if ( openIDs . has ( row . dataset . storageTestId ) ) {
row . open = true ;
}
} ) ;
2026-05-31 13:02:58 +03:00
}
2026-05-31 19:52:46 +03:00
setInterval ( ( ) => {
refreshTests ( ) . catch ( ( ) => { } ) ;
} , 1200 ) ;
2026-05-31 13:02:58 +03:00
} ) ( ) ;