@ -48,201 +48,198 @@ function loaded() {
} ;
} ;
ready ( ( ) => {
const locale = document . documentElement . lang ;
const dateTimeFormat = new Intl . DateTimeFormat ( locale , {
year : 'numeric' ,
month : 'long' ,
day : 'numeric' ,
hour : 'numeric' ,
minute : 'numeric' ,
} ) ;
const dateFormat = new Intl . DateTimeFormat ( locale , {
year : 'numeric' ,
month : 'short' ,
day : 'numeric' ,
timeFormat : false ,
} ) ;
const timeFormat = new Intl . DateTimeFormat ( locale , {
timeStyle : 'short' ,
hour12 : false ,
} ) ;
const formatMessage = ( { id , defaultMessage } , values ) => {
const messageFormat = new IntlMessageFormat ( localeData [ id ] || defaultMessage , locale ) ;
return messageFormat . format ( values ) ;
} ;
const locale = document . documentElement . lang ;
const dateTimeFormat = new Intl . DateTimeFormat ( locale , {
year : 'numeric' ,
month : 'long' ,
day : 'numeric' ,
hour : 'numeric' ,
minute : 'numeric' ,
} ) ;
[ ] . forEach . call ( document . querySelectorAll ( '.emojify' ) , ( content ) => {
content . innerHTML = emojify ( content . innerHTML ) ;
} ) ;
const dateFormat = new Intl . DateTimeFormat ( locale , {
year : 'numeric' ,
month : 'short' ,
day : 'numeric' ,
timeFormat : false ,
} ) ;
[ ] . forEach . call ( document . querySelectorAll ( 'time.formatted' ) , ( content ) => {
const datetime = new Date ( content . getAttribute ( 'datetime' ) ) ;
const formattedDate = dateTimeFormat . format ( datetime ) ;
const timeFormat = new Intl . DateTimeFormat ( locale , {
timeStyle : 'short' ,
hour12 : false ,
} ) ;
content . title = formattedDate ;
content . textContent = formattedDate ;
} ) ;
const formatMessage = ( { id , defaultMessage } , values ) => {
const messageFormat = new IntlMessageFormat ( localeData [ id ] || defaultMessage , locale ) ;
return messageFormat . format ( values ) ;
} ;
const isToday = date => {
const today = new Date ( ) ;
[ ] . forEach . call ( document . querySelectorAll ( '.emojify' ) , ( content ) => {
content . innerHTML = emojify ( content . innerHTML ) ;
} ) ;
return date . getDate ( ) === today . getDate ( ) &&
date . getMonth ( ) === today . getMonth ( ) &&
date . getFullYear ( ) === today . getFullYear ( ) ;
} ;
const todayFormat = new IntlMessageFormat ( localeData [ 'relative_format.today' ] || 'Today at {time}' , locale ) ;
[ ] . forEach . call ( document . querySelectorAll ( 'time.relative-formatted' ) , ( content ) => {
const datetime = new Date ( content . getAttribute ( 'datetime' ) ) ;
let formattedContent ;
if ( isToday ( datetime ) ) {
const formattedTime = timeFormat . format ( datetime ) ;
formattedContent = todayFormat . format ( { time : formattedTime } ) ;
} else {
formattedContent = dateFormat . format ( datetime ) ;
}
content . title = formattedContent ;
content . textContent = formattedContent ;
} ) ;
[ ] . forEach . call ( document . querySelectorAll ( 'time.time-ago' ) , ( content ) => {
const datetime = new Date ( content . getAttribute ( 'datetime' ) ) ;
const now = new Date ( ) ;
const timeGiven = content . getAttribute ( 'datetime' ) . includes ( 'T' ) ;
content . title = timeGiven ? dateTimeFormat . format ( datetime ) : dateFormat . format ( datetime ) ;
content . textContent = timeAgoString ( {
formatMessage ,
formatDate : ( date , options ) => ( new Intl . DateTimeFormat ( locale , options ) ) . format ( date ) ,
} , datetime , now , now . getFullYear ( ) , timeGiven ) ;
} ) ;
const reactComponents = document . querySelectorAll ( '[data-component]' ) ;
if ( reactComponents . length > 0 ) {
import ( /* webpackChunkName: "containers/media_container" */ '../mastodon/containers/media_container' )
. then ( ( { default : MediaContainer } ) => {
[ ] . forEach . call ( reactComponents , ( component ) => {
[ ] . forEach . call ( component . children , ( child ) => {
component . removeChild ( child ) ;
} ) ;
} ) ;
[ ] . forEach . call ( document . querySelectorAll ( 'time.formatted' ) , ( content ) => {
const datetime = new Date ( content . getAttribute ( 'datetime' ) ) ;
const formattedDate = dateTimeFormat . format ( datetime ) ;
const content = document . createElement ( 'div' ) ;
content . title = formattedDate ;
content . textContent = formattedDate ;
} ) ;
const root = createRoot ( content ) ;
root . render ( < MediaContainer locale = { locale } components = { reactComponents } / > ) ;
document . body . appendChild ( content ) ;
scrollToDetailedStatus ( ) ;
} )
. catch ( error => {
console . error ( error ) ;
scrollToDetailedStatus ( ) ;
} ) ;
const isToday = date => {
const today = new Date ( ) ;
return date . getDate ( ) === today . getDate ( ) &&
date . getMonth ( ) === today . getMonth ( ) &&
date . getFullYear ( ) === today . getFullYear ( ) ;
} ;
const todayFormat = new IntlMessageFormat ( localeData [ 'relative_format.today' ] || 'Today at {time}' , locale ) ;
[ ] . forEach . call ( document . querySelectorAll ( 'time.relative-formatted' ) , ( content ) => {
const datetime = new Date ( content . getAttribute ( 'datetime' ) ) ;
let formattedContent ;
if ( isToday ( datetime ) ) {
const formattedTime = timeFormat . format ( datetime ) ;
formattedContent = todayFormat . format ( { time : formattedTime } ) ;
} else {
scrollToDetailedStatus ( ) ;
formattedContent = dateFormat . format ( datetime ) ;
}
delegate ( document , '#user_account_attributes_username' , 'input' , throttle ( ( ) => {
const username = document . getElementById ( 'user_account_attributes_username' ) ;
content . title = formattedContent ;
content . textContent = formattedContent ;
} ) ;
if ( username . value && username . value . length > 0 ) {
axios . get ( '/api/v1/accounts/lookup' , { params : { acct : username . value } } ) . then ( ( ) => {
username . setCustomValidity ( formatMessage ( messages . usernameTaken ) ) ;
} ) . catch ( ( ) => {
username . setCustomValidity ( '' ) ;
} ) ;
} else {
username . setCustomValidity ( '' ) ;
}
} , 500 , { leading : false , trailing : true } ) ) ;
delegate ( document , '#user_password,#user_password_confirmation' , 'input' , ( ) => {
const password = document . getElementById ( 'user_password' ) ;
const confirmation = document . getElementById ( 'user_password_confirmation' ) ;
if ( ! confirmation ) return ;
if ( confirmation . value && confirmation . value . length > password . maxLength ) {
confirmation . setCustomValidity ( formatMessage ( messages . passwordExceedsLength ) ) ;
} else if ( password . value && password . value !== confirmation . value ) {
confirmation . setCustomValidity ( formatMessage ( messages . passwordDoesNotMatch ) ) ;
} else {
confirmation . setCustomValidity ( '' ) ;
}
} ) ;
delegate ( document , '.custom-emoji' , 'mouseover' , getEmojiAnimationHandler ( 'data-original' ) ) ;
delegate ( document , '.custom-emoji' , 'mouseout' , getEmojiAnimationHandler ( 'data-static' ) ) ;
delegate ( document , '.status__content__spoiler-link' , 'click' , function ( ) {
const statusEl = this . parentNode . parentNode ;
if ( statusEl . dataset . spoiler === 'expanded' ) {
statusEl . dataset . spoiler = 'folded' ;
this . textContent = ( new IntlMessageFormat ( localeData [ 'status.show_more' ] || 'Show more' , locale ) ) . format ( ) ;
} else {
statusEl . dataset . spoiler = 'expanded' ;
this . textContent = ( new IntlMessageFormat ( localeData [ 'status.show_less' ] || 'Show less' , locale ) ) . format ( ) ;
}
return false ;
} ) ;
[ ] . forEach . call ( document . querySelectorAll ( '.status__content__spoiler-link' ) , ( spoilerLink ) => {
const statusEl = spoilerLink . parentNode . parentNode ;
const message = ( statusEl . dataset . spoiler === 'expanded' ) ? ( localeData [ 'status.show_less' ] || 'Show less' ) : ( localeData [ 'status.show_more' ] || 'Show more' ) ;
spoilerLink . textContent = ( new IntlMessageFormat ( message , locale ) ) . format ( ) ;
} ) ;
[ ] . forEach . call ( document . querySelectorAll ( 'time.time-ago' ) , ( content ) => {
const datetime = new Date ( content . getAttribute ( 'datetime' ) ) ;
const now = new Date ( ) ;
const timeGiven = content . getAttribute ( 'datetime' ) . includes ( 'T' ) ;
content . title = timeGiven ? dateTimeFormat . format ( datetime ) : dateFormat . format ( datetime ) ;
content . textContent = timeAgoString ( {
formatMessage ,
formatDate : ( date , options ) => ( new Intl . DateTimeFormat ( locale , options ) ) . format ( date ) ,
} , datetime , now , now . getFullYear ( ) , timeGiven ) ;
} ) ;
const toggleSidebar = ( ) => {
const sidebar = document . querySelector ( '.sidebar ul' ) ;
const toggleButton = document . querySelector ( '.sidebar__toggle__icon' ) ;
const reactComponents = document . querySelectorAll ( '[data-component]' ) ;
if ( sidebar . classList . contains ( 'visible' ) ) {
document . body . style . overflow = null ;
toggleButton . setAttribute ( 'aria-expanded' , 'false' ) ;
if ( reactComponents . length > 0 ) {
import ( /* webpackChunkName: "containers/media_container" */ '../mastodon/containers/media_container' )
. then ( ( { default : MediaContainer } ) => {
[ ] . forEach . call ( reactComponents , ( component ) => {
[ ] . forEach . call ( component . children , ( child ) => {
component . removeChild ( child ) ;
} ) ;
} ) ;
const content = document . createElement ( 'div' ) ;
const root = createRoot ( content ) ;
root . render ( < MediaContainer locale = { locale } components = { reactComponents } / > ) ;
document . body . appendChild ( content ) ;
scrollToDetailedStatus ( ) ;
} )
. catch ( error => {
console . error ( error ) ;
scrollToDetailedStatus ( ) ;
} ) ;
} else {
scrollToDetailedStatus ( ) ;
}
delegate ( document , '#user_account_attributes_username' , 'input' , throttle ( ( ) => {
const username = document . getElementById ( 'user_account_attributes_username' ) ;
if ( username . value && username . value . length > 0 ) {
axios . get ( '/api/v1/accounts/lookup' , { params : { acct : username . value } } ) . then ( ( ) => {
username . setCustomValidity ( formatMessage ( messages . usernameTaken ) ) ;
} ) . catch ( ( ) => {
username . setCustomValidity ( '' ) ;
} ) ;
} else {
document . body . style . overflow = 'hidden' ;
toggleButton . setAttribute ( 'aria-expanded' , 'true' ) ;
username . setCustomValidity ( '' ) ;
}
} , 500 , { leading : false , trailing : true } ) ) ;
toggleButton . classList . toggle ( 'active' ) ;
sidebar . classList . toggle ( 'visible' ) ;
} ;
delegate ( document , '#user_password,#user_password_confirmation' , 'input' , ( ) => {
const password = document . getElementById ( 'user_password' ) ;
const confirmation = document . getElementById ( 'user_password_confirmation' ) ;
if ( ! confirmation ) return ;
delegate ( document , '.sidebar__toggle__icon' , 'click' , ( ) => {
toggleSidebar ( ) ;
if ( confirmation . value && confirmation . value . length > password . maxLength ) {
confirmation . setCustomValidity ( formatMessage ( messages . passwordExceedsLength ) ) ;
} else if ( password . value && password . value !== confirmation . value ) {
confirmation . setCustomValidity ( formatMessage ( messages . passwordDoesNotMatch ) ) ;
} else {
confirmation . setCustomValidity ( '' ) ;
}
} ) ;
delegate ( document , '.sidebar__toggle__icon' , 'keydown' , e => {
if ( e . key === ' ' || e . key === 'Enter' ) {
e . preventDefault ( ) ;
toggleSidebar ( ) ;
delegate ( document , '.custom-emoji' , 'mouseover' , getEmojiAnimationHandler ( 'data-original' ) ) ;
delegate ( document , '.custom-emoji' , 'mouseout' , getEmojiAnimationHandler ( 'data-static' ) ) ;
delegate ( document , '.status__content__spoiler-link' , 'click' , function ( ) {
const statusEl = this . parentNode . parentNode ;
if ( statusEl . dataset . spoiler === 'expanded' ) {
statusEl . dataset . spoiler = 'folded' ;
this . textContent = ( new IntlMessageFormat ( localeData [ 'status.show_more' ] || 'Show more' , locale ) ) . format ( ) ;
} else {
statusEl . dataset . spoiler = 'expanded' ;
this . textContent = ( new IntlMessageFormat ( localeData [ 'status.show_less' ] || 'Show less' , locale ) ) . format ( ) ;
}
return false ;
} ) ;
/ / E m p t y t h e h o n e y p o t f i e l d s i n J S i n c a s e s o m e t h i n g l i k e a n e x t e n s i o n
/ / a u t o m a t i c a l l y f i l l e d t h e m .
delegate ( document , '#registration_new_user,#new_user' , 'submit' , ( ) => {
[ 'user_website' , 'user_confirm_password' , 'registration_user_website' , 'registration_user_confirm_password' ] . forEach ( id => {
const field = document . getElementById ( id ) ;
if ( field ) {
field . value = '' ;
}
} ) ;
[ ] . forEach . call ( document . querySelectorAll ( '.status__content__spoiler-link' ) , ( spoilerLink ) => {
const statusEl = spoilerLink . parentNode . parentNode ;
const message = ( statusEl . dataset . spoiler === 'expanded' ) ? ( localeData [ 'status.show_less' ] || 'Show less' ) : ( localeData [ 'status.show_more' ] || 'Show more' ) ;
spoilerLink . textContent = ( new IntlMessageFormat ( message , locale ) ) . format ( ) ;
} ) ;
}
const toggleSidebar = ( ) => {
const sidebar = document . querySelector ( '.sidebar ul' ) ;
const toggleButton = document . querySelector ( '.sidebar__toggle__icon' ) ;
if ( sidebar . classList . contains ( 'visible' ) ) {
document . body . style . overflow = null ;
toggleButton . setAttribute ( 'aria-expanded' , 'false' ) ;
} else {
document . body . style . overflow = 'hidden' ;
toggleButton . setAttribute ( 'aria-expanded' , 'true' ) ;
}
toggleButton . classList . toggle ( 'active' ) ;
sidebar . classList . toggle ( 'visible' ) ;
} ;
delegate ( document , '.sidebar__toggle__icon' , 'click' , ( ) => {
toggleSidebar ( ) ;
} ) ;
delegate ( document , '.sidebar__toggle__icon' , 'keydown' , e => {
if ( e . key === ' ' || e . key === 'Enter' ) {
e . preventDefault ( ) ;
toggleSidebar ( ) ;
}
} ) ;
/ / E m p t y t h e h o n e y p o t f i e l d s i n J S i n c a s e s o m e t h i n g l i k e a n e x t e n s i o n
/ / a u t o m a t i c a l l y f i l l e d t h e m .
delegate ( document , '#registration_new_user,#new_user' , 'submit' , ( ) => {
[ 'user_website' , 'user_confirm_password' , 'registration_user_website' , 'registration_user_confirm_password' ] . forEach ( id => {
const field = document . getElementById ( id ) ;
if ( field ) {
field . value = '' ;
}
} ) ;
} ) ;
function main ( ) {
ready ( loaded ) ;