2020-10-13 02:19:35 +03:00
import './public-path' ;
2017-11-21 08:13:37 +02:00
import loadPolyfills from '../mastodon/load_polyfills' ;
import ready from '../mastodon/ready' ;
2018-07-14 04:56:41 +03:00
import { start } from '../mastodon/common' ;
2019-11-04 14:03:09 +02:00
import loadKeyboardExtensions from '../mastodon/load_keyboard_extensions' ;
2018-07-14 04:56:41 +03:00
start ( ) ;
2017-11-21 08:13:37 +02:00
function main ( ) {
2018-07-28 20:25:33 +03:00
const IntlMessageFormat = require ( 'intl-messageformat' ) . default ;
const { timeAgoString } = require ( '../mastodon/components/relative_timestamp' ) ;
2020-03-21 04:14:50 +02:00
const { delegate } = require ( '@rails/ujs' ) ;
2017-11-21 08:13:37 +02:00
const emojify = require ( '../mastodon/features/emoji/emoji' ) . default ;
const { getLocale } = require ( '../mastodon/locales' ) ;
2018-07-28 20:25:33 +03:00
const { messages } = getLocale ( ) ;
2017-11-21 08:13:37 +02:00
const React = require ( 'react' ) ;
const ReactDOM = require ( 'react-dom' ) ;
2018-07-28 20:25:33 +03:00
const Rellax = require ( 'rellax' ) ;
2019-09-18 16:41:50 +03:00
const { createBrowserHistory } = require ( 'history' ) ;
2017-11-21 08:13:37 +02:00
2019-01-10 16:13:30 +02:00
const scrollToDetailedStatus = ( ) => {
2019-09-18 16:41:50 +03:00
const history = createBrowserHistory ( ) ;
2019-01-10 16:13:30 +02:00
const detailedStatuses = document . querySelectorAll ( '.public-layout .detailed-status' ) ;
const location = history . location ;
if ( detailedStatuses . length === 1 && ( ! location . state || ! location . state . scrolledToDetailedStatus ) ) {
detailedStatuses [ 0 ] . scrollIntoView ( ) ;
history . replace ( location . pathname , { ... location . state , scrolledToDetailedStatus : true } ) ;
}
} ;
2019-07-21 19:10:40 +03:00
const getEmojiAnimationHandler = ( swapTo ) => {
return ( { target } ) => {
target . src = target . getAttribute ( swapTo ) ;
} ;
} ;
2017-11-21 08:13:37 +02:00
ready ( ( ) => {
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 ) ;
} ) ;
[ ] . forEach . call ( document . querySelectorAll ( 'time.formatted' ) , ( content ) => {
const datetime = new Date ( content . getAttribute ( 'datetime' ) ) ;
const formattedDate = dateTimeFormat . format ( datetime ) ;
content . title = formattedDate ;
content . textContent = formattedDate ;
} ) ;
[ ] . forEach . call ( document . querySelectorAll ( 'time.time-ago' ) , ( content ) => {
const datetime = new Date ( content . getAttribute ( 'datetime' ) ) ;
2018-07-28 20:25:33 +03:00
const now = new Date ( ) ;
2017-11-21 08:13:37 +02:00
content . title = dateTimeFormat . format ( datetime ) ;
2018-07-28 20:25:33 +03:00
content . textContent = timeAgoString ( {
formatMessage : ( { id , defaultMessage } , values ) => ( new IntlMessageFormat ( messages [ id ] || defaultMessage , locale ) ) . format ( values ) ,
formatDate : ( date , options ) => ( new Intl . DateTimeFormat ( locale , options ) ) . format ( date ) ,
2020-02-03 18:48:56 +02:00
} , datetime , now , now . getFullYear ( ) , content . getAttribute ( 'datetime' ) . includes ( 'T' ) ) ;
2017-11-21 08:13:37 +02:00
} ) ;
2018-05-12 16:30:06 +03:00
const reactComponents = document . querySelectorAll ( '[data-component]' ) ;
2018-09-18 17:45:58 +03:00
2018-05-12 16:30:06 +03:00
if ( reactComponents . length > 0 ) {
import ( /* webpackChunkName: "containers/media_container" */ '../mastodon/containers/media_container' )
. then ( ( { default : MediaContainer } ) => {
2019-01-13 11:23:54 +02:00
[ ] . forEach . call ( reactComponents , ( component ) => {
[ ] . forEach . call ( component . children , ( child ) => {
component . removeChild ( child ) ;
} ) ;
} ) ;
2018-05-12 16:30:06 +03:00
const content = document . createElement ( 'div' ) ;
2018-03-24 13:52:26 +02:00
2018-05-12 16:30:06 +03:00
ReactDOM . render ( < MediaContainer locale = { locale } components = { reactComponents } / > , content ) ;
document . body . appendChild ( content ) ;
2019-01-10 16:13:30 +02:00
scrollToDetailedStatus ( ) ;
2018-05-12 16:30:06 +03:00
} )
2019-01-10 16:13:30 +02:00
. catch ( error => {
console . error ( error ) ;
scrollToDetailedStatus ( ) ;
} ) ;
} else {
scrollToDetailedStatus ( ) ;
2018-03-24 13:52:26 +02:00
}
2018-07-28 20:25:33 +03:00
2018-08-26 02:19:13 +03:00
const parallaxComponents = document . querySelectorAll ( '.parallax' ) ;
2018-09-18 17:45:58 +03:00
2018-08-26 02:19:13 +03:00
if ( parallaxComponents . length > 0 ) {
new Rellax ( '.parallax' , { speed : - 1 } ) ;
}
2019-07-21 19:10:40 +03:00
2020-08-12 00:09:13 +03:00
delegate ( document , '#registration_user_password_confirmation,#registration_user_password' , 'input' , ( ) => {
const password = document . getElementById ( 'registration_user_password' ) ;
const confirmation = document . getElementById ( 'registration_user_password_confirmation' ) ;
2021-12-05 22:49:50 +02:00
if ( confirmation . value && confirmation . value . length > password . maxLength ) {
confirmation . setCustomValidity ( ( new IntlMessageFormat ( messages [ 'password_confirmation.exceeds_maxlength' ] || 'Password confirmation exceeds the maximum password length' , locale ) ) . format ( ) ) ;
} else if ( password . value && password . value !== confirmation . value ) {
2020-08-12 00:09:13 +03:00
confirmation . setCustomValidity ( ( new IntlMessageFormat ( messages [ 'password_confirmation.mismatching' ] || 'Password confirmation does not match' , locale ) ) . format ( ) ) ;
} else {
confirmation . setCustomValidity ( '' ) ;
}
} ) ;
2020-08-12 13:11:15 +03:00
delegate ( document , '#user_password,#user_password_confirmation' , 'input' , ( ) => {
const password = document . getElementById ( 'user_password' ) ;
const confirmation = document . getElementById ( 'user_password_confirmation' ) ;
if ( ! confirmation ) return ;
2021-12-05 22:49:50 +02:00
if ( confirmation . value && confirmation . value . length > password . maxLength ) {
confirmation . setCustomValidity ( ( new IntlMessageFormat ( messages [ 'password_confirmation.exceeds_maxlength' ] || 'Password confirmation exceeds the maximum password length' , locale ) ) . format ( ) ) ;
} else if ( password . value && password . value !== confirmation . value ) {
2020-08-12 13:11:15 +03:00
confirmation . setCustomValidity ( ( new IntlMessageFormat ( messages [ 'password_confirmation.mismatching' ] || 'Password confirmation does not match' , locale ) ) . format ( ) ) ;
} else {
confirmation . setCustomValidity ( '' ) ;
}
} ) ;
2019-07-21 19:10:40 +03:00
delegate ( document , '.custom-emoji' , 'mouseover' , getEmojiAnimationHandler ( 'data-original' ) ) ;
delegate ( document , '.custom-emoji' , 'mouseout' , getEmojiAnimationHandler ( 'data-static' ) ) ;
2020-04-05 15:02:22 +03:00
delegate ( document , '.status__content__spoiler-link' , 'click' , function ( ) {
2020-04-28 11:16:55 +03:00
const statusEl = this . parentNode . parentNode ;
2020-04-05 15:02:22 +03:00
2020-04-28 11:16:55 +03:00
if ( statusEl . dataset . spoiler === 'expanded' ) {
statusEl . dataset . spoiler = 'folded' ;
2020-04-05 15:02:22 +03:00
this . textContent = ( new IntlMessageFormat ( messages [ 'status.show_more' ] || 'Show more' , locale ) ) . format ( ) ;
} else {
2020-04-28 11:16:55 +03:00
statusEl . dataset . spoiler = 'expanded' ;
2020-04-05 15:02:22 +03:00
this . textContent = ( new IntlMessageFormat ( messages [ 'status.show_less' ] || 'Show less' , locale ) ) . format ( ) ;
}
return false ;
} ) ;
[ ] . forEach . call ( document . querySelectorAll ( '.status__content__spoiler-link' ) , ( spoilerLink ) => {
2020-04-28 11:16:55 +03:00
const statusEl = spoilerLink . parentNode . parentNode ;
const message = ( statusEl . dataset . spoiler === 'expanded' ) ? ( messages [ 'status.show_less' ] || 'Show less' ) : ( messages [ 'status.show_more' ] || 'Show more' ) ;
2020-04-05 15:02:22 +03:00
spoilerLink . textContent = ( new IntlMessageFormat ( message , locale ) ) . format ( ) ;
} ) ;
2017-11-21 08:13:37 +02:00
} ) ;
2019-09-20 11:52:14 +03:00
delegate ( document , '.sidebar__toggle__icon' , 'click' , ( ) => {
2022-02-16 22:44:19 +02:00
document . querySelector ( '.sidebar ul' ) . classList . toggle ( 'visible' ) ;
2019-09-20 11:52:14 +03:00
} ) ;
2020-12-10 07:27:26 +02:00
// Empty the honeypot fields in JS in case something like an extension
// automatically filled them.
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 = '' ;
}
} ) ;
} ) ;
2017-11-21 08:13:37 +02:00
}
2019-11-04 14:03:09 +02:00
loadPolyfills ( )
. then ( main )
. then ( loadKeyboardExtensions )
. catch ( error => {
console . error ( error ) ;
} ) ;