2023-07-22 16:24:16 +00:00
const SITE _FULL _IMAGES = document . getElementById ( 'SITE_FULL_IMAGES' ) . value
2022-10-14 10:47:08 +00:00
function getMessageFromJsonData ( success , json ) {
2023-11-10 14:15:37 +00:00
let message = success ? "Success!" : "Error, please refresh the page and try again" ;
2022-10-14 10:47:08 +00:00
let key = success ? "message" : "error" ;
if ( ! json || ! json [ key ] ) return message ;
message = json [ key ] ;
if ( ! success && json [ "details" ] ) {
message = json [ "details" ] ;
}
return message ;
}
2024-02-29 21:48:49 +00:00
function actuallyShowToast ( success , message ) {
2023-08-11 21:50:23 +00:00
const oldToast = bootstrap . Toast . getOrCreateInstance ( document . getElementById ( 'toast-post-' + ( success ? 'error' : 'success' ) ) ) ; // intentionally reversed here: this is the old toast
oldToast . hide ( ) ;
2022-10-14 10:47:08 +00:00
let element = success ? "toast-post-success" : "toast-post-error" ;
2022-10-14 12:33:36 +00:00
let textElement = element + "-text" ;
2022-10-14 09:49:58 +00:00
if ( ! message ) {
2023-11-10 14:15:37 +00:00
message = success ? "Action successful!" : "Error, please refresh the page and try again" ;
2022-10-14 09:49:58 +00:00
}
2023-08-14 14:29:06 +00:00
document . getElementById ( textElement ) . textContent = message ;
2022-10-14 09:49:58 +00:00
bootstrap . Toast . getOrCreateInstance ( document . getElementById ( element ) ) . show ( ) ;
2022-10-14 08:19:09 +00:00
}
2024-02-29 21:48:49 +00:00
function showToast ( success , message ) {
if ( document . hasFocus ( ) )
actuallyShowToast ( success , message )
else
document . addEventListener ( 'visibilitychange' , ( ) => {
actuallyShowToast ( success , message )
} , { once : true } )
}
2023-08-13 14:06:32 +00:00
function createXhrWithFormKey ( url , form = new FormData ( ) , method = 'POST' ) {
2022-10-14 12:33:36 +00:00
const xhr = new XMLHttpRequest ( ) ;
2023-08-13 14:06:32 +00:00
xhr . open ( method , url ) ;
2022-10-14 12:33:36 +00:00
xhr . setRequestHeader ( 'xhr' , 'xhr' ) ;
2022-10-14 12:43:23 +00:00
if ( ! form ) form = new FormData ( ) ;
2022-10-14 12:33:36 +00:00
form . append ( "formkey" , formkey ( ) ) ;
return [ xhr , form ] ; // hacky but less stupid than what we were doing before
2022-10-14 11:31:02 +00:00
}
2022-10-14 07:58:05 +00:00
2023-08-12 10:54:10 +00:00
function postToast ( t , url , data , extraActionsOnSuccess , extraActionsOnFailure ) {
2023-10-10 18:23:14 +00:00
const is _shop = t . id && t . id . startsWith ( 'buy-' )
if ( ! is _shop ) {
t . disabled = true ;
t . classList . add ( "disabled" ) ;
}
2023-08-12 12:48:40 +00:00
2022-10-14 12:33:36 +00:00
let form = new FormData ( ) ;
2023-08-06 03:33:34 +00:00
if ( typeof data === 'object' && data !== null ) {
2022-10-14 07:58:05 +00:00
for ( let k of Object . keys ( data ) ) {
form . append ( k , data [ k ] ) ;
}
}
2023-08-12 10:35:59 +00:00
const xhr = createXhrWithFormKey ( url , form ) ;
2023-03-10 03:21:02 +00:00
xhr [ 0 ] . onload = function ( ) {
2023-08-11 21:50:23 +00:00
const success = xhr [ 0 ] . status >= 200 && xhr [ 0 ] . status < 300 ;
2023-10-10 18:23:14 +00:00
if ( ! ( extraActionsOnSuccess == reload && success && ! is _shop ) ) {
2023-08-11 21:50:23 +00:00
t . disabled = false ;
t . classList . remove ( "disabled" ) ;
}
2022-10-14 07:58:05 +00:00
let result
2022-10-14 12:33:36 +00:00
let message ;
if ( typeof result == "string" ) {
message = result ;
} else {
message = getMessageFromJsonData ( success , JSON . parse ( xhr [ 0 ] . response ) ) ;
}
showToast ( success , message ) ;
2023-08-12 10:49:37 +00:00
if ( success && extraActionsOnSuccess ) extraActionsOnSuccess ( xhr [ 0 ] ) ;
2023-08-12 10:54:10 +00:00
if ( ! success && extraActionsOnFailure ) extraActionsOnFailure ( xhr [ 0 ] ) ;
2022-10-14 12:33:36 +00:00
return success ;
2022-10-14 07:58:05 +00:00
} ;
2022-10-14 12:01:11 +00:00
xhr [ 0 ] . send ( xhr [ 1 ] ) ;
2022-11-03 19:07:08 +00:00
}
2023-09-15 13:55:27 +00:00
function handle _disabled ( t ) {
btn = t . parentElement . getElementsByClassName ( 'handle_disabled' ) [ 0 ]
2023-09-17 19:14:07 +00:00
if ( ! btn ) return
2023-09-15 13:55:27 +00:00
if ( t . value ) {
btn . disabled = false ;
btn . classList . remove ( 'disabled' )
}
else {
btn . disabled = true ;
btn . classList . add ( 'disabled' )
}
}
2023-08-12 10:35:59 +00:00
function postToastReload ( t , url ) {
postToast ( t , url , { } , reload ) ;
2022-11-04 21:44:37 +00:00
}
2023-08-12 10:35:59 +00:00
function postToastSwitch ( t , url , button1 , button2 , cls , extraActionsOnSuccess ) {
2022-11-03 19:08:22 +00:00
postToast ( t , url ,
2022-11-03 19:07:08 +00:00
{
} ,
( xhr ) => {
2022-11-04 18:45:52 +00:00
if ( button1 )
{
2023-08-23 00:31:20 +00:00
if ( typeof button1 == 'boolean' ) {
2022-11-04 18:45:52 +00:00
location . reload ( )
} else {
2022-12-16 20:00:42 +00:00
try {
document . getElementById ( button1 ) . classList . toggle ( cls ) ;
2022-12-16 20:17:23 +00:00
}
catch ( e ) { }
try {
document . getElementById ( button2 ) . classList . toggle ( cls ) ;
2022-12-16 20:00:42 +00:00
}
catch ( e ) { }
2022-11-04 18:45:52 +00:00
}
}
2023-01-24 10:40:25 +00:00
if ( typeof extraActionsOnSuccess == 'function' )
2023-08-12 10:35:59 +00:00
extraActionsOnSuccess ( xhr ) ;
} ) ;
2022-10-14 07:58:05 +00:00
}
2023-10-08 19:56:14 +00:00
if ( ! location . pathname . endsWith ( '/submit' ) && ! location . pathname . endsWith ( '/chat' ) )
2022-10-14 07:58:05 +00:00
{
document . addEventListener ( 'keydown' , ( e ) => {
2023-08-06 03:33:34 +00:00
if ( ! ( ( e . ctrlKey || e . metaKey ) && e . key === "Enter" ) ) return ;
2022-10-14 07:58:05 +00:00
const targetDOM = document . activeElement ;
2023-08-06 03:33:34 +00:00
if ( ! ( targetDOM instanceof HTMLTextAreaElement || targetDOM instanceof HTMLInputElement ) ) return ;
2022-10-14 07:58:05 +00:00
const formDOM = targetDOM . parentElement ;
2023-07-22 17:43:32 +00:00
if ( formDOM . id == 'note_section' ) {
2023-10-10 16:53:46 +00:00
document . querySelector ( '.awardbtn:not(.d-none)' ) . click ( ) ;
2023-07-22 17:43:32 +00:00
return
}
2023-10-13 15:56:12 +00:00
if ( location . pathname == '/admin/orgies' ) {
2023-08-16 19:18:05 +00:00
document . getElementById ( 'start-orgy' ) . click ( ) ;
return
}
2022-10-14 07:58:05 +00:00
const submitButtonDOMs = formDOM . querySelectorAll ( 'input[type=submit], .btn-primary' ) ;
2023-10-02 06:04:05 +00:00
if ( submitButtonDOMs . length === 0 )
throw new TypeError ( "I am unable to find the submit button :(. Contact the head custodian immediately." )
const btn = submitButtonDOMs [ 0 ]
btn . click ( ) ;
2022-10-14 07:58:05 +00:00
} ) ;
}
2022-11-08 04:09:55 +00:00
function autoExpand ( field ) {
2023-09-29 01:10:05 +00:00
xpos = window . scrollX ;
ypos = window . scrollY ;
2022-10-14 07:58:05 +00:00
field . style . height = 'inherit' ;
2023-09-29 01:10:05 +00:00
let computed = window . getComputedStyle ( field ) ;
2022-10-14 07:58:05 +00:00
2022-12-04 15:40:32 +00:00
let height = parseInt ( computed . getPropertyValue ( 'border-top-width' ) , 10 )
2022-10-14 07:58:05 +00:00
+ parseInt ( computed . getPropertyValue ( 'padding-top' ) , 10 )
+ field . scrollHeight
+ parseInt ( computed . getPropertyValue ( 'padding-bottom' ) , 10 )
+ parseInt ( computed . getPropertyValue ( 'border-bottom-width' ) , 10 ) ;
field . style . height = height + 'px' ;
2023-09-29 01:10:05 +00:00
if ( Math . abs ( window . scrollX - xpos ) < 1 && Math . abs ( window . scrollY - ypos ) < 1 ) return ;
window . scrollTo ( xpos , ypos ) ;
2022-10-14 07:58:05 +00:00
} ;
function smoothScrollTop ( )
{
2023-09-29 01:10:05 +00:00
window . scrollTo ( { top : 0 , behavior : 'smooth' } ) ;
2022-10-14 07:58:05 +00:00
}
// Click navbar to scroll back to top
2022-11-26 05:34:50 +00:00
const nav = document . getElementsByTagName ( 'nav' )
2022-12-04 15:40:32 +00:00
if ( nav . length ) {
2022-11-26 05:34:50 +00:00
nav [ 0 ] . addEventListener ( 'click' , ( e ) => {
if ( e . target . id === "navbar" ||
e . target . classList . contains ( "container-fluid" ) ||
e . target . id == "navbarResponsive" ||
e . target . id == "logo-container" ||
e . target . classList . contains ( "srd" ) )
smoothScrollTop ( ) ;
} , false ) ;
}
2022-10-14 07:58:05 +00:00
function formkey ( ) {
let formkey = document . getElementById ( "formkey" )
if ( formkey ) return formkey . innerHTML ;
else return null ;
}
function bs _trigger ( e ) {
let tooltipTriggerList = [ ] . slice . call ( e . querySelectorAll ( '[data-bs-toggle="tooltip"]' ) ) ;
tooltipTriggerList . map ( function ( element ) {
return bootstrap . Tooltip . getOrCreateInstance ( element ) ;
} ) ;
2024-01-12 05:18:24 +00:00
if ( typeof update _inline _emoji _modal == 'function' ) {
2023-08-12 18:57:59 +00:00
insertGhostDivs ( e )
2022-10-14 07:58:05 +00:00
}
}
function escapeHTML ( unsafe ) {
return unsafe . replace ( /&/g , "&" ) . replace ( /</g , "<" ) . replace ( />/g , ">" ) . replace ( /"/g , """ ) . replace ( /'/g , "'" ) ;
}
2023-01-01 12:31:40 +00:00
function showmore ( t ) {
2023-03-10 21:10:46 +00:00
div = t . parentElement . parentElement . parentElement
2023-02-24 07:31:12 +00:00
let text = div . getElementsByTagName ( 'd' ) [ 0 ]
if ( ! text ) text = div . getElementsByClassName ( 'showmore-text' ) [ 0 ]
2023-03-10 23:30:42 +00:00
if ( ! text ) text = div . querySelector ( 'div.d-none' )
2023-02-24 07:31:12 +00:00
2023-05-16 02:05:19 +00:00
text . classList . remove ( 'd-none' )
t . remove ( )
2022-10-14 07:58:05 +00:00
}
function formatDate ( d ) {
2023-09-26 10:20:45 +00:00
const options = { year : 'numeric' , month : 'short' , day : 'numeric' , hour : '2-digit' , minute : '2-digit' , timeZoneName : 'short' } ;
return d . toLocaleTimeString ( [ ] , options )
2022-10-14 07:58:05 +00:00
}
const timestamps = document . querySelectorAll ( '[data-time]' ) ;
for ( const e of timestamps ) {
2022-11-25 23:25:15 +00:00
e . innerHTML = formatDate ( new Date ( e . dataset . time * 1000 ) ) ;
2022-10-14 07:58:05 +00:00
} ;
2023-01-01 03:05:09 +00:00
function timestamp ( t , ti ) {
2022-11-25 23:25:15 +00:00
const date = formatDate ( new Date ( ti * 1000 ) ) ;
2023-01-01 03:05:09 +00:00
t . setAttribute ( "data-bs-original-title" , date ) ;
2022-10-14 07:58:05 +00:00
} ;
function areyousure ( t ) {
2024-02-12 07:18:43 +00:00
if ( t . dataset . nonce != nonce ) { //to stop the oldhtml attribute from being used as a vector for html injections
2024-02-12 06:10:22 +00:00
console . error ( "Nonce check failed!" )
return
}
2023-03-21 19:11:02 +00:00
if ( t . value ) {
t . dataset . oldvalue = t . value
2022-10-14 07:58:05 +00:00
t . value = 'Are you sure?'
2023-03-21 19:11:02 +00:00
}
else {
t . dataset . oldhtml = t . innerHTML
2022-10-14 07:58:05 +00:00
t . innerHTML = t . innerHTML . replace ( t . textContent , 'Are you sure?' )
2023-03-21 19:11:02 +00:00
}
2022-10-14 07:58:05 +00:00
2022-12-30 12:14:18 +00:00
t . setAttribute ( "data-onclick" , t . dataset . areyousure ) ;
2022-10-14 07:58:05 +00:00
if ( t . dataset . dismiss )
2022-10-14 09:49:58 +00:00
t . setAttribute ( "data-bs-dismiss" , t . dataset . dismiss ) ;
2023-03-21 19:11:02 +00:00
t . classList . add ( 'areyousure' )
2022-10-14 18:20:23 +00:00
}
2022-10-24 22:36:51 +00:00
function prepare _to _pause ( audio ) {
for ( const e of document . querySelectorAll ( 'video,audio' ) )
{
2023-10-12 19:50:35 +00:00
if ( e == audio ) continue
2022-10-24 22:36:51 +00:00
e . addEventListener ( 'play' , ( ) => {
if ( ! audio . paused ) audio . pause ( ) ;
} ) ;
}
2022-12-27 02:19:19 +00:00
document . addEventListener ( 'click' , ( e ) => {
2023-01-28 10:38:06 +00:00
if ( ( e . target . tagName . toLowerCase ( ) == "lite-youtube" || e . target . classList . contains ( 'lty-playbtn' ) ) && ! audio . paused ) {
audio . pause ( ) ;
}
2022-11-18 19:41:03 +00:00
} ) ;
2022-10-24 22:36:51 +00:00
}
2022-11-07 06:08:50 +00:00
2023-10-19 18:58:44 +00:00
function handle _playing _music ( audio ) {
audio . addEventListener ( 'play' , ( ) => {
localStorage . setItem ( "playing_music" , Date . now ( ) ) ;
2023-10-19 19:08:32 +00:00
addEventListener ( 'beforeunload' , ( ) => {
2023-10-19 18:58:44 +00:00
localStorage . setItem ( "playing_music" , 0 ) ;
} )
} )
audio . addEventListener ( 'pause' , ( ) => {
localStorage . setItem ( "playing_music" , 0 ) ;
} )
}
function playing _music ( ) {
2023-10-19 19:23:06 +00:00
return ( Date . now ( ) - localStorage . getItem ( "playing_music" , 0 ) < 300000 )
2023-10-19 18:58:44 +00:00
}
2023-08-11 21:50:23 +00:00
function reload ( ) {
location . reload ( ) ;
}
2022-12-30 12:52:59 +00:00
function sendFormXHR ( form , extraActionsOnSuccess ) {
2024-01-12 05:18:24 +00:00
if ( typeof close _inline _emoji _modal === "function" ) {
close _inline _emoji _modal ( ) ;
2023-10-17 20:35:47 +00:00
}
2023-08-11 21:50:23 +00:00
const t = form . querySelector ( '[type="submit"]' )
t . disabled = true ;
t . classList . add ( "disabled" ) ;
2023-08-05 15:19:19 +00:00
2022-11-07 06:08:50 +00:00
const xhr = new XMLHttpRequest ( ) ;
formData = new FormData ( form ) ;
formData . append ( "formkey" , formkey ( ) ) ;
actionPath = form . getAttribute ( "action" ) ;
xhr . open ( "POST" , actionPath ) ;
xhr . setRequestHeader ( 'xhr' , 'xhr' ) ;
2023-03-10 03:21:02 +00:00
xhr . onload = function ( ) {
2023-08-11 21:50:23 +00:00
const success = xhr . status >= 200 && xhr . status < 300 ;
if ( ! ( extraActionsOnSuccess == reload && success ) ) {
t . disabled = false ;
t . classList . remove ( "disabled" ) ;
}
2023-10-10 19:34:38 +00:00
try {
2023-08-11 21:50:23 +00:00
const data = JSON . parse ( xhr . response ) ;
showToast ( success , getMessageFromJsonData ( success , data ) ) ;
2022-11-07 06:08:50 +00:00
}
2023-10-10 19:34:38 +00:00
catch { }
2023-08-11 21:50:23 +00:00
if ( success && extraActionsOnSuccess ) extraActionsOnSuccess ( xhr ) ;
2022-11-07 06:08:50 +00:00
} ;
xhr . send ( formData ) ;
}
2023-03-17 14:23:42 +00:00
function sendFormXHRSwitch ( form ) {
2022-12-30 12:52:59 +00:00
sendFormXHR ( form ,
2022-11-07 06:08:50 +00:00
( ) => {
2023-09-20 14:57:31 +00:00
form . nextElementSibling . classList . remove ( 'd-none' ) ;
2023-03-17 14:23:42 +00:00
const days = form . querySelector ( "input[name=days]" )
if ( ! days || ! days . value )
2023-02-19 13:23:08 +00:00
form . classList . add ( 'd-none' ) ;
2022-11-07 06:08:50 +00:00
}
)
}
2022-12-10 10:40:34 +00:00
2023-07-14 17:07:58 +00:00
function sendFormXHRReload ( form ) {
2023-08-11 21:50:23 +00:00
sendFormXHR ( form , reload )
2023-07-14 17:07:58 +00:00
}
2022-12-10 10:40:34 +00:00
let sortAscending = { } ;
function sort _table ( t ) {
const n = Array . prototype . indexOf . call ( t . parentElement . children , t ) ;
const table = this . event . target . parentElement . parentElement . parentElement
const rows = table . rows ;
let items = [ ] ;
for ( let i = 1 ; i < rows . length ; i ++ ) {
const ele = rows [ i ] ;
let x = rows [ i ] . getElementsByTagName ( "TD" ) [ n ] ;
2024-02-23 21:27:11 +00:00
if ( ! x . dataset . sort ) {
2022-12-10 10:40:34 +00:00
x = x . getElementsByTagName ( 'a' ) [ 0 ] || x ;
}
let attr ;
2024-02-23 21:27:11 +00:00
if ( x . dataset . sort ) {
attr = x . dataset . sort ;
2023-03-07 05:38:55 +00:00
if ( /^[\d-,]+$/ . test ( attr ) ) {
2023-03-07 05:37:14 +00:00
attr = parseInt ( attr . replace ( /,/g , '' ) )
}
2022-12-10 10:40:34 +00:00
} else if ( 'time' in x . dataset ) {
attr = parseInt ( x . dataset . time ) ;
} else {
2023-08-14 14:29:06 +00:00
attr = x . textContent
2022-12-10 11:57:23 +00:00
if ( /^[\d-,]+$/ . test ( x . innerHTML ) ) {
2022-12-10 10:40:34 +00:00
attr = parseInt ( attr . replace ( /,/g , '' ) )
}
}
items . push ( { ele , attr } ) ;
}
if ( sortAscending [ n ] ) {
items . sort ( ( a , b ) => a . attr > b . attr ? 1 : - 1 ) ;
sortAscending [ n ] = false ;
} else {
items . sort ( ( a , b ) => a . attr < b . attr ? 1 : - 1 ) ;
sortAscending [ n ] = true ;
}
for ( let i = items . length - 1 ; i -- ; ) {
items [ i ] . ele . parentNode . insertBefore ( items [ i ] . ele , items [ i + 1 ] . ele ) ;
}
}
2023-09-29 01:10:05 +00:00
const is _pwa = window . matchMedia ( '(display-mode: standalone)' ) [ 'matches' ] || window . matchMedia ( '(display-mode: minimal-ui)' ) [ 'matches' ]
2023-06-29 19:05:24 +00:00
if ( is _pwa ) {
2022-12-29 14:20:27 +00:00
const links = document . querySelectorAll ( 'a[data-target="t"]' ) ;
for ( const link of links ) {
link . removeAttribute ( "target" ) ;
}
}
2023-06-29 19:05:24 +00:00
const gbrowser = document . getElementById ( 'gbrowser' ) . value
2023-09-24 22:12:42 +00:00
if ( location . pathname != '/chat' && ( gbrowser == 'iphone' || gbrowser == 'mac' ) ) {
2022-12-29 14:20:27 +00:00
const videos = document . querySelectorAll ( 'video' )
for ( const video of videos ) {
const link = video . src
const htmlString = `
2023-11-04 21:36:05 +00:00
< a rel = "noopener" href = "${link}" target = "_blank" >
2022-12-29 14:20:27 +00:00
< div class = "d-flex justify-content-between align-items-center border rounded p-2 mb-3 download-video" >
< span > $ { link } < / s p a n >
< i class = "fas fa-external-link-alt text-small" > < / i >
< / d i v >
< / a > `
const div = document . createElement ( 'div' ) ;
div . innerHTML = htmlString ;
video . after ( div )
}
}
2023-01-24 10:02:08 +00:00
2023-09-29 06:11:18 +00:00
const screen _width = ( innerWidth > 0 ) ? innerWidth : screen . width ;
2023-02-18 18:58:07 +00:00
function focusSearchBar ( element )
{
2023-06-26 11:40:36 +00:00
if ( screen _width >= 768 ) {
2023-02-18 18:58:07 +00:00
element . focus ( ) ;
}
}
2023-02-27 15:02:35 +00:00
2023-06-26 11:40:36 +00:00
let MINFLIES ;
let MAXFLIES ;
2023-07-14 11:24:53 +00:00
let ACTUALMAXFILES ;
2023-02-27 15:02:35 +00:00
2023-06-26 11:40:36 +00:00
if ( screen _width < 768 ) {
MINFLIES = 5 ;
MAXFLIES = 10 ;
2023-07-14 11:24:53 +00:00
ACTUALMAXFILES = 50 ;
2023-06-26 11:40:36 +00:00
}
else {
MINFLIES = 10 ;
MAXFLIES = 20 ;
2023-07-14 11:24:53 +00:00
ACTUALMAXFILES = 150 ;
2023-06-26 11:40:36 +00:00
}
2023-02-27 15:02:35 +00:00
2023-03-18 14:27:12 +00:00
function insertText ( input , text ) {
2023-10-31 20:02:15 +00:00
if ( input . value ) text = ` ${ text } `
2023-03-18 14:27:12 +00:00
const newPos = input . selectionStart + text . length ;
input . setRangeText ( text ) ;
2023-09-29 01:10:05 +00:00
if ( window . chrome !== undefined )
2023-03-18 14:27:12 +00:00
setTimeout ( function ( ) {
input . focus ( ) ;
for ( let i = 0 ; i < 2 ; i ++ )
input . setSelectionRange ( newPos , newPos ) ;
input . focus ( ) ;
for ( let i = 0 ; i < 2 ; i ++ )
input . setSelectionRange ( newPos , newPos ) ;
} , 1 ) ;
else
input . setSelectionRange ( newPos , newPos ) ;
2023-07-22 16:29:19 +00:00
input . selectionStart = newPos ;
2023-09-15 13:55:27 +00:00
handle _disabled ( input )
2023-10-29 14:06:50 +00:00
if ( typeof checkForRequired === "function" ) checkForRequired ( ) ;
setTimeout ( ( ) => {
2023-10-29 14:12:29 +00:00
if ( document . activeElement !== input )
input . focus ( ) ;
2023-10-29 14:09:35 +00:00
} , 200 ) ;
2023-03-18 14:27:12 +00:00
}
2023-02-27 15:02:35 +00:00
//FILE SHIT
let oldfiles = { } ;
2023-10-02 08:12:54 +00:00
2023-10-02 15:02:39 +00:00
let MAX _IMAGE _AUDIO _SIZE _MB
let MAX _IMAGE _AUDIO _SIZE _MB _PATRON
let MAX _VIDEO _SIZE _MB
let MAX _VIDEO _SIZE _MB _PATRON
let vpatron
if ( document . getElementById ( "MAX_IMAGE_AUDIO_SIZE_MB" ) ) {
MAX _IMAGE _AUDIO _SIZE _MB = parseInt ( document . getElementById ( "MAX_IMAGE_AUDIO_SIZE_MB" ) . value )
MAX _IMAGE _AUDIO _SIZE _MB _PATRON = parseInt ( document . getElementById ( "MAX_IMAGE_AUDIO_SIZE_MB_PATRON" ) . value )
MAX _VIDEO _SIZE _MB = parseInt ( document . getElementById ( "MAX_VIDEO_SIZE_MB" ) . value )
MAX _VIDEO _SIZE _MB _PATRON = parseInt ( document . getElementById ( "MAX_VIDEO_SIZE_MB_PATRON" ) . value )
vpatron = parseInt ( document . getElementById ( "vpatron" ) . value )
}
2023-08-12 18:28:21 +00:00
let patron
if ( location . host == 'rdrama.net' ) patron = 'paypig'
else patron = 'patron'
2023-02-27 15:02:35 +00:00
function handle _files ( input , newfiles ) {
if ( ! newfiles ) return ;
2023-05-05 21:45:25 +00:00
2023-08-12 18:28:21 +00:00
for ( const file of newfiles ) {
2023-08-12 20:00:11 +00:00
if ( file . type . startsWith ( 'image/' ) )
continue
2023-08-12 18:28:21 +00:00
let max _size
let max _size _patron
let type
if ( file . type . startsWith ( 'video/' ) ) {
max _size = MAX _VIDEO _SIZE _MB
max _size _patron = MAX _VIDEO _SIZE _MB _PATRON
type = 'video'
}
else {
max _size = MAX _IMAGE _AUDIO _SIZE _MB
max _size _patron = MAX _IMAGE _AUDIO _SIZE _MB _PATRON
type = 'image/audio'
}
2023-10-02 08:12:54 +00:00
if ( file . size > max _size _patron * 1024 * 1024 || ( ! vpatron && file . size > max _size * 1024 * 1024 ) ) {
2023-08-12 18:28:21 +00:00
const msg = ` Max ${ type } size is ${ max _size } MB ( ${ max _size _patron } MB for ${ patron } s) `
showToast ( false , msg ) ;
input . value = null ;
return
}
}
2023-02-27 15:02:35 +00:00
const ta = input . parentElement . parentElement . parentElement . parentElement . querySelector ( 'textarea.file-ta' ) ;
2023-08-18 02:11:21 +00:00
if ( ! oldfiles [ ta . id ] ) {
2023-08-08 10:52:07 +00:00
oldfiles [ ta . id ] = new DataTransfer ( ) ;
2023-02-27 15:02:35 +00:00
}
2023-09-07 15:26:31 +00:00
2023-09-12 23:20:39 +00:00
for ( let file of newfiles ) {
2024-02-28 18:12:31 +00:00
if ( oldfiles [ ta . id ] . items . length == 20 )
{
window . alert ( "You can't upload more than 20 files at one time!" )
break
}
2023-09-12 23:20:39 +00:00
if ( file . name == 'image.png' ) {
const blob = file . slice ( 0 , file . size , 'image/png' ) ;
const new _name = Math . random ( ) . toString ( 32 ) . substring ( 2 , 10 ) + '.png'
file = new File ( [ blob ] , new _name , { type : 'image/png' } ) ;
}
2023-08-18 02:11:21 +00:00
oldfiles [ ta . id ] . items . add ( file ) ;
2023-09-12 23:20:39 +00:00
insertText ( ta , ` [ ${ file . name } ] ` ) ;
2023-08-18 02:11:21 +00:00
}
2023-02-27 15:02:35 +00:00
2023-09-12 23:20:39 +00:00
input . files = oldfiles [ ta . id ] . files ;
2023-09-07 15:26:31 +00:00
2023-08-22 23:21:49 +00:00
markdown ( ta )
2023-02-27 15:02:35 +00:00
autoExpand ( ta )
2023-09-07 15:26:31 +00:00
if ( typeof checkForRequired === "function" )
2023-08-08 10:55:14 +00:00
checkForRequired ( ) ;
2023-09-07 15:26:31 +00:00
if ( typeof savetext === "function" )
2023-08-08 10:55:14 +00:00
savetext ( ) ;
2023-08-08 12:26:32 +00:00
if ( typeof submit _save _files === "function" ) {
const array = [ ]
for ( const x of input . files ) {
array . push ( x )
}
submit _save _files ( "textarea" , array ) ;
}
2023-02-27 15:02:35 +00:00
}
2023-03-04 19:54:06 +00:00
file _upload = document . getElementById ( 'file-upload' ) ;
if ( file _upload ) {
2023-08-08 14:20:42 +00:00
function display _url _image ( ) {
2023-03-04 19:54:06 +00:00
if ( file _upload . files )
{
2023-08-07 13:27:04 +00:00
const file = file _upload . files [ 0 ]
2023-10-04 17:03:03 +00:00
const char _limit = screen _width >= 768 ? 50 : 10 ;
file _upload . previousElementSibling . textContent = file . name . substr ( 0 , char _limit ) ;
2023-08-07 13:27:04 +00:00
if ( file . type . startsWith ( 'image/' ) ) {
const fileReader = new FileReader ( ) ;
fileReader . readAsDataURL ( file _upload . files [ 0 ] ) ;
fileReader . onload = function ( ) {
document . getElementById ( 'image-preview' ) . setAttribute ( 'src' , this . result ) ;
document . getElementById ( 'image-preview' ) . classList . remove ( 'd-none' ) ;
document . getElementById ( 'image-preview' ) . classList . add ( 'mr-2' ) ;
} ;
}
else {
document . getElementById ( 'image-preview' ) . classList . add ( 'd-none' ) ;
document . getElementById ( 'image-preview' ) . classList . remove ( 'mr-2' ) ;
2023-03-04 19:54:06 +00:00
}
if ( typeof checkForRequired === "function" ) {
document . getElementById ( 'urlblock' ) . classList . add ( 'd-none' ) ;
2023-08-11 16:19:06 +00:00
document . getElementById ( 'remove-attachment' ) . classList . remove ( 'd-none' ) ;
2023-03-04 19:54:06 +00:00
checkForRequired ( ) ;
}
else {
document . getElementById ( 'submit-btn' ) . disabled = false ;
}
2023-08-08 14:20:42 +00:00
}
}
file _upload . onchange = ( ) => {
display _url _image ( )
if ( typeof submit _save _files === "function" ) {
const array = [ ]
for ( const x of file _upload . files ) {
array . push ( x )
2023-08-08 10:55:14 +00:00
}
2023-08-08 14:20:42 +00:00
submit _save _files ( "attachment" , array ) ;
2023-03-04 19:54:06 +00:00
}
}
2023-08-08 14:20:42 +00:00
2023-03-04 19:54:06 +00:00
}
2023-02-27 15:02:35 +00:00
document . onpaste = function ( event ) {
const files = structuredClone ( event . clipboardData . files ) ;
if ( ! files . length ) return
const focused = document . activeElement ;
let input ;
2023-03-04 19:54:06 +00:00
if ( file _upload ) {
if ( location . pathname . endsWith ( '/submit' ) && focused && focused . id == 'post-text' ) {
2023-02-27 15:02:35 +00:00
input = document . getElementById ( 'file-upload-submit' )
}
else {
2023-03-04 19:54:06 +00:00
file _upload . files = files ;
2023-08-08 14:20:42 +00:00
display _url _image ( ) ;
if ( typeof submit _save _files === "function" ) {
const array = [ ]
for ( const x of file _upload . files ) {
array . push ( x )
}
submit _save _files ( "attachment" , array ) ;
}
2023-02-27 15:02:35 +00:00
return ;
}
}
else if ( focused ) {
input = focused . parentElement . querySelector ( 'input[type="file"]' )
}
else {
input = document . querySelector ( 'input[type="file"]' )
}
2023-03-17 13:20:11 +00:00
event . preventDefault ( ) ;
2023-02-27 15:02:35 +00:00
handle _files ( input , files ) ;
}
2023-02-27 17:25:38 +00:00
function handleUploadProgress ( e , upload _prog ) {
const bar = upload _prog . firstElementChild ;
const percentIndicator = upload _prog . lastElementChild ;
2023-05-05 21:45:25 +00:00
2023-02-27 17:25:38 +00:00
upload _prog . classList . remove ( "d-none" )
if ( e . lengthComputable ) {
const progressPercent = Math . floor ( ( e . loaded / e . total ) * 100 ) ;
bar . value = progressPercent ;
percentIndicator . textContent = progressPercent + '%' ;
}
}
2023-03-10 01:51:45 +00:00
2023-10-02 06:04:05 +00:00
2023-10-14 19:29:33 +00:00
if ( screen _width < 768 ) {
2023-10-02 06:04:05 +00:00
let object
2024-02-18 20:39:01 +00:00
const expandImageModal = document . getElementById ( 'expandImageModal' )
2023-10-02 06:04:05 +00:00
if ( gbrowser == 'iphone' && expandImageModal )
object = expandImageModal
2024-02-18 20:39:01 +00:00
2023-10-02 06:04:05 +00:00
if ( gbrowser != 'iphone' )
object = document
if ( object ) {
object . addEventListener ( 'shown.bs.modal' , function ( e ) {
const new _href = ` ${ location . href . split ( '#' ) [ 0 ] } #m- ${ e . target . id } `
history . pushState ( { } , '' , new _href )
} ) ;
object . addEventListener ( 'hide.bs.modal' , function ( e ) {
if ( location . hash == ` #m- ${ e . target . id } ` ) {
history . back ( ) ;
}
} ) ;
addEventListener ( 'hashchange' , function ( ) {
if ( ! location . hash . startsWith ( "#m-" ) ) {
const curr _modal = bootstrap . Modal . getInstance ( document . getElementsByClassName ( 'show' ) [ 0 ] )
if ( curr _modal ) curr _modal . hide ( )
}
} ) ;
}
}
2023-10-27 10:38:55 +00:00
document . addEventListener ( 'show.bs.modal' , ( ) => {
2024-01-12 05:18:24 +00:00
if ( typeof close _inline _emoji _modal === "function" ) {
close _inline _emoji _modal ( ) ;
2023-10-27 10:38:55 +00:00
}
} ) ;
2023-10-17 20:35:47 +00:00
document . addEventListener ( 'hide.bs.modal' , ( ) => {
2024-01-12 05:18:24 +00:00
if ( typeof close _inline _emoji _modal === "function" ) {
close _inline _emoji _modal ( ) ;
2023-10-17 20:35:47 +00:00
}
2023-10-17 18:59:16 +00:00
} ) ;
2023-03-21 19:03:28 +00:00
document . querySelectorAll ( 'form' ) . forEach ( form => {
2023-03-21 18:56:05 +00:00
form . addEventListener ( 'submit' , ( e ) => {
if ( form . classList . contains ( 'is-submitting' ) ) {
e . preventDefault ( ) ;
}
2023-05-05 21:45:25 +00:00
2023-03-21 18:56:05 +00:00
form . classList . add ( 'is-submitting' ) ;
} ) ;
} ) ;
2023-06-29 18:09:27 +00:00
function urlB64ToUint8Array ( base64String ) {
const padding = '=' . repeat ( ( 4 - base64String . length % 4 ) % 4 ) ;
const base64 = ( base64String + padding )
. replace ( /\-/g , '+' )
. replace ( /_/g , '/' ) ;
2023-09-29 01:10:05 +00:00
const rawData = window . atob ( base64 ) ;
2023-06-29 18:09:27 +00:00
const outputArray = new Uint8Array ( rawData . length ) ;
for ( let i = 0 ; i < rawData . length ; ++ i ) {
outputArray [ i ] = rawData . charCodeAt ( i ) ;
}
return outputArray ;
}
function updateSubscriptionOnServer ( subscription , apiEndpoint ) {
const formData = new FormData ( ) ;
formData . append ( "subscription_json" , JSON . stringify ( subscription ) ) ;
const xhr = createXhrWithFormKey (
apiEndpoint ,
formData
) ;
xhr [ 0 ] . send ( xhr [ 1 ] ) ;
}
function enablePushNotifications ( ) {
if ( ! ( 'serviceWorker' in navigator && 'PushManager' in window ) ) return ;
let publicKeyElement = document . getElementById ( 'VAPID_PUBLIC_KEY' ) ;
if ( ! publicKeyElement ) return ;
let publicKey = urlB64ToUint8Array ( publicKeyElement . value ) ;
navigator . serviceWorker . getRegistration ( "/assets/js/service_worker.js" ) . then ( ( reg ) => {
return reg . pushManager . subscribe ( {
userVisibleOnly : true ,
applicationServerKey : publicKey ,
} )
} ) . then ( ( subscription ) => {
updateSubscriptionOnServer ( subscription , "/push_subscribe" )
2023-09-29 01:10:05 +00:00
window . alert ( "Push notifications are enabled!" )
2023-06-29 18:09:27 +00:00
} ) . catch ( ( e ) => {
2023-09-29 01:10:05 +00:00
window . alert ( "Please give the site access to notifications!" )
2023-07-22 23:44:00 +00:00
console . error ( e )
2023-06-29 18:09:27 +00:00
} )
}
2024-01-31 21:14:20 +00:00
function delReport ( t , url ) {
postToast ( t , url ,
{
} ,
( ) => {
t . parentElement . remove ( )
}
) ;
}
2024-02-14 09:57:05 +00:00
for ( const el of document . getElementsByClassName ( 'autofocus' ) ) {
el . focus ( )
}
2024-02-28 22:34:29 +00:00
for ( const el of document . getElementsByClassName ( 'tor-disabled' ) ) {
el . onclick = ( e ) => {
e . preventDefault ( ) ;
window . alert ( "File uploads are not allowed through TOR!" )
} ;
}