1 import escapeTextContentForBrowser
from 'escape-html';
2 import loadPolyfills
from '../mastodon/load_polyfills';
3 import ready
from '../mastodon/ready';
4 import { start
} from '../mastodon/common';
5 import loadKeyboardExtensions
from '../mastodon/load_keyboard_extensions';
9 window
.addEventListener('message', e
=> {
10 const data
= e
.data
|| {};
12 if (!window
.parent
|| data
.type
!== 'setHeight') {
17 window
.parent
.postMessage({
20 height: document
.getElementsByTagName('html')[0].scrollHeight
,
26 const IntlMessageFormat
= require('intl-messageformat').default;
27 const { timeAgoString
} = require('../mastodon/components/relative_timestamp');
28 const { delegate
} = require('rails-ujs');
29 const emojify
= require('../mastodon/features/emoji/emoji').default;
30 const { getLocale
} = require('../mastodon/locales');
31 const { messages
} = getLocale();
32 const React
= require('react');
33 const ReactDOM
= require('react-dom');
34 const Rellax
= require('rellax');
35 const { createBrowserHistory
} = require('history');
37 const scrollToDetailedStatus
= () => {
38 const history
= createBrowserHistory();
39 const detailedStatuses
= document
.querySelectorAll('.public-layout .detailed-status');
40 const location
= history
.location
;
42 if (detailedStatuses
.length
=== 1 && (!location
.state
|| !location
.state
.scrolledToDetailedStatus
)) {
43 detailedStatuses
[0].scrollIntoView();
44 history
.replace(location
.pathname
, { ...location
.state
, scrolledToDetailedStatus: true });
48 const getEmojiAnimationHandler
= (swapTo
) => {
49 return ({ target
}) => {
50 target
.src
= target
.getAttribute(swapTo
);
55 const locale
= document
.documentElement
.lang
;
57 const dateTimeFormat
= new Intl
.DateTimeFormat(locale
, {
65 [].forEach
.call(document
.querySelectorAll('.emojify'), (content
) => {
66 content
.innerHTML
= emojify(content
.innerHTML
);
69 [].forEach
.call(document
.querySelectorAll('time.formatted'), (content
) => {
70 const datetime
= new Date(content
.getAttribute('datetime'));
71 const formattedDate
= dateTimeFormat
.format(datetime
);
73 content
.title
= formattedDate
;
74 content
.textContent
= formattedDate
;
77 [].forEach
.call(document
.querySelectorAll('time.time-ago'), (content
) => {
78 const datetime
= new Date(content
.getAttribute('datetime'));
79 const now
= new Date();
81 content
.title
= dateTimeFormat
.format(datetime
);
82 content
.textContent
= timeAgoString({
83 formatMessage: ({ id
, defaultMessage
}, values
) => (new IntlMessageFormat(messages
[id
] || defaultMessage
, locale
)).format(values
),
84 formatDate: (date
, options
) => (new Intl
.DateTimeFormat(locale
, options
)).format(date
),
85 }, datetime
, now
, now
.getFullYear());
88 const reactComponents
= document
.querySelectorAll('[data-component]');
90 if (reactComponents
.length
> 0) {
91 import(/* webpackChunkName: "containers/media_container" */ '../mastodon/containers/media_container')
92 .then(({ default: MediaContainer
}) => {
93 [].forEach
.call(reactComponents
, (component
) => {
94 [].forEach
.call(component
.children
, (child
) => {
95 component
.removeChild(child
);
99 const content
= document
.createElement('div');
101 ReactDOM
.render(<MediaContainer locale
={locale
} components
={reactComponents
} />, content
);
102 document
.body
.appendChild(content
);
103 scrollToDetailedStatus();
106 console
.error(error
);
107 scrollToDetailedStatus();
110 scrollToDetailedStatus();
113 const parallaxComponents
= document
.querySelectorAll('.parallax');
115 if (parallaxComponents
.length
> 0 ) {
116 new Rellax('.parallax', { speed: -1 });
119 delegate(document
, '.custom-emoji', 'mouseover', getEmojiAnimationHandler('data-original'));
120 delegate(document
, '.custom-emoji', 'mouseout', getEmojiAnimationHandler('data-static'));
123 delegate(document
, '.webapp-btn', 'click', ({ target
, button
}) => {
127 window
.location
.href
= target
.href
;
131 delegate(document
, '.status__content__spoiler-link', 'click', function() {
132 const contentEl
= this.parentNode
.parentNode
.querySelector('.e-content');
134 if (contentEl
.style
.display
=== 'block') {
135 contentEl
.style
.display
= 'none';
136 this.parentNode
.style
.marginBottom
= 0;
138 contentEl
.style
.display
= 'block';
139 this.parentNode
.style
.marginBottom
= null;
145 delegate(document
, '.modal-button', 'click', e
=> {
150 if (e
.target
.nodeName
!== 'A') {
151 href
= e
.target
.parentNode
.href
;
153 href
= e
.target
.href
;
156 window
.open(href
, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');
159 delegate(document
, '#account_display_name', 'input', ({ target
}) => {
160 const name
= document
.querySelector('.card .display-name strong');
163 name
.innerHTML
= emojify(escapeTextContentForBrowser(target
.value
));
165 name
.textContent
= document
.querySelector('#default_account_display_name').textContent
;
170 delegate(document
, '#account_avatar', 'change', ({ target
}) => {
171 const avatar
= document
.querySelector('.card .avatar img');
172 const [file
] = target
.files
|| [];
173 const url
= file
? URL
.createObjectURL(file
) : avatar
.dataset
.originalSrc
;
178 const getProfileAvatarAnimationHandler
= (swapTo
) => {
179 //animate avatar gifs on the profile page when moused over
180 return ({ target
}) => {
181 const swapSrc
= target
.getAttribute(swapTo
);
182 //only change the img source if autoplay is off and the image src is actually different
183 if(target
.getAttribute('data-autoplay') !== 'true' && target
.src
!== swapSrc
) {
184 target
.src
= swapSrc
;
189 delegate(document
, 'img#profile_page_avatar', 'mouseover', getProfileAvatarAnimationHandler('data-original'));
191 delegate(document
, 'img#profile_page_avatar', 'mouseout', getProfileAvatarAnimationHandler('data-static'));
193 delegate(document
, '#account_header', 'change', ({ target
}) => {
194 const header
= document
.querySelector('.card .card__img img');
195 const [file
] = target
.files
|| [];
196 const url
= file
? URL
.createObjectURL(file
) : header
.dataset
.originalSrc
;
201 delegate(document
, '#account_locked', 'change', ({ target
}) => {
202 const lock
= document
.querySelector('.card .display-name i');
204 if (target
.checked
) {
205 lock
.style
.display
= 'inline';
207 lock
.style
.display
= 'none';
211 delegate(document
, '.input-copy input', 'click', ({ target
}) => {
214 target
.setSelectionRange(0, target
.value
.length
);
217 delegate(document
, '.input-copy button', 'click', ({ target
}) => {
218 const input
= target
.parentNode
.querySelector('.input-copy__wrapper input');
220 const oldReadOnly
= input
.readonly
;
222 input
.readonly
= false;
225 input
.setSelectionRange(0, input
.value
.length
);
228 if (document
.execCommand('copy')) {
230 target
.parentNode
.classList
.add('copied');
233 target
.parentNode
.classList
.remove('copied');
240 input
.readonly
= oldReadOnly
;
243 delegate(document
, '.sidebar__toggle__icon', 'click', () => {
244 const target
= document
.querySelector('.sidebar ul');
246 if (target
.style
.display
=== 'block') {
247 target
.style
.display
= 'none';
249 target
.style
.display
= 'block';
256 .then(loadKeyboardExtensions
)
258 console
.error(error
);