chore: update standard to v13 (#1370)

This commit is contained in:
Nolan Lawson 2019-08-03 13:49:37 -07:00 committed by GitHub
parent b034b60145
commit 00945a3608
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
274 changed files with 1472 additions and 1422 deletions

View File

@ -13,9 +13,9 @@ const writeFile = promisify(fs.writeFile)
const themeColors = fromPairs(themes.map(_ => ([_.name, _.color]))) const themeColors = fromPairs(themes.map(_ => ([_.name, _.color])))
export async function buildInlineScript () { export async function buildInlineScript () {
let inlineScriptPath = path.join(__dirname, '../src/inline-script/inline-script.js') const inlineScriptPath = path.join(__dirname, '../src/inline-script/inline-script.js')
let bundle = await rollup({ const bundle = await rollup({
input: inlineScriptPath, input: inlineScriptPath,
plugins: [ plugins: [
replace({ replace({
@ -28,15 +28,15 @@ export async function buildInlineScript () {
}) })
] ]
}) })
let { output } = await bundle.generate({ const { output } = await bundle.generate({
format: 'iife', format: 'iife',
sourcemap: true sourcemap: true
}) })
let { code, map } = output[0] const { code, map } = output[0]
let fullCode = `${code}//# sourceMappingURL=/inline-script.js.map` const fullCode = `${code}//# sourceMappingURL=/inline-script.js.map`
let checksum = crypto.createHash('sha256').update(fullCode).digest('base64') const checksum = crypto.createHash('sha256').update(fullCode).digest('base64')
await writeFile(path.resolve(__dirname, '../src/inline-script/checksum.js'), await writeFile(path.resolve(__dirname, '../src/inline-script/checksum.js'),
`module.exports = ${JSON.stringify(checksum)}`, 'utf8') `module.exports = ${JSON.stringify(checksum)}`, 'utf8')

View File

@ -13,42 +13,42 @@ import { sapperInlineScriptChecksums } from '../src/server/sapperInlineScriptChe
const writeFile = promisify(fs.writeFile) const writeFile = promisify(fs.writeFile)
const JSON_TEMPLATE = { const JSON_TEMPLATE = {
'version': 2, version: 2,
'env': { env: {
'NODE_ENV': 'production' NODE_ENV: 'production'
}, },
'builds': [ builds: [
{ {
'src': 'package.json', src: 'package.json',
'use': '@now/static-build', use: '@now/static-build',
'config': { config: {
'distDir': '__sapper__/export' distDir: '__sapper__/export'
} }
} }
], ],
'routes': [ routes: [
{ {
'src': '^/service-worker\\.js$', src: '^/service-worker\\.js$',
'headers': { headers: {
'cache-control': 'public,max-age=0' 'cache-control': 'public,max-age=0'
} }
}, },
{ {
'src': '^/(report\\.html|stats\\.json)$', src: '^/(report\\.html|stats\\.json)$',
'headers': { headers: {
'cache-control': 'public,max-age=3600' 'cache-control': 'public,max-age=3600'
}, },
'dest': 'client/$1' dest: 'client/$1'
}, },
{ {
'src': '^/client/.*\\.(js|css|map)$', src: '^/client/.*\\.(js|css|map)$',
'headers': { headers: {
'cache-control': 'public,max-age=31536000,immutable' 'cache-control': 'public,max-age=31536000,immutable'
} }
}, },
{ {
'src': '^/.*\\.(png|css|json|svg|jpe?g|map|txt)$', src: '^/.*\\.(png|css|json|svg|jpe?g|map|txt)$',
'headers': { headers: {
'cache-control': 'public,max-age=3600' 'cache-control': 'public,max-age=3600'
} }
} }
@ -69,21 +69,21 @@ const HTML_HEADERS = {
} }
async function main () { async function main () {
let json = cloneDeep(JSON_TEMPLATE) const json = cloneDeep(JSON_TEMPLATE)
let exportDir = path.resolve(__dirname, '../__sapper__/export') const exportDir = path.resolve(__dirname, '../__sapper__/export')
for (let { pattern } of routes) { for (const { pattern } of routes) {
let route = { const route = {
src: pattern.source, src: pattern.source,
headers: cloneDeep(HTML_HEADERS) headers: cloneDeep(HTML_HEADERS)
} }
// remove all the regexy stuff in the regex // remove all the regexy stuff in the regex
let filename = pattern.source.replace(/^\^\\\//, '').replace(/(\\\/)?\?\$$/, '').replace(/\\\//g, '/') const filename = pattern.source.replace(/^\^\\\//, '').replace(/(\\\/)?\?\$$/, '').replace(/\\\//g, '/')
// try two different possible paths // try two different possible paths
let filePath = [ const filePath = [
`${filename}.html`, `${filename}.html`,
path.join(filename, 'index.html') path.join(filename, 'index.html')
].map(_ => path.resolve(exportDir, _)).find(_ => fs.existsSync(_)) ].map(_ => path.resolve(exportDir, _)).find(_ => fs.existsSync(_))

View File

@ -20,24 +20,24 @@ async function renderCss (file) {
} }
async function compileGlobalSass () { async function compileGlobalSass () {
let mainStyle = (await Promise.all([defaultThemeScss, globalScss].map(renderCss))).join('') const mainStyle = (await Promise.all([defaultThemeScss, globalScss].map(renderCss))).join('')
let scrollbarStyle = (await renderCss(customScrollbarScss)) const scrollbarStyle = (await renderCss(customScrollbarScss))
return `<style>\n${mainStyle}</style>\n` + return `<style>\n${mainStyle}</style>\n` +
`<style media="all" id="theScrollbarStyle">\n${scrollbarStyle}</style>\n` `<style media="all" id="theScrollbarStyle">\n${scrollbarStyle}</style>\n`
} }
async function compileThemesSass () { async function compileThemesSass () {
let files = (await readdir(themesScssDir)).filter(file => !path.basename(file).startsWith('_')) const files = (await readdir(themesScssDir)).filter(file => !path.basename(file).startsWith('_'))
await Promise.all(files.map(async file => { await Promise.all(files.map(async file => {
let css = await renderCss(path.join(themesScssDir, file)) let css = await renderCss(path.join(themesScssDir, file))
css = cssDedoupe(new TextDecoder('utf-8').decode(css)) // remove duplicate custom properties css = cssDedoupe(new TextDecoder('utf-8').decode(css)) // remove duplicate custom properties
let outputFilename = 'theme-' + path.basename(file).replace(/\.scss$/, '.css') const outputFilename = 'theme-' + path.basename(file).replace(/\.scss$/, '.css')
await writeFile(path.join(assetsDir, outputFilename), css, 'utf8') await writeFile(path.join(assetsDir, outputFilename), css, 'utf8')
})) }))
} }
export async function buildSass () { export async function buildSass () {
let [ result ] = await Promise.all([compileGlobalSass(), compileThemesSass()]) const [result] = await Promise.all([compileGlobalSass(), compileThemesSass()])
return result return result
} }

View File

@ -10,12 +10,12 @@ const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile) const writeFile = promisify(fs.writeFile)
async function readSvg (svg) { async function readSvg (svg) {
let filepath = path.join(__dirname, '../', svg.src) const filepath = path.join(__dirname, '../', svg.src)
let content = await readFile(filepath, 'utf8') const content = await readFile(filepath, 'utf8')
let optimized = (await svgo.optimize(content)) const optimized = (await svgo.optimize(content))
let $optimized = $(optimized.data) const $optimized = $(optimized.data)
let $path = $optimized.find('path').removeAttr('fill') const $path = $optimized.find('path').removeAttr('fill')
let $symbol = $('<symbol></symbol>') const $symbol = $('<symbol></symbol>')
.attr('id', svg.id) .attr('id', svg.id)
.attr('viewBox', `0 0 ${optimized.info.width} ${optimized.info.height}`) .attr('viewBox', `0 0 ${optimized.info.width} ${optimized.info.height}`)
.append($path) .append($path)
@ -23,14 +23,14 @@ async function readSvg (svg) {
} }
export async function buildSvg () { export async function buildSvg () {
let inlineSvgs = svgs.filter(_ => _.inline) const inlineSvgs = svgs.filter(_ => _.inline)
let regularSvgs = svgs.filter(_ => !_.inline) const regularSvgs = svgs.filter(_ => !_.inline)
let inlineSvgStrings = (await Promise.all(inlineSvgs.map(readSvg))).join('') const inlineSvgStrings = (await Promise.all(inlineSvgs.map(readSvg))).join('')
let regularSvgStrings = (await Promise.all(regularSvgs.map(readSvg))).join('') const regularSvgStrings = (await Promise.all(regularSvgs.map(readSvg))).join('')
let inlineOutput = `<svg xmlns="http://www.w3.org/2000/svg" style="display:none">${inlineSvgStrings}</svg>` const inlineOutput = `<svg xmlns="http://www.w3.org/2000/svg" style="display:none">${inlineSvgStrings}</svg>`
let regularOutput = `<svg xmlns="http://www.w3.org/2000/svg">${regularSvgStrings}</svg>` const regularOutput = `<svg xmlns="http://www.w3.org/2000/svg">${regularSvgStrings}</svg>`
await writeFile(path.resolve(__dirname, '../static/icons.svg'), regularOutput, 'utf8') await writeFile(path.resolve(__dirname, '../static/icons.svg'), regularOutput, 'utf8')

View File

@ -34,17 +34,17 @@ const builders = [
const partials = buildPartials() const partials = buildPartials()
function buildPartials () { function buildPartials () {
let rawTemplate = fs.readFileSync(path.resolve(__dirname, '../src/build/template.html'), 'utf8') const rawTemplate = fs.readFileSync(path.resolve(__dirname, '../src/build/template.html'), 'utf8')
let partials = [rawTemplate] const partials = [rawTemplate]
builders.forEach(builder => { builders.forEach(builder => {
for (let i = 0; i < partials.length; i++) { for (let i = 0; i < partials.length; i++) {
let partial = partials[i] const partial = partials[i]
if (typeof partial !== 'string') { if (typeof partial !== 'string') {
continue continue
} }
let idx = partial.indexOf(builder.comment) const idx = partial.indexOf(builder.comment)
if (idx !== -1) { if (idx !== -1) {
partials.splice( partials.splice(
i, i,
@ -77,8 +77,8 @@ function doWatch () {
} }
async function buildAll () { async function buildAll () {
let start = now() const start = now()
let html = (await Promise.all(partials.map(async partial => { const html = (await Promise.all(partials.map(async partial => {
if (typeof partial === 'string') { if (typeof partial === 'string') {
return partial return partial
} }
@ -89,7 +89,7 @@ async function buildAll () {
}))).join('') }))).join('')
await writeFile(path.resolve(__dirname, '../src/template.html'), html, 'utf8') await writeFile(path.resolve(__dirname, '../src/template.html'), html, 'utf8')
let end = now() const end = now()
console.log(`Built template.html in ${(end - start).toFixed(2)}ms`) console.log(`Built template.html in ${(end - start).toFixed(2)}ms`)
} }

View File

@ -1,13 +1,13 @@
import times from 'lodash-es/times' import times from 'lodash-es/times'
function unrollThread (user, prefix, privacy, thread) { function unrollThread (user, prefix, privacy, thread) {
let res = [] const res = []
function unroll (node, parentKey) { function unroll (node, parentKey) {
if (!node) { if (!node) {
return return
} }
for (let key of Object.keys(node)) { for (const key of Object.keys(node)) {
res.push({ res.push({
user: user, user: user,
post: { post: {

View File

@ -15,24 +15,24 @@ global.fetch = fetch
export async function restoreMastodonData () { export async function restoreMastodonData () {
console.log('Restoring mastodon data...') console.log('Restoring mastodon data...')
let internalIdsToIds = {} const internalIdsToIds = {}
for (let action of actions) { for (const action of actions) {
if (!action.post) { if (!action.post) {
// If the action is a boost, favorite, etc., then it needs to // If the action is a boost, favorite, etc., then it needs to
// be delayed, otherwise it may appear in an unpredictable order and break the tests. // be delayed, otherwise it may appear in an unpredictable order and break the tests.
await new Promise(resolve => setTimeout(resolve, 1000)) await new Promise(resolve => setTimeout(resolve, 1000))
} }
console.log(JSON.stringify(action)) console.log(JSON.stringify(action))
let accessToken = users[action.user].accessToken const accessToken = users[action.user].accessToken
if (action.post) { if (action.post) {
let { text, media, sensitive, spoiler, privacy, inReplyTo, internalId } = action.post const { text, media, sensitive, spoiler, privacy, inReplyTo, internalId } = action.post
let mediaIds = media && await Promise.all(media.map(async mediaItem => { const mediaIds = media && await Promise.all(media.map(async mediaItem => {
let mediaResponse = await submitMedia(accessToken, mediaItem, 'kitten') const mediaResponse = await submitMedia(accessToken, mediaItem, 'kitten')
return mediaResponse.id return mediaResponse.id
})) }))
let inReplyToId = inReplyTo && internalIdsToIds[inReplyTo] const inReplyToId = inReplyTo && internalIdsToIds[inReplyTo]
let status = await postStatus('localhost:3000', accessToken, text, inReplyToId, mediaIds, const status = await postStatus('localhost:3000', accessToken, text, inReplyToId, mediaIds,
sensitive, spoiler, privacy || 'public') sensitive, spoiler, privacy || 'public')
if (typeof internalId !== 'undefined') { if (typeof internalId !== 'undefined') {
internalIdsToIds[internalId] = status.id internalIdsToIds[internalId] = status.id

View File

@ -66,21 +66,21 @@ async function setupMastodonDatabase () {
env: Object.assign({ PGPASSWORD: DB_PASS }, process.env) env: Object.assign({ PGPASSWORD: DB_PASS }, process.env)
}) })
let dumpFile = path.join(dir, '../tests/fixtures/dump.sql') const dumpFile = path.join(dir, '../tests/fixtures/dump.sql')
await exec(`psql -h 127.0.0.1 -U ${DB_USER} -w -d ${DB_NAME} -f "${dumpFile}"`, { await exec(`psql -h 127.0.0.1 -U ${DB_USER} -w -d ${DB_NAME} -f "${dumpFile}"`, {
cwd: mastodonDir, cwd: mastodonDir,
env: Object.assign({ PGPASSWORD: DB_PASS }, process.env) env: Object.assign({ PGPASSWORD: DB_PASS }, process.env)
}) })
let tgzFile = path.join(dir, '../tests/fixtures/system.tgz') const tgzFile = path.join(dir, '../tests/fixtures/system.tgz')
let systemDir = path.join(mastodonDir, 'public/system') const systemDir = path.join(mastodonDir, 'public/system')
await mkdirp(systemDir) await mkdirp(systemDir)
await exec(`tar -xzf "${tgzFile}"`, { cwd: systemDir }) await exec(`tar -xzf "${tgzFile}"`, { cwd: systemDir })
} }
async function runMastodon () { async function runMastodon () {
console.log('Running mastodon...') console.log('Running mastodon...')
let env = Object.assign({}, process.env, { const env = Object.assign({}, process.env, {
RAILS_ENV: 'development', RAILS_ENV: 'development',
NODE_ENV: 'development', NODE_ENV: 'development',
DB_NAME, DB_NAME,
@ -89,8 +89,8 @@ async function runMastodon () {
DB_HOST, DB_HOST,
DB_PORT DB_PORT
}) })
let cwd = mastodonDir const cwd = mastodonDir
let cmds = [ const cmds = [
'gem install bundler foreman', 'gem install bundler foreman',
'bundle install', 'bundle install',
'bundle exec rails db:migrate', 'bundle exec rails db:migrate',
@ -103,7 +103,7 @@ async function runMastodon () {
console.log('Already installed Mastodon') console.log('Already installed Mastodon')
} catch (e) { } catch (e) {
console.log('Installing Mastodon...') console.log('Installing Mastodon...')
for (let cmd of cmds) { for (const cmd of cmds) {
console.log(cmd) console.log(cmd)
await exec(cmd, { cwd, env }) await exec(cmd, { cwd, env })
} }

View File

@ -10,7 +10,7 @@ const numStatuses = actions
async function waitForMastodonData () { async function waitForMastodonData () {
while (true) { while (true) {
try { try {
let json = await ((await fetch('http://127.0.0.1:3000/api/v1/instance')).json()) const json = await ((await fetch('http://127.0.0.1:3000/api/v1/instance')).json())
if (json.stats.status_count === numStatuses) { if (json.stats.status_count === numStatuses) {
break break
} else { } else {

View File

@ -3,7 +3,7 @@ import fetch from 'node-fetch'
export async function waitForMastodonUiToStart () { export async function waitForMastodonUiToStart () {
while (true) { while (true) {
try { try {
let html = await ((await fetch('http://127.0.0.1:3035/packs/common.js')).text()) const html = await ((await fetch('http://127.0.0.1:3035/packs/common.js')).text())
if (html) { if (html) {
break break
} }
@ -18,7 +18,7 @@ export async function waitForMastodonUiToStart () {
export async function waitForMastodonApiToStart () { export async function waitForMastodonApiToStart () {
while (true) { while (true) {
try { try {
let json = await ((await fetch('http://127.0.0.1:3000/api/v1/instance')).json()) const json = await ((await fetch('http://127.0.0.1:3000/api/v1/instance')).json())
if (json.uri) { if (json.uri) {
break break
} }

View File

@ -109,7 +109,7 @@
"fake-indexeddb": "^2.1.1", "fake-indexeddb": "^2.1.1",
"mocha": "^6.1.4", "mocha": "^6.1.4",
"now": "^15.7.0", "now": "^15.7.0",
"standard": "^12.0.1", "standard": "^13.1.0",
"testcafe": "^1.2.1" "testcafe": "^1.2.1"
}, },
"engines": { "engines": {

View File

@ -19,8 +19,8 @@ app.use(compression({ threshold: 0 }))
app.use(express.static(exportDir, { app.use(express.static(exportDir, {
setHeaders (res, thisPath) { setHeaders (res, thisPath) {
let localPath = '/' + path.relative(exportDir, thisPath) const localPath = '/' + path.relative(exportDir, thisPath)
for (let { regex, headers } of routes) { for (const { regex, headers } of routes) {
if (regex.test(localPath)) { if (regex.test(localPath)) {
res.set(headers) res.set(headers)
return return

View File

@ -23,7 +23,7 @@ const theme = (instanceThemes && instanceThemes[currentInstance]) || DEFAULT_THE
if (currentInstance) { if (currentInstance) {
// Do preconnect if we're logged in, so we can connect faster to the other origin. // Do preconnect if we're logged in, so we can connect faster to the other origin.
let link = document.createElement('link') const link = document.createElement('link')
link.setAttribute('rel', 'preconnect') link.setAttribute('rel', 'preconnect')
link.setAttribute('href', basename(currentInstance)) link.setAttribute('href', basename(currentInstance))
link.setAttribute('crossorigin', 'anonymous') link.setAttribute('crossorigin', 'anonymous')

View File

@ -5,7 +5,7 @@ function getNotificationText (notification, omitEmojiInDisplayNames) {
if (!notification) { if (!notification) {
return return
} }
let notificationAccountDisplayName = getAccountAccessibleName(notification.account, omitEmojiInDisplayNames) const notificationAccountDisplayName = getAccountAccessibleName(notification.account, omitEmojiInDisplayNames)
if (notification.type === 'reblog') { if (notification.type === 'reblog') {
return `${notificationAccountDisplayName} boosted your status` return `${notificationAccountDisplayName} boosted your status`
} else if (notification.type === 'favourite') { } else if (notification.type === 'favourite') {
@ -14,7 +14,7 @@ function getNotificationText (notification, omitEmojiInDisplayNames) {
} }
function getPrivacyText (visibility) { function getPrivacyText (visibility) {
for (let option of POST_PRIVACY_OPTIONS) { for (const option of POST_PRIVACY_OPTIONS) {
if (option.key === visibility) { if (option.key === visibility) {
return option.label return option.label
} }
@ -25,7 +25,7 @@ function getReblogText (reblog, account, omitEmojiInDisplayNames) {
if (!reblog) { if (!reblog) {
return return
} }
let accountDisplayName = getAccountAccessibleName(account, omitEmojiInDisplayNames) const accountDisplayName = getAccountAccessibleName(account, omitEmojiInDisplayNames)
return `Boosted by ${accountDisplayName}` return `Boosted by ${accountDisplayName}`
} }
@ -37,11 +37,11 @@ export function getAccessibleLabelForStatus (originalAccount, account, plainText
timeagoFormattedDate, spoilerText, showContent, timeagoFormattedDate, spoilerText, showContent,
reblog, notification, visibility, omitEmojiInDisplayNames, reblog, notification, visibility, omitEmojiInDisplayNames,
disableLongAriaLabels) { disableLongAriaLabels) {
let originalAccountDisplayName = getAccountAccessibleName(originalAccount, omitEmojiInDisplayNames) const originalAccountDisplayName = getAccountAccessibleName(originalAccount, omitEmojiInDisplayNames)
let contentTextToShow = (showContent || !spoilerText) const contentTextToShow = (showContent || !spoilerText)
? cleanupText(plainTextContent) ? cleanupText(plainTextContent)
: `Content warning: ${cleanupText(spoilerText)}` : `Content warning: ${cleanupText(spoilerText)}`
let privacyText = getPrivacyText(visibility) const privacyText = getPrivacyText(visibility)
if (disableLongAriaLabels) { if (disableLongAriaLabels) {
// Long text can crash NVDA; allow users to shorten it like we had it before. // Long text can crash NVDA; allow users to shorten it like we had it before.
@ -49,7 +49,7 @@ export function getAccessibleLabelForStatus (originalAccount, account, plainText
return `${privacyText} status by ${originalAccountDisplayName}` return `${privacyText} status by ${originalAccountDisplayName}`
} }
let values = [ const values = [
getNotificationText(notification, omitEmojiInDisplayNames), getNotificationText(notification, omitEmojiInDisplayNames),
originalAccountDisplayName, originalAccountDisplayName,
contentTextToShow, contentTextToShow,

View File

@ -1,7 +1,7 @@
import { removeEmoji } from '../_utils/removeEmoji' import { removeEmoji } from '../_utils/removeEmoji'
export function getAccountAccessibleName (account, omitEmojiInDisplayNames) { export function getAccountAccessibleName (account, omitEmojiInDisplayNames) {
let emojis = account.emojis const emojis = account.emojis
let displayName = account.display_name || account.username let displayName = account.display_name || account.username
if (omitEmojiInDisplayNames) { if (omitEmojiInDisplayNames) {
displayName = removeEmoji(displayName, emojis) || displayName displayName = removeEmoji(displayName, emojis) || displayName

View File

@ -4,8 +4,8 @@ import { database } from '../_database/database'
import { store } from '../_store/store' import { store } from '../_store/store'
async function _updateAccount (accountId, instanceName, accessToken) { async function _updateAccount (accountId, instanceName, accessToken) {
let localPromise = database.getAccount(instanceName, accountId) const localPromise = database.getAccount(instanceName, accountId)
let remotePromise = getAccount(instanceName, accessToken, accountId).then(account => { const remotePromise = getAccount(instanceName, accessToken, accountId).then(account => {
/* no await */ database.setAccount(instanceName, account) /* no await */ database.setAccount(instanceName, account)
return account return account
}) })
@ -23,8 +23,8 @@ async function _updateAccount (accountId, instanceName, accessToken) {
} }
async function _updateRelationship (accountId, instanceName, accessToken) { async function _updateRelationship (accountId, instanceName, accessToken) {
let localPromise = database.getRelationship(instanceName, accountId) const localPromise = database.getRelationship(instanceName, accountId)
let remotePromise = getRelationship(instanceName, accessToken, accountId).then(relationship => { const remotePromise = getRelationship(instanceName, accessToken, accountId).then(relationship => {
/* no await */ database.setRelationship(instanceName, relationship) /* no await */ database.setRelationship(instanceName, relationship)
return relationship return relationship
}) })
@ -57,7 +57,7 @@ export async function clearProfileAndRelationship () {
} }
export async function updateProfileAndRelationship (accountId) { export async function updateProfileAndRelationship (accountId) {
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
await Promise.all([ await Promise.all([
_updateAccount(accountId, currentInstance, accessToken), _updateAccount(accountId, currentInstance, accessToken),
@ -66,7 +66,7 @@ export async function updateProfileAndRelationship (accountId) {
} }
export async function updateRelationship (accountId) { export async function updateRelationship (accountId) {
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
await _updateRelationship(accountId, currentInstance, accessToken) await _updateRelationship(accountId, currentInstance, accessToken)
} }

View File

@ -12,7 +12,7 @@ const REDIRECT_URI = (typeof location !== 'undefined'
? location.origin : 'https://pinafore.social') + '/settings/instances/add' ? location.origin : 'https://pinafore.social') + '/settings/instances/add'
function createKnownError (message) { function createKnownError (message) {
let err = new Error(message) const err = new Error(message)
err.knownError = true err.knownError = true
return err return err
} }
@ -23,20 +23,20 @@ async function redirectToOauth () {
if (Object.keys(loggedInInstances).includes(instanceNameInSearch)) { if (Object.keys(loggedInInstances).includes(instanceNameInSearch)) {
throw createKnownError(`You've already logged in to ${instanceNameInSearch}`) throw createKnownError(`You've already logged in to ${instanceNameInSearch}`)
} }
let instanceHostname = new URL(`http://${instanceNameInSearch}`).hostname const instanceHostname = new URL(`http://${instanceNameInSearch}`).hostname
if (DOMAIN_BLOCKS.some(domain => new RegExp(`(?:\\.|^)${domain}$`, 'i').test(instanceHostname))) { if (DOMAIN_BLOCKS.some(domain => new RegExp(`(?:\\.|^)${domain}$`, 'i').test(instanceHostname))) {
throw createKnownError('This service is blocked') throw createKnownError('This service is blocked')
} }
let registrationPromise = registerApplication(instanceNameInSearch, REDIRECT_URI) const registrationPromise = registerApplication(instanceNameInSearch, REDIRECT_URI)
let instanceInfo = await getInstanceInfo(instanceNameInSearch) const instanceInfo = await getInstanceInfo(instanceNameInSearch)
await database.setInstanceInfo(instanceNameInSearch, instanceInfo) // cache for later await database.setInstanceInfo(instanceNameInSearch, instanceInfo) // cache for later
let instanceData = await registrationPromise const instanceData = await registrationPromise
store.set({ store.set({
currentRegisteredInstanceName: instanceNameInSearch, currentRegisteredInstanceName: instanceNameInSearch,
currentRegisteredInstance: instanceData currentRegisteredInstance: instanceData
}) })
store.save() store.save()
let oauthUrl = generateAuthLink( const oauthUrl = generateAuthLink(
instanceNameInSearch, instanceNameInSearch,
instanceData.client_id, instanceData.client_id,
REDIRECT_URI REDIRECT_URI
@ -53,12 +53,12 @@ export async function logInToInstance () {
await redirectToOauth() await redirectToOauth()
} catch (err) { } catch (err) {
console.error(err) console.error(err)
let error = `${err.message || err.name}. ` + const error = `${err.message || err.name}. ` +
(err.knownError ? '' : (navigator.onLine (err.knownError ? '' : (navigator.onLine
? `Is this a valid Mastodon instance? Is a browser extension ? `Is this a valid Mastodon instance? Is a browser extension
blocking the request? Are you in private browsing mode?` blocking the request? Are you in private browsing mode?`
: `Are you offline?`)) : `Are you offline?`))
let { instanceNameInSearch } = store.get() const { instanceNameInSearch } = store.get()
store.set({ store.set({
logInToInstanceError: error, logInToInstanceError: error,
logInToInstanceErrorForText: instanceNameInSearch logInToInstanceErrorForText: instanceNameInSearch
@ -69,15 +69,15 @@ export async function logInToInstance () {
} }
async function registerNewInstance (code) { async function registerNewInstance (code) {
let { currentRegisteredInstanceName, currentRegisteredInstance } = store.get() const { currentRegisteredInstanceName, currentRegisteredInstance } = store.get()
let instanceData = await getAccessTokenFromAuthCode( const instanceData = await getAccessTokenFromAuthCode(
currentRegisteredInstanceName, currentRegisteredInstanceName,
currentRegisteredInstance.client_id, currentRegisteredInstance.client_id,
currentRegisteredInstance.client_secret, currentRegisteredInstance.client_secret,
code, code,
REDIRECT_URI REDIRECT_URI
) )
let { loggedInInstances, loggedInInstancesInOrder, instanceThemes } = store.get() const { loggedInInstances, loggedInInstancesInOrder, instanceThemes } = store.get()
instanceThemes[currentRegisteredInstanceName] = DEFAULT_THEME instanceThemes[currentRegisteredInstanceName] = DEFAULT_THEME
loggedInInstances[currentRegisteredInstanceName] = instanceData loggedInInstances[currentRegisteredInstanceName] = instanceData
if (!loggedInInstancesInOrder.includes(currentRegisteredInstanceName)) { if (!loggedInInstancesInOrder.includes(currentRegisteredInstanceName)) {
@ -93,7 +93,7 @@ async function registerNewInstance (code) {
instanceThemes: instanceThemes instanceThemes: instanceThemes
}) })
store.save() store.save()
let { enableGrayscale } = store.get() const { enableGrayscale } = store.get()
switchToTheme(DEFAULT_THEME, enableGrayscale) switchToTheme(DEFAULT_THEME, enableGrayscale)
// fire off these requests so they're cached // fire off these requests so they're cached
/* no await */ updateVerifyCredentialsForInstance(currentRegisteredInstanceName) /* no await */ updateVerifyCredentialsForInstance(currentRegisteredInstanceName)

View File

@ -8,13 +8,13 @@ import { scheduleIdleTask } from '../_utils/scheduleIdleTask'
import { timelineItemToSummary } from '../_utils/timelineItemToSummary' import { timelineItemToSummary } from '../_utils/timelineItemToSummary'
function getExistingItemIdsSet (instanceName, timelineName) { function getExistingItemIdsSet (instanceName, timelineName) {
let timelineItemSummaries = store.getForTimeline(instanceName, timelineName, 'timelineItemSummaries') || [] const timelineItemSummaries = store.getForTimeline(instanceName, timelineName, 'timelineItemSummaries') || []
return new Set(timelineItemSummaries.map(_ => _.id)) return new Set(timelineItemSummaries.map(_ => _.id))
} }
function removeDuplicates (instanceName, timelineName, updates) { function removeDuplicates (instanceName, timelineName, updates) {
// remove duplicates, including duplicates due to reblogs // remove duplicates, including duplicates due to reblogs
let existingItemIds = getExistingItemIdsSet(instanceName, timelineName) const existingItemIds = getExistingItemIdsSet(instanceName, timelineName)
return updates.filter(update => !existingItemIds.has(update.id)) return updates.filter(update => !existingItemIds.has(update.id))
} }
@ -27,12 +27,12 @@ async function insertUpdatesIntoTimeline (instanceName, timelineName, updates) {
await database.insertTimelineItems(instanceName, timelineName, updates) await database.insertTimelineItems(instanceName, timelineName, updates)
let itemSummariesToAdd = store.getForTimeline(instanceName, timelineName, 'timelineItemSummariesToAdd') || [] const itemSummariesToAdd = store.getForTimeline(instanceName, timelineName, 'timelineItemSummariesToAdd') || []
console.log('itemSummariesToAdd', JSON.parse(JSON.stringify(itemSummariesToAdd))) console.log('itemSummariesToAdd', JSON.parse(JSON.stringify(itemSummariesToAdd)))
console.log('updates.map(timelineItemToSummary)', JSON.parse(JSON.stringify(updates.map(timelineItemToSummary)))) console.log('updates.map(timelineItemToSummary)', JSON.parse(JSON.stringify(updates.map(timelineItemToSummary))))
console.log('concat(itemSummariesToAdd, updates.map(timelineItemToSummary))', console.log('concat(itemSummariesToAdd, updates.map(timelineItemToSummary))',
JSON.parse(JSON.stringify(concat(itemSummariesToAdd, updates.map(timelineItemToSummary))))) JSON.parse(JSON.stringify(concat(itemSummariesToAdd, updates.map(timelineItemToSummary)))))
let newItemSummariesToAdd = uniqBy( const newItemSummariesToAdd = uniqBy(
concat(itemSummariesToAdd, updates.map(timelineItemToSummary)), concat(itemSummariesToAdd, updates.map(timelineItemToSummary)),
_ => _.id _ => _.id
) )
@ -44,12 +44,12 @@ async function insertUpdatesIntoTimeline (instanceName, timelineName, updates) {
} }
function isValidStatusForThread (thread, timelineName, itemSummariesToAdd) { function isValidStatusForThread (thread, timelineName, itemSummariesToAdd) {
let itemSummariesToAddIdSet = new Set(itemSummariesToAdd.map(_ => _.id)) const itemSummariesToAddIdSet = new Set(itemSummariesToAdd.map(_ => _.id))
let threadIdSet = new Set(thread.map(_ => _.id)) const threadIdSet = new Set(thread.map(_ => _.id))
let focusedStatusId = timelineName.split('/')[1] // e.g. "status/123456" const focusedStatusId = timelineName.split('/')[1] // e.g. "status/123456"
let focusedStatusIdx = thread.findIndex(_ => _.id === focusedStatusId) const focusedStatusIdx = thread.findIndex(_ => _.id === focusedStatusId)
return status => { return status => {
let repliedToStatusIdx = thread.findIndex(_ => _.id === status.in_reply_to_id) const repliedToStatusIdx = thread.findIndex(_ => _.id === status.in_reply_to_id)
return ( return (
// A reply to an ancestor status is not valid for this thread, but for the focused status // A reply to an ancestor status is not valid for this thread, but for the focused status
// itself or any of its descendents, it is valid. // itself or any of its descendents, it is valid.
@ -67,17 +67,17 @@ async function insertUpdatesIntoThreads (instanceName, updates) {
return return
} }
let threads = store.getThreads(instanceName) const threads = store.getThreads(instanceName)
let timelineNames = Object.keys(threads) const timelineNames = Object.keys(threads)
for (let timelineName of timelineNames) { for (const timelineName of timelineNames) {
let thread = threads[timelineName] const thread = threads[timelineName]
let itemSummariesToAdd = store.getForTimeline(instanceName, timelineName, 'timelineItemSummariesToAdd') || [] const itemSummariesToAdd = store.getForTimeline(instanceName, timelineName, 'timelineItemSummariesToAdd') || []
let validUpdates = updates.filter(isValidStatusForThread(thread, timelineName, itemSummariesToAdd)) const validUpdates = updates.filter(isValidStatusForThread(thread, timelineName, itemSummariesToAdd))
if (!validUpdates.length) { if (!validUpdates.length) {
continue continue
} }
let newItemSummariesToAdd = uniqBy( const newItemSummariesToAdd = uniqBy(
concat(itemSummariesToAdd, validUpdates.map(timelineItemToSummary)), concat(itemSummariesToAdd, validUpdates.map(timelineItemToSummary)),
_ => _.id _ => _.id
) )
@ -91,9 +91,9 @@ async function insertUpdatesIntoThreads (instanceName, updates) {
async function processFreshUpdates (instanceName, timelineName) { async function processFreshUpdates (instanceName, timelineName) {
mark('processFreshUpdates') mark('processFreshUpdates')
let freshUpdates = store.getForTimeline(instanceName, timelineName, 'freshUpdates') const freshUpdates = store.getForTimeline(instanceName, timelineName, 'freshUpdates')
if (freshUpdates && freshUpdates.length) { if (freshUpdates && freshUpdates.length) {
let updates = freshUpdates.slice() const updates = freshUpdates.slice()
store.setForTimeline(instanceName, timelineName, { freshUpdates: [] }) store.setForTimeline(instanceName, timelineName, { freshUpdates: [] })
await Promise.all([ await Promise.all([

View File

@ -1,59 +1,59 @@
import { store } from '../_store/store' import { store } from '../_store/store'
export async function insertUsername (realm, username, startIndex, endIndex) { export async function insertUsername (realm, username, startIndex, endIndex) {
let { currentInstance } = store.get() const { currentInstance } = store.get()
let oldText = store.getComposeData(realm, 'text') const oldText = store.getComposeData(realm, 'text')
let pre = oldText.substring(0, startIndex) const pre = oldText.substring(0, startIndex)
let post = oldText.substring(endIndex) const post = oldText.substring(endIndex)
let newText = `${pre}@${username} ${post}` const newText = `${pre}@${username} ${post}`
store.setComposeData(realm, { text: newText }) store.setComposeData(realm, { text: newText })
store.setForAutosuggest(currentInstance, realm, { autosuggestSearchResults: [] }) store.setForAutosuggest(currentInstance, realm, { autosuggestSearchResults: [] })
} }
export async function clickSelectedAutosuggestionUsername (realm) { export async function clickSelectedAutosuggestionUsername (realm) {
let { const {
composeSelectionStart, composeSelectionStart,
autosuggestSearchText, autosuggestSearchText,
autosuggestSelected, autosuggestSelected,
autosuggestSearchResults autosuggestSearchResults
} = store.get() } = store.get()
let account = autosuggestSearchResults[autosuggestSelected] const account = autosuggestSearchResults[autosuggestSelected]
let startIndex = composeSelectionStart - autosuggestSearchText.length const startIndex = composeSelectionStart - autosuggestSearchText.length
let endIndex = composeSelectionStart const endIndex = composeSelectionStart
await insertUsername(realm, account.acct, startIndex, endIndex) await insertUsername(realm, account.acct, startIndex, endIndex)
} }
export function insertEmojiAtPosition (realm, emoji, startIndex, endIndex) { export function insertEmojiAtPosition (realm, emoji, startIndex, endIndex) {
let { currentInstance } = store.get() const { currentInstance } = store.get()
let oldText = store.getComposeData(realm, 'text') || '' const oldText = store.getComposeData(realm, 'text') || ''
let pre = oldText.substring(0, startIndex) const pre = oldText.substring(0, startIndex)
let post = oldText.substring(endIndex) const post = oldText.substring(endIndex)
let newText = `${pre}:${emoji.shortcode}: ${post}` const newText = `${pre}:${emoji.shortcode}: ${post}`
store.setComposeData(realm, { text: newText }) store.setComposeData(realm, { text: newText })
store.setForAutosuggest(currentInstance, realm, { autosuggestSearchResults: [] }) store.setForAutosuggest(currentInstance, realm, { autosuggestSearchResults: [] })
} }
export async function clickSelectedAutosuggestionEmoji (realm) { export async function clickSelectedAutosuggestionEmoji (realm) {
let { const {
composeSelectionStart, composeSelectionStart,
autosuggestSearchText, autosuggestSearchText,
autosuggestSelected, autosuggestSelected,
autosuggestSearchResults autosuggestSearchResults
} = store.get() } = store.get()
let emoji = autosuggestSearchResults[autosuggestSelected] const emoji = autosuggestSearchResults[autosuggestSelected]
let startIndex = composeSelectionStart - autosuggestSearchText.length const startIndex = composeSelectionStart - autosuggestSearchText.length
let endIndex = composeSelectionStart const endIndex = composeSelectionStart
await insertEmojiAtPosition(realm, emoji, startIndex, endIndex) await insertEmojiAtPosition(realm, emoji, startIndex, endIndex)
} }
export function selectAutosuggestItem (item) { export function selectAutosuggestItem (item) {
let { const {
currentComposeRealm, currentComposeRealm,
composeSelectionStart, composeSelectionStart,
autosuggestSearchText autosuggestSearchText
} = store.get() } = store.get()
let startIndex = composeSelectionStart - autosuggestSearchText.length const startIndex = composeSelectionStart - autosuggestSearchText.length
let endIndex = composeSelectionStart const endIndex = composeSelectionStart
if (item.acct) { if (item.acct) {
/* no await */ insertUsername(currentComposeRealm, item.acct, startIndex, endIndex) /* no await */ insertUsername(currentComposeRealm, item.acct, startIndex, endIndex)
} else { } else {

View File

@ -11,8 +11,8 @@ const DATABASE_SEARCH_RESULTS_LIMIT = 30
const promiseThrottler = new PromiseThrottler(200) // Mastodon FE also uses 200ms const promiseThrottler = new PromiseThrottler(200) // Mastodon FE also uses 200ms
function byUsername (a, b) { function byUsername (a, b) {
let usernameA = a.acct.toLowerCase() const usernameA = a.acct.toLowerCase()
let usernameB = b.acct.toLowerCase() const usernameB = b.acct.toLowerCase()
return usernameA < usernameB ? -1 : usernameA === usernameB ? 0 : 1 return usernameA < usernameB ? -1 : usernameA === usernameB ? 0 : 1
} }
@ -25,7 +25,7 @@ export function doAccountSearch (searchText) {
let canceled = false let canceled = false
let localResults let localResults
let remoteResults let remoteResults
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
let controller = typeof AbortController === 'function' && new AbortController() let controller = typeof AbortController === 'function' && new AbortController()
function abortFetch () { function abortFetch () {
@ -60,7 +60,7 @@ export function doAccountSearch (searchText) {
.slice(0, SEARCH_RESULTS_LIMIT) .slice(0, SEARCH_RESULTS_LIMIT)
if (results.length < SEARCH_RESULTS_LIMIT) { if (results.length < SEARCH_RESULTS_LIMIT) {
let topRemoteResults = (remoteResults || []) const topRemoteResults = (remoteResults || [])
.sort(byUsername) .sort(byUsername)
.slice(0, SEARCH_RESULTS_LIMIT - results.length) .slice(0, SEARCH_RESULTS_LIMIT - results.length)
results = concat(results, topRemoteResults) results = concat(results, topRemoteResults)
@ -74,7 +74,7 @@ export function doAccountSearch (searchText) {
if (canceled) { if (canceled) {
return return
} }
let results = mergeAndTruncateResults() const results = mergeAndTruncateResults()
store.setForCurrentAutosuggest({ store.setForCurrentAutosuggest({
autosuggestType: 'account', autosuggestType: 'account',
autosuggestSelected: 0, autosuggestSelected: 0,

View File

@ -4,8 +4,8 @@ import { scheduleIdleTask } from '../_utils/scheduleIdleTask'
function searchEmoji (searchText) { function searchEmoji (searchText) {
searchText = searchText.toLowerCase().substring(1) searchText = searchText.toLowerCase().substring(1)
let { currentCustomEmoji } = store.get() const { currentCustomEmoji } = store.get()
let results = currentCustomEmoji.filter(emoji => emoji.shortcode.toLowerCase().startsWith(searchText)) const results = currentCustomEmoji.filter(emoji => emoji.shortcode.toLowerCase().startsWith(searchText))
.sort((a, b) => a.shortcode.toLowerCase() < b.shortcode.toLowerCase() ? -1 : 1) .sort((a, b) => a.shortcode.toLowerCase() < b.shortcode.toLowerCase() ? -1 : 1)
.slice(0, SEARCH_RESULTS_LIMIT) .slice(0, SEARCH_RESULTS_LIMIT)
return results return results
@ -18,7 +18,7 @@ export function doEmojiSearch (searchText) {
if (canceled) { if (canceled) {
return return
} }
let results = searchEmoji(searchText) const results = searchEmoji(searchText)
store.setForCurrentAutosuggest({ store.setForCurrentAutosuggest({
autosuggestType: 'emoji', autosuggestType: 'emoji',
autosuggestSelected: 0, autosuggestSelected: 0,

View File

@ -5,7 +5,7 @@ import { updateLocalRelationship } from './accounts'
import { emit } from '../_utils/eventBus' import { emit } from '../_utils/eventBus'
export async function setAccountBlocked (accountId, block, toastOnSuccess) { export async function setAccountBlocked (accountId, block, toastOnSuccess) {
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
try { try {
let relationship let relationship
if (block) { if (block) {

View File

@ -7,11 +7,11 @@ import { emit } from '../_utils/eventBus'
import { putMediaMetadata } from '../_api/media' import { putMediaMetadata } from '../_api/media'
export async function insertHandleForReply (statusId) { export async function insertHandleForReply (statusId) {
let { currentInstance } = store.get() const { currentInstance } = store.get()
let status = await database.getStatus(currentInstance, statusId) const status = await database.getStatus(currentInstance, statusId)
let { currentVerifyCredentials } = store.get() const { currentVerifyCredentials } = store.get()
let originalStatus = status.reblog || status const originalStatus = status.reblog || status
let accounts = [originalStatus.account].concat(originalStatus.mentions || []) const accounts = [originalStatus.account].concat(originalStatus.mentions || [])
.filter(account => account.id !== currentVerifyCredentials.id) .filter(account => account.id !== currentVerifyCredentials.id)
if (!store.getComposeData(statusId, 'text') && accounts.length) { if (!store.getComposeData(statusId, 'text') && accounts.length) {
store.setComposeData(statusId, { store.setComposeData(statusId, {
@ -23,7 +23,7 @@ export async function insertHandleForReply (statusId) {
export async function postStatus (realm, text, inReplyToId, mediaIds, export async function postStatus (realm, text, inReplyToId, mediaIds,
sensitive, spoilerText, visibility, sensitive, spoilerText, visibility,
mediaDescriptions, inReplyToUuid, poll, mediaFocalPoints) { mediaDescriptions, inReplyToUuid, poll, mediaFocalPoints) {
let { currentInstance, accessToken, online } = store.get() const { currentInstance, accessToken, online } = store.get()
if (!online) { if (!online) {
toast.say('You cannot post while offline') toast.say('You cannot post while offline')
@ -32,7 +32,7 @@ export async function postStatus (realm, text, inReplyToId, mediaIds,
text = text || '' text = text || ''
let mediaMetadata = (mediaIds || []).map((mediaId, idx) => { const mediaMetadata = (mediaIds || []).map((mediaId, idx) => {
return { return {
description: mediaDescriptions && mediaDescriptions[idx], description: mediaDescriptions && mediaDescriptions[idx],
focalPoint: mediaFocalPoints && mediaFocalPoints[idx] focalPoint: mediaFocalPoints && mediaFocalPoints[idx]
@ -50,7 +50,7 @@ export async function postStatus (realm, text, inReplyToId, mediaIds,
return putMediaMetadata(currentInstance, accessToken, mediaIds[i], description, focalPoint) return putMediaMetadata(currentInstance, accessToken, mediaIds[i], description, focalPoint)
} }
})) }))
let status = await postStatusToServer(currentInstance, accessToken, text, const status = await postStatusToServer(currentInstance, accessToken, text,
inReplyToId, mediaIds, sensitive, spoilerText, visibility, poll, mediaFocalPoints) inReplyToId, mediaIds, sensitive, spoilerText, visibility, poll, mediaFocalPoints)
addStatusOrNotification(currentInstance, 'home', status) addStatusOrNotification(currentInstance, 'home', status)
store.clearComposeData(realm) store.clearComposeData(realm)
@ -64,8 +64,8 @@ export async function postStatus (realm, text, inReplyToId, mediaIds,
} }
export function setReplySpoiler (realm, spoiler) { export function setReplySpoiler (realm, spoiler) {
let contentWarning = store.getComposeData(realm, 'contentWarning') const contentWarning = store.getComposeData(realm, 'contentWarning')
let contentWarningShown = store.getComposeData(realm, 'contentWarningShown') const contentWarningShown = store.getComposeData(realm, 'contentWarningShown')
if (typeof contentWarningShown !== 'undefined' || contentWarning) { if (typeof contentWarningShown !== 'undefined' || contentWarning) {
return // user has already interacted with the CW return // user has already interacted with the CW
} }
@ -76,22 +76,22 @@ export function setReplySpoiler (realm, spoiler) {
} }
const PRIVACY_LEVEL = { const PRIVACY_LEVEL = {
'direct': 1, direct: 1,
'private': 2, private: 2,
'unlisted': 3, unlisted: 3,
'public': 4 public: 4
} }
export function setReplyVisibility (realm, replyVisibility) { export function setReplyVisibility (realm, replyVisibility) {
// return the most private between the user's preferred default privacy // return the most private between the user's preferred default privacy
// and the privacy of the status they're replying to // and the privacy of the status they're replying to
let postPrivacy = store.getComposeData(realm, 'postPrivacy') const postPrivacy = store.getComposeData(realm, 'postPrivacy')
if (typeof postPrivacy !== 'undefined') { if (typeof postPrivacy !== 'undefined') {
return // user has already set the postPrivacy return // user has already set the postPrivacy
} }
let { currentVerifyCredentials } = store.get() const { currentVerifyCredentials } = store.get()
let defaultVisibility = currentVerifyCredentials.source.privacy const defaultVisibility = currentVerifyCredentials.source.privacy
let visibility = PRIVACY_LEVEL[replyVisibility] < PRIVACY_LEVEL[defaultVisibility] const visibility = PRIVACY_LEVEL[replyVisibility] < PRIVACY_LEVEL[defaultVisibility]
? replyVisibility ? replyVisibility
: defaultVisibility : defaultVisibility
store.setComposeData(realm, { postPrivacy: visibility }) store.setComposeData(realm, { postPrivacy: visibility })

View File

@ -1,9 +1,9 @@
import { store } from '../_store/store' import { store } from '../_store/store'
export function toggleContentWarningShown (realm) { export function toggleContentWarningShown (realm) {
let shown = store.getComposeData(realm, 'contentWarningShown') const shown = store.getComposeData(realm, 'contentWarningShown')
let contentWarning = store.getComposeData(realm, 'contentWarning') const contentWarning = store.getComposeData(realm, 'contentWarning')
let newShown = !shown const newShown = !shown
store.setComposeData(realm, { store.setComposeData(realm, {
contentWarning: newShown ? contentWarning : '', contentWarning: newShown ? contentWarning : '',
contentWarningShown: newShown contentWarningShown: newShown

View File

@ -12,6 +12,6 @@ export async function copyText (text) {
} }
} }
let showCopyDialog = await importShowCopyDialog() const showCopyDialog = await importShowCopyDialog()
showCopyDialog(text) showCopyDialog(text)
} }

View File

@ -36,7 +36,7 @@ export function createMakeProps (instanceName, timelineType, timelineValue) {
return (itemId) => { return (itemId) => {
taskCount++ taskCount++
let promise = timelineType === 'notifications' const promise = timelineType === 'notifications'
? getNotification(instanceName, timelineType, timelineValue, itemId) ? getNotification(instanceName, timelineType, timelineValue, itemId)
: getStatus(instanceName, timelineType, timelineValue, itemId) : getStatus(instanceName, timelineType, timelineValue, itemId)

View File

@ -4,9 +4,9 @@ import { toast } from '../_components/toast/toast'
import { deleteStatus as deleteStatusLocally } from './deleteStatuses' import { deleteStatus as deleteStatusLocally } from './deleteStatuses'
export async function doDeleteStatus (statusId) { export async function doDeleteStatus (statusId) {
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
try { try {
let deletedStatus = await deleteStatus(currentInstance, accessToken, statusId) const deletedStatus = await deleteStatus(currentInstance, accessToken, statusId)
deleteStatusLocally(currentInstance, statusId) deleteStatusLocally(currentInstance, statusId)
toast.say('Status deleted.') toast.say('Status deleted.')
return deletedStatus return deletedStatus

View File

@ -4,9 +4,9 @@ import { doDeleteStatus } from './delete'
import { store } from '../_store/store' import { store } from '../_store/store'
export async function deleteAndRedraft (status) { export async function deleteAndRedraft (status) {
let deleteStatusPromise = doDeleteStatus(status.id) const deleteStatusPromise = doDeleteStatus(status.id)
let dialogPromise = importShowComposeDialog() const dialogPromise = importShowComposeDialog()
let deletedStatus = await deleteStatusPromise const deletedStatus = await deleteStatusPromise
store.setComposeData('dialog', { store.setComposeData('dialog', {
text: deletedStatus.text || statusHtmlToPlainText(status.content, status.mentions), text: deletedStatus.text || statusHtmlToPlainText(status.content, status.mentions),
@ -24,6 +24,6 @@ export async function deleteAndRedraft (status) {
options: (status.poll.options || []).map(option => option.title) options: (status.poll.options || []).map(option => option.title)
} }
}) })
let showComposeDialog = await dialogPromise const showComposeDialog = await dialogPromise
showComposeDialog() showComposeDialog()
} }

View File

@ -5,17 +5,17 @@ import { database } from '../_database/database'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask' import { scheduleIdleTask } from '../_utils/scheduleIdleTask'
function filterItemIdsFromTimelines (instanceName, timelineFilter, idFilter) { function filterItemIdsFromTimelines (instanceName, timelineFilter, idFilter) {
let keys = ['timelineItemSummaries', 'timelineItemSummariesToAdd'] const keys = ['timelineItemSummaries', 'timelineItemSummariesToAdd']
let summaryFilter = _ => idFilter(_.id) const summaryFilter = _ => idFilter(_.id)
keys.forEach(key => { keys.forEach(key => {
let timelineData = store.getAllTimelineData(instanceName, key) const timelineData = store.getAllTimelineData(instanceName, key)
Object.keys(timelineData).forEach(timelineName => { Object.keys(timelineData).forEach(timelineName => {
let summaries = timelineData[timelineName] const summaries = timelineData[timelineName]
if (!timelineFilter(timelineName)) { if (!timelineFilter(timelineName)) {
return return
} }
let filteredSummaries = summaries.filter(summaryFilter) const filteredSummaries = summaries.filter(summaryFilter)
if (!isEqual(summaries, filteredSummaries)) { if (!isEqual(summaries, filteredSummaries)) {
console.log('deleting an item from timelineName', timelineName, 'for key', key) console.log('deleting an item from timelineName', timelineName, 'for key', key)
store.setForTimeline(instanceName, timelineName, { store.setForTimeline(instanceName, timelineName, {
@ -27,17 +27,17 @@ function filterItemIdsFromTimelines (instanceName, timelineFilter, idFilter) {
} }
function deleteStatusIdsFromStore (instanceName, idsToDelete) { function deleteStatusIdsFromStore (instanceName, idsToDelete) {
let idsToDeleteSet = new Set(idsToDelete) const idsToDeleteSet = new Set(idsToDelete)
let idWasNotDeleted = id => !idsToDeleteSet.has(id) const idWasNotDeleted = id => !idsToDeleteSet.has(id)
let notNotificationTimeline = timelineName => timelineName !== 'notifications' const notNotificationTimeline = timelineName => timelineName !== 'notifications'
filterItemIdsFromTimelines(instanceName, notNotificationTimeline, idWasNotDeleted) filterItemIdsFromTimelines(instanceName, notNotificationTimeline, idWasNotDeleted)
} }
function deleteNotificationIdsFromStore (instanceName, idsToDelete) { function deleteNotificationIdsFromStore (instanceName, idsToDelete) {
let idsToDeleteSet = new Set(idsToDelete) const idsToDeleteSet = new Set(idsToDelete)
let idWasNotDeleted = id => !idsToDeleteSet.has(id) const idWasNotDeleted = id => !idsToDeleteSet.has(id)
let isNotificationTimeline = timelineName => timelineName === 'notifications' const isNotificationTimeline = timelineName => timelineName === 'notifications'
filterItemIdsFromTimelines(instanceName, isNotificationTimeline, idWasNotDeleted) filterItemIdsFromTimelines(instanceName, isNotificationTimeline, idWasNotDeleted)
} }
@ -50,9 +50,9 @@ async function deleteStatusesAndNotifications (instanceName, statusIdsToDelete,
async function doDeleteStatus (instanceName, statusId) { async function doDeleteStatus (instanceName, statusId) {
console.log('deleting statusId', statusId) console.log('deleting statusId', statusId)
let rebloggedIds = await getIdsThatRebloggedThisStatus(instanceName, statusId) const rebloggedIds = await getIdsThatRebloggedThisStatus(instanceName, statusId)
let statusIdsToDelete = Array.from(new Set([statusId].concat(rebloggedIds).filter(Boolean))) const statusIdsToDelete = Array.from(new Set([statusId].concat(rebloggedIds).filter(Boolean)))
let notificationIdsToDelete = Array.from(new Set(await getNotificationIdsForStatuses(instanceName, statusIdsToDelete))) const notificationIdsToDelete = Array.from(new Set(await getNotificationIdsForStatuses(instanceName, statusIdsToDelete)))
await deleteStatusesAndNotifications(instanceName, statusIdsToDelete, notificationIdsToDelete) await deleteStatusesAndNotifications(instanceName, statusIdsToDelete, notificationIdsToDelete)
} }

View File

@ -9,7 +9,7 @@ export async function updateCustomEmojiForInstance (instanceName) {
() => database.getCustomEmoji(instanceName), () => database.getCustomEmoji(instanceName),
emoji => database.setCustomEmoji(instanceName, emoji), emoji => database.setCustomEmoji(instanceName, emoji),
emoji => { emoji => {
let { customEmoji } = store.get() const { customEmoji } = store.get()
customEmoji[instanceName] = emoji customEmoji[instanceName] = emoji
store.set({ customEmoji: customEmoji }) store.set({ customEmoji: customEmoji })
} }
@ -17,12 +17,12 @@ export async function updateCustomEmojiForInstance (instanceName) {
} }
export function insertEmoji (realm, emoji) { export function insertEmoji (realm, emoji) {
let emojiText = emoji.custom ? emoji.colons : emoji.native const emojiText = emoji.custom ? emoji.colons : emoji.native
let { composeSelectionStart } = store.get() const { composeSelectionStart } = store.get()
let idx = composeSelectionStart || 0 const idx = composeSelectionStart || 0
let oldText = store.getComposeData(realm, 'text') || '' const oldText = store.getComposeData(realm, 'text') || ''
let pre = oldText.substring(0, idx) const pre = oldText.substring(0, idx)
let post = oldText.substring(idx) const post = oldText.substring(idx)
let newText = `${pre}${emojiText} ${post}` const newText = `${pre}${emojiText} ${post}`
store.setComposeData(realm, { text: newText }) store.setComposeData(realm, { text: newText })
} }

View File

@ -4,13 +4,13 @@ import { toast } from '../_components/toast/toast'
import { database } from '../_database/database' import { database } from '../_database/database'
export async function setFavorited (statusId, favorited) { export async function setFavorited (statusId, favorited) {
let { online } = store.get() const { online } = store.get()
if (!online) { if (!online) {
toast.say(`You cannot ${favorited ? 'favorite' : 'unfavorite'} while offline.`) toast.say(`You cannot ${favorited ? 'favorite' : 'unfavorite'} while offline.`)
return return
} }
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
let networkPromise = favorited const networkPromise = favorited
? favoriteStatus(currentInstance, accessToken, statusId) ? favoriteStatus(currentInstance, accessToken, statusId)
: unfavoriteStatus(currentInstance, accessToken, statusId) : unfavoriteStatus(currentInstance, accessToken, statusId)
store.setStatusFavorited(currentInstance, statusId, favorited) // optimistic update store.setStatusFavorited(currentInstance, statusId, favorited) // optimistic update

View File

@ -4,7 +4,7 @@ import { toast } from '../_components/toast/toast'
import { updateLocalRelationship } from './accounts' import { updateLocalRelationship } from './accounts'
export async function setAccountFollowed (accountId, follow, toastOnSuccess) { export async function setAccountFollowed (accountId, follow, toastOnSuccess) {
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
try { try {
let relationship let relationship
if (follow) { if (follow) {

View File

@ -2,16 +2,16 @@ import { DEFAULT_TIMEOUT, get, post, WRITE_TIMEOUT } from '../_utils/ajax'
import { auth, basename } from '../_api/utils' import { auth, basename } from '../_api/utils'
export async function getFollowRequests (instanceName, accessToken) { export async function getFollowRequests (instanceName, accessToken) {
let url = `${basename(instanceName)}/api/v1/follow_requests` const url = `${basename(instanceName)}/api/v1/follow_requests`
return get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT }) return get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT })
} }
export async function authorizeFollowRequest (instanceName, accessToken, id) { export async function authorizeFollowRequest (instanceName, accessToken, id) {
let url = `${basename(instanceName)}/api/v1/follow_requests/${id}/authorize` const url = `${basename(instanceName)}/api/v1/follow_requests/${id}/authorize`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }
export async function rejectFollowRequest (instanceName, accessToken, id) { export async function rejectFollowRequest (instanceName, accessToken, id) {
let url = `${basename(instanceName)}/api/v1/follow_requests/${id}/reject` const url = `${basename(instanceName)}/api/v1/follow_requests/${id}/reject`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }

View File

@ -8,31 +8,31 @@ import { getInstanceInfo } from '../_api/instance'
import { database } from '../_database/database' import { database } from '../_database/database'
export function changeTheme (instanceName, newTheme) { export function changeTheme (instanceName, newTheme) {
let { instanceThemes } = store.get() const { instanceThemes } = store.get()
instanceThemes[instanceName] = newTheme instanceThemes[instanceName] = newTheme
store.set({ instanceThemes: instanceThemes }) store.set({ instanceThemes: instanceThemes })
store.save() store.save()
let { currentInstance } = store.get() const { currentInstance } = store.get()
if (instanceName === currentInstance) { if (instanceName === currentInstance) {
let { enableGrayscale } = store.get() const { enableGrayscale } = store.get()
switchToTheme(newTheme, enableGrayscale) switchToTheme(newTheme, enableGrayscale)
} }
} }
export function switchToInstance (instanceName) { export function switchToInstance (instanceName) {
let { instanceThemes } = store.get() const { instanceThemes } = store.get()
store.set({ store.set({
currentInstance: instanceName, currentInstance: instanceName,
searchResults: null, searchResults: null,
queryInSearch: '' queryInSearch: ''
}) })
store.save() store.save()
let { enableGrayscale } = store.get() const { enableGrayscale } = store.get()
switchToTheme(instanceThemes[instanceName], enableGrayscale) switchToTheme(instanceThemes[instanceName], enableGrayscale)
} }
export async function logOutOfInstance (instanceName) { export async function logOutOfInstance (instanceName) {
let { const {
loggedInInstances, loggedInInstances,
instanceThemes, instanceThemes,
loggedInInstancesInOrder, loggedInInstancesInOrder,
@ -40,7 +40,7 @@ export async function logOutOfInstance (instanceName) {
currentInstance currentInstance
} = store.get() } = store.get()
loggedInInstancesInOrder.splice(loggedInInstancesInOrder.indexOf(instanceName), 1) loggedInInstancesInOrder.splice(loggedInInstancesInOrder.indexOf(instanceName), 1)
let newInstance = instanceName === currentInstance const newInstance = instanceName === currentInstance
? loggedInInstancesInOrder[0] ? loggedInInstancesInOrder[0]
: currentInstance : currentInstance
delete loggedInInstances[instanceName] delete loggedInInstances[instanceName]
@ -57,21 +57,21 @@ export async function logOutOfInstance (instanceName) {
}) })
store.save() store.save()
toast.say(`Logged out of ${instanceName}`) toast.say(`Logged out of ${instanceName}`)
let { enableGrayscale } = store.get() const { enableGrayscale } = store.get()
switchToTheme(instanceThemes[newInstance], enableGrayscale) switchToTheme(instanceThemes[newInstance], enableGrayscale)
/* no await */ database.clearDatabaseForInstance(instanceName) /* no await */ database.clearDatabaseForInstance(instanceName)
goto('/settings/instances') goto('/settings/instances')
} }
function setStoreVerifyCredentials (instanceName, thisVerifyCredentials) { function setStoreVerifyCredentials (instanceName, thisVerifyCredentials) {
let { verifyCredentials } = store.get() const { verifyCredentials } = store.get()
verifyCredentials[instanceName] = thisVerifyCredentials verifyCredentials[instanceName] = thisVerifyCredentials
store.set({ verifyCredentials: verifyCredentials }) store.set({ verifyCredentials: verifyCredentials })
} }
export async function updateVerifyCredentialsForInstance (instanceName) { export async function updateVerifyCredentialsForInstance (instanceName) {
let { loggedInInstances } = store.get() const { loggedInInstances } = store.get()
let accessToken = loggedInInstances[instanceName].access_token const accessToken = loggedInInstances[instanceName].access_token
await cacheFirstUpdateAfter( await cacheFirstUpdateAfter(
() => getVerifyCredentials(instanceName, accessToken), () => getVerifyCredentials(instanceName, accessToken),
() => database.getInstanceVerifyCredentials(instanceName), () => database.getInstanceVerifyCredentials(instanceName),
@ -81,7 +81,7 @@ export async function updateVerifyCredentialsForInstance (instanceName) {
} }
export async function updateVerifyCredentialsForCurrentInstance () { export async function updateVerifyCredentialsForCurrentInstance () {
let { currentInstance } = store.get() const { currentInstance } = store.get()
await updateVerifyCredentialsForInstance(currentInstance) await updateVerifyCredentialsForInstance(currentInstance)
} }
@ -91,7 +91,7 @@ export async function updateInstanceInfo (instanceName) {
() => database.getInstanceInfo(instanceName), () => database.getInstanceInfo(instanceName),
info => database.setInstanceInfo(instanceName, info), info => database.setInstanceInfo(instanceName, info),
info => { info => {
let { instanceInfos } = store.get() const { instanceInfos } = store.get()
instanceInfos[instanceName] = info instanceInfos[instanceName] = info
store.set({ instanceInfos: instanceInfos }) store.set({ instanceInfos: instanceInfos })
} }

View File

@ -4,15 +4,15 @@ import { cacheFirstUpdateAfter } from '../_utils/sync'
import { database } from '../_database/database' import { database } from '../_database/database'
export async function updateListsForInstance (instanceName) { export async function updateListsForInstance (instanceName) {
let { loggedInInstances } = store.get() const { loggedInInstances } = store.get()
let accessToken = loggedInInstances[instanceName].access_token const accessToken = loggedInInstances[instanceName].access_token
await cacheFirstUpdateAfter( await cacheFirstUpdateAfter(
() => getLists(instanceName, accessToken), () => getLists(instanceName, accessToken),
() => database.getLists(instanceName), () => database.getLists(instanceName),
lists => database.setLists(instanceName, lists), lists => database.setLists(instanceName, lists),
lists => { lists => {
let { instanceLists } = store.get() const { instanceLists } = store.get()
instanceLists[instanceName] = lists instanceLists[instanceName] = lists
store.set({ instanceLists: instanceLists }) store.set({ instanceLists: instanceLists })
} }

View File

@ -4,11 +4,11 @@ import { toast } from '../_components/toast/toast'
import { scheduleIdleTask } from '../_utils/scheduleIdleTask' import { scheduleIdleTask } from '../_utils/scheduleIdleTask'
export async function doMediaUpload (realm, file) { export async function doMediaUpload (realm, file) {
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
store.set({ uploadingMedia: true }) store.set({ uploadingMedia: true })
try { try {
let response = await uploadMedia(currentInstance, accessToken, file) const response = await uploadMedia(currentInstance, accessToken, file)
let composeMedia = store.getComposeData(realm, 'media') || [] const composeMedia = store.getComposeData(realm, 'media') || []
if (composeMedia.length === 4) { if (composeMedia.length === 4) {
throw new Error('Only 4 media max are allowed') throw new Error('Only 4 media max are allowed')
} }
@ -30,7 +30,7 @@ export async function doMediaUpload (realm, file) {
} }
export function deleteMedia (realm, i) { export function deleteMedia (realm, i) {
let composeMedia = store.getComposeData(realm, 'media') const composeMedia = store.getComposeData(realm, 'media')
composeMedia.splice(i, 1) composeMedia.splice(i, 1)
store.setComposeData(realm, { store.setComposeData(realm, {

View File

@ -3,6 +3,6 @@ import { store } from '../_store/store'
export async function composeNewStatusMentioning (account) { export async function composeNewStatusMentioning (account) {
store.setComposeData('dialog', { text: `@${account.acct} ` }) store.setComposeData('dialog', { text: `@${account.acct} ` })
let showComposeDialog = await importShowComposeDialog() const showComposeDialog = await importShowComposeDialog()
showComposeDialog() showComposeDialog()
} }

View File

@ -5,7 +5,7 @@ import { updateLocalRelationship } from './accounts'
import { emit } from '../_utils/eventBus' import { emit } from '../_utils/eventBus'
export async function setAccountMuted (accountId, mute, notifications, toastOnSuccess) { export async function setAccountMuted (accountId, mute, notifications, toastOnSuccess) {
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
try { try {
let relationship let relationship
if (mute) { if (mute) {

View File

@ -4,7 +4,7 @@ import { toast } from '../_components/toast/toast'
import { database } from '../_database/database' import { database } from '../_database/database'
export async function setConversationMuted (statusId, mute, toastOnSuccess) { export async function setConversationMuted (statusId, mute, toastOnSuccess) {
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
try { try {
if (mute) { if (mute) {
await muteConversation(currentInstance, accessToken, statusId) await muteConversation(currentInstance, accessToken, statusId)

View File

@ -4,7 +4,7 @@ export function onUserIsLoggedOut () {
if (document.getElementById('hiddenFromSsrStyle')) { if (document.getElementById('hiddenFromSsrStyle')) {
return return
} }
let style = document.createElement('style') const style = document.createElement('style')
style.setAttribute('id', 'hiddenFromSsrStyle') style.setAttribute('id', 'hiddenFromSsrStyle')
style.textContent = '.hidden-from-ssr { opacity: 1 !important; }' style.textContent = '.hidden-from-ssr { opacity: 1 !important; }'
document.head.appendChild(style) document.head.appendChild(style)

View File

@ -5,7 +5,7 @@ import { database } from '../_database/database'
import { emit } from '../_utils/eventBus' import { emit } from '../_utils/eventBus'
export async function setStatusPinnedOrUnpinned (statusId, pinned, toastOnSuccess) { export async function setStatusPinnedOrUnpinned (statusId, pinned, toastOnSuccess) {
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
try { try {
if (pinned) { if (pinned) {
await pinStatus(currentInstance, accessToken, statusId) await pinStatus(currentInstance, accessToken, statusId)

View File

@ -6,12 +6,12 @@ import {
} from '../_api/pinnedStatuses' } from '../_api/pinnedStatuses'
export async function updatePinnedStatusesForAccount (accountId) { export async function updatePinnedStatusesForAccount (accountId) {
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
await cacheFirstUpdateAfter( await cacheFirstUpdateAfter(
() => getPinnedStatuses(currentInstance, accessToken, accountId), () => getPinnedStatuses(currentInstance, accessToken, accountId),
async () => { async () => {
let pinnedStatuses = await database.getPinnedStatuses(currentInstance, accountId) const pinnedStatuses = await database.getPinnedStatuses(currentInstance, accountId)
if (!pinnedStatuses || !pinnedStatuses.every(Boolean)) { if (!pinnedStatuses || !pinnedStatuses.every(Boolean)) {
throw new Error('missing pinned statuses in idb') throw new Error('missing pinned statuses in idb')
} }
@ -19,7 +19,7 @@ export async function updatePinnedStatusesForAccount (accountId) {
}, },
statuses => database.insertPinnedStatuses(currentInstance, accountId, statuses), statuses => database.insertPinnedStatuses(currentInstance, accountId, statuses),
statuses => { statuses => {
let { pinnedStatuses } = store.get() const { pinnedStatuses } = store.get()
pinnedStatuses[currentInstance] = pinnedStatuses[currentInstance] || {} pinnedStatuses[currentInstance] = pinnedStatuses[currentInstance] || {}
pinnedStatuses[currentInstance][accountId] = statuses pinnedStatuses[currentInstance][accountId] = statuses
store.set({ pinnedStatuses: pinnedStatuses }) store.set({ pinnedStatuses: pinnedStatuses })

View File

@ -3,9 +3,9 @@ import { store } from '../_store/store'
import { toast } from '../_components/toast/toast' import { toast } from '../_components/toast/toast'
export async function getPoll (pollId) { export async function getPoll (pollId) {
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
try { try {
let poll = await getPollApi(currentInstance, accessToken, pollId) const poll = await getPollApi(currentInstance, accessToken, pollId)
return poll return poll
} catch (e) { } catch (e) {
console.error(e) console.error(e)
@ -14,9 +14,9 @@ export async function getPoll (pollId) {
} }
export async function voteOnPoll (pollId, choices) { export async function voteOnPoll (pollId, choices) {
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
try { try {
let poll = await voteOnPollApi(currentInstance, accessToken, pollId, choices.map(_ => _.toString())) const poll = await voteOnPollApi(currentInstance, accessToken, pollId, choices.map(_ => _.toString()))
return poll return poll
} catch (e) { } catch (e) {
console.error(e) console.error(e)

View File

@ -4,13 +4,13 @@ import { reblogStatus, unreblogStatus } from '../_api/reblog'
import { database } from '../_database/database' import { database } from '../_database/database'
export async function setReblogged (statusId, reblogged) { export async function setReblogged (statusId, reblogged) {
let online = store.get() const online = store.get()
if (!online) { if (!online) {
toast.say(`You cannot ${reblogged ? 'boost' : 'unboost'} while offline.`) toast.say(`You cannot ${reblogged ? 'boost' : 'unboost'} while offline.`)
return return
} }
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
let networkPromise = reblogged const networkPromise = reblogged
? reblogStatus(currentInstance, accessToken, statusId) ? reblogStatus(currentInstance, accessToken, statusId)
: unreblogStatus(currentInstance, accessToken, statusId) : unreblogStatus(currentInstance, accessToken, statusId)
store.setStatusReblogged(currentInstance, statusId, reblogged) // optimistic update store.setStatusReblogged(currentInstance, statusId, reblogged) // optimistic update

View File

@ -1,6 +1,6 @@
import { importShowReportDialog } from '../_components/dialog/asyncDialogs' import { importShowReportDialog } from '../_components/dialog/asyncDialogs'
export async function reportStatusOrAccount ({ status, account }) { export async function reportStatusOrAccount ({ status, account }) {
let showReportDialog = await importShowReportDialog() const showReportDialog = await importShowReportDialog()
showReportDialog({ status, account }) showReportDialog({ status, account })
} }

View File

@ -3,7 +3,7 @@ import { toast } from '../_components/toast/toast'
import { report } from '../_api/report' import { report } from '../_api/report'
export async function reportStatuses (account, statusIds, comment, forward) { export async function reportStatuses (account, statusIds, comment, forward) {
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
try { try {
await report(currentInstance, accessToken, account.id, statusIds, comment, forward) await report(currentInstance, accessToken, account.id, statusIds, comment, forward)
toast.say('Submitted report') toast.say('Submitted report')

View File

@ -4,7 +4,7 @@ import { emit } from '../_utils/eventBus'
import { toast } from '../_components/toast/toast' import { toast } from '../_components/toast/toast'
export async function setFollowRequestApprovedOrRejected (accountId, approved, toastOnSuccess) { export async function setFollowRequestApprovedOrRejected (accountId, approved, toastOnSuccess) {
let { const {
currentInstance, currentInstance,
accessToken accessToken
} = store.get() } = store.get()

View File

@ -3,11 +3,11 @@ import { toast } from '../_components/toast/toast'
import { search } from '../_api/search' import { search } from '../_api/search'
export async function doSearch () { export async function doSearch () {
let { currentInstance, accessToken, queryInSearch } = store.get() const { currentInstance, accessToken, queryInSearch } = store.get()
store.set({ searchLoading: true }) store.set({ searchLoading: true })
try { try {
let results = await search(currentInstance, accessToken, queryInSearch) const results = await search(currentInstance, accessToken, queryInSearch)
let { queryInSearch: newQueryInSearch } = store.get() // avoid race conditions const { queryInSearch: newQueryInSearch } = store.get() // avoid race conditions
if (newQueryInSearch === queryInSearch) { if (newQueryInSearch === queryInSearch) {
store.set({ store.set({
searchResultsForQuery: queryInSearch, searchResultsForQuery: queryInSearch,

View File

@ -4,7 +4,7 @@ import { toast } from '../_components/toast/toast'
import { updateRelationship } from './accounts' import { updateRelationship } from './accounts'
export async function setDomainBlocked (accountId, domain, block, toastOnSuccess) { export async function setDomainBlocked (accountId, domain, block, toastOnSuccess) {
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
try { try {
if (block) { if (block) {
await blockDomain(currentInstance, accessToken, domain) await blockDomain(currentInstance, accessToken, domain)

View File

@ -4,9 +4,9 @@ import { toast } from '../_components/toast/toast'
import { updateLocalRelationship } from './accounts' import { updateLocalRelationship } from './accounts'
export async function setShowReblogs (accountId, showReblogs, toastOnSuccess) { export async function setShowReblogs (accountId, showReblogs, toastOnSuccess) {
let { currentInstance, accessToken } = store.get() const { currentInstance, accessToken } = store.get()
try { try {
let relationship = await setShowReblogsApi(currentInstance, accessToken, accountId, showReblogs) const relationship = await setShowReblogsApi(currentInstance, accessToken, accountId, showReblogs)
await updateLocalRelationship(currentInstance, accountId, relationship) await updateLocalRelationship(currentInstance, accountId, relationship)
if (toastOnSuccess) { if (toastOnSuccess) {
if (showReblogs) { if (showReblogs) {

View File

@ -11,27 +11,27 @@ export function showMoreAndScrollToTop () {
// Similar to Twitter, pressing "." will click the "show more" button and select // Similar to Twitter, pressing "." will click the "show more" button and select
// the first toot. // the first toot.
showMoreItemsForCurrentTimeline() showMoreItemsForCurrentTimeline()
let { const {
currentInstance, currentInstance,
timelineItemSummaries, timelineItemSummaries,
currentTimelineType, currentTimelineType,
currentTimelineValue currentTimelineValue
} = store.get() } = store.get()
let firstItemSummary = timelineItemSummaries && timelineItemSummaries[0] const firstItemSummary = timelineItemSummaries && timelineItemSummaries[0]
if (!firstItemSummary) { if (!firstItemSummary) {
return return
} }
let notificationId = currentTimelineType === 'notifications' && firstItemSummary.id const notificationId = currentTimelineType === 'notifications' && firstItemSummary.id
let statusId = currentTimelineType !== 'notifications' && firstItemSummary.id const statusId = currentTimelineType !== 'notifications' && firstItemSummary.id
scrollToTop(/* smooth */ false) scrollToTop(/* smooth */ false)
// try 5 times to wait for the element to be rendered and then focus it // try 5 times to wait for the element to be rendered and then focus it
let count = 0 let count = 0
const tryToFocusElement = () => { const tryToFocusElement = () => {
let uuid = createStatusOrNotificationUuid( const uuid = createStatusOrNotificationUuid(
currentInstance, currentTimelineType, currentInstance, currentTimelineType,
currentTimelineValue, notificationId, statusId currentTimelineValue, notificationId, statusId
) )
let element = document.getElementById(uuid) const element = document.getElementById(uuid)
if (element) { if (element) {
try { try {
element.focus({ preventScroll: true }) element.focus({ preventScroll: true })

View File

@ -2,10 +2,10 @@ import { store } from '../_store/store'
import { importShowComposeDialog } from '../_components/dialog/asyncDialogs' import { importShowComposeDialog } from '../_components/dialog/asyncDialogs'
export async function showShareDialogIfNecessary () { export async function showShareDialogIfNecessary () {
let { isUserLoggedIn, openShareDialog } = store.get() const { isUserLoggedIn, openShareDialog } = store.get()
store.set({ openShareDialog: false }) store.set({ openShareDialog: false })
if (isUserLoggedIn && openShareDialog) { if (isUserLoggedIn && openShareDialog) {
let showComposeDialog = await importShowComposeDialog() const showComposeDialog = await importShowComposeDialog()
showComposeDialog() showComposeDialog()
} }
} }

View File

@ -1,12 +1,12 @@
import { database } from '../_database/database' import { database } from '../_database/database'
export async function getIdThatThisStatusReblogged (instanceName, statusId) { export async function getIdThatThisStatusReblogged (instanceName, statusId) {
let status = await database.getStatus(instanceName, statusId) const status = await database.getStatus(instanceName, statusId)
return status.reblog && status.reblog.id return status.reblog && status.reblog.id
} }
export async function getIdsThatTheseStatusesReblogged (instanceName, statusIds) { export async function getIdsThatTheseStatusesReblogged (instanceName, statusIds) {
let reblogIds = await Promise.all(statusIds.map(async statusId => { const reblogIds = await Promise.all(statusIds.map(async statusId => {
return getIdThatThisStatusReblogged(instanceName, statusId) return getIdThatThisStatusReblogged(instanceName, statusId)
})) }))
return reblogIds.filter(Boolean) return reblogIds.filter(Boolean)

View File

@ -35,11 +35,11 @@ export function createStream (api, instanceName, accessToken, timelineName, firs
console.log(`streaming ${instanceName} ${timelineName}: reconnected`) console.log(`streaming ${instanceName} ${timelineName}: reconnected`)
// When reconnecting, we recompute the firstStatusId and firstNotificationId because these may have // When reconnecting, we recompute the firstStatusId and firstNotificationId because these may have
// changed since we first started streaming. // changed since we first started streaming.
let newFirstStatusId = store.getFirstTimelineItemId(instanceName, timelineName) const newFirstStatusId = store.getFirstTimelineItemId(instanceName, timelineName)
fillGap(timelineName, newFirstStatusId) fillGap(timelineName, newFirstStatusId)
if (timelineName === 'home') { if (timelineName === 'home') {
// special case - home timeline stream also handles notifications // special case - home timeline stream also handles notifications
let newFirstNotificationId = store.getFirstTimelineItemId(instanceName, 'notifications') const newFirstNotificationId = store.getFirstTimelineItemId(instanceName, 'notifications')
fillGap('notifications', newFirstNotificationId) fillGap('notifications', newFirstNotificationId)
} }
} }

View File

@ -25,10 +25,10 @@ async function storeFreshTimelineItemsInDatabase (instanceName, timelineName, it
async function fetchTimelineItemsFromNetwork (instanceName, accessToken, timelineName, lastTimelineItemId) { async function fetchTimelineItemsFromNetwork (instanceName, accessToken, timelineName, lastTimelineItemId) {
if (timelineName.startsWith('status/')) { // special case - this is a list of descendents and ancestors if (timelineName.startsWith('status/')) { // special case - this is a list of descendents and ancestors
let statusId = timelineName.split('/').slice(-1)[0] const statusId = timelineName.split('/').slice(-1)[0]
let statusRequest = getStatus(instanceName, accessToken, statusId) const statusRequest = getStatus(instanceName, accessToken, statusId)
let contextRequest = getStatusContext(instanceName, accessToken, statusId) const contextRequest = getStatusContext(instanceName, accessToken, statusId)
let [ status, context ] = await Promise.all([statusRequest, contextRequest]) const [status, context] = await Promise.all([statusRequest, contextRequest])
return concat(context.ancestors, status, context.descendants) return concat(context.ancestors, status, context.descendants)
} else { // normal timeline } else { // normal timeline
return getTimeline(instanceName, accessToken, timelineName, lastTimelineItemId, null, TIMELINE_BATCH_SIZE) return getTimeline(instanceName, accessToken, timelineName, lastTimelineItemId, null, TIMELINE_BATCH_SIZE)
@ -61,16 +61,16 @@ async function fetchTimelineItems (instanceName, accessToken, timelineName, last
async function addTimelineItems (instanceName, timelineName, items, stale) { async function addTimelineItems (instanceName, timelineName, items, stale) {
console.log('addTimelineItems, length:', items.length) console.log('addTimelineItems, length:', items.length)
mark('addTimelineItemSummaries') mark('addTimelineItemSummaries')
let newSummaries = items.map(timelineItemToSummary) const newSummaries = items.map(timelineItemToSummary)
addTimelineItemSummaries(instanceName, timelineName, newSummaries, stale) addTimelineItemSummaries(instanceName, timelineName, newSummaries, stale)
stop('addTimelineItemSummaries') stop('addTimelineItemSummaries')
} }
export async function addTimelineItemSummaries (instanceName, timelineName, newSummaries, newStale) { export async function addTimelineItemSummaries (instanceName, timelineName, newSummaries, newStale) {
let oldSummaries = store.getForTimeline(instanceName, timelineName, 'timelineItemSummaries') || [] const oldSummaries = store.getForTimeline(instanceName, timelineName, 'timelineItemSummaries') || []
let oldStale = store.getForTimeline(instanceName, timelineName, 'timelineItemSummariesAreStale') const oldStale = store.getForTimeline(instanceName, timelineName, 'timelineItemSummariesAreStale')
let mergedSummaries = mergeArrays(oldSummaries, newSummaries, compareTimelineItemSummaries) const mergedSummaries = mergeArrays(oldSummaries, newSummaries, compareTimelineItemSummaries)
if (!isEqual(oldSummaries, mergedSummaries)) { if (!isEqual(oldSummaries, mergedSummaries)) {
store.setForTimeline(instanceName, timelineName, { timelineItemSummaries: mergedSummaries }) store.setForTimeline(instanceName, timelineName, { timelineItemSummaries: mergedSummaries })
@ -82,7 +82,7 @@ export async function addTimelineItemSummaries (instanceName, timelineName, newS
async function fetchTimelineItemsAndPossiblyFallBack () { async function fetchTimelineItemsAndPossiblyFallBack () {
mark('fetchTimelineItemsAndPossiblyFallBack') mark('fetchTimelineItemsAndPossiblyFallBack')
let { const {
currentTimeline, currentTimeline,
currentInstance, currentInstance,
accessToken, accessToken,
@ -90,7 +90,7 @@ async function fetchTimelineItemsAndPossiblyFallBack () {
online online
} = store.get() } = store.get()
let { items, stale } = await fetchTimelineItems(currentInstance, accessToken, currentTimeline, lastTimelineItemId, online) const { items, stale } = await fetchTimelineItems(currentInstance, accessToken, currentTimeline, lastTimelineItemId, online)
addTimelineItems(currentInstance, currentTimeline, items, stale) addTimelineItems(currentInstance, currentTimeline, items, stale)
stop('fetchTimelineItemsAndPossiblyFallBack') stop('fetchTimelineItemsAndPossiblyFallBack')
} }
@ -101,7 +101,7 @@ export async function setupTimeline () {
// (i.e. via offline mode), then we need to re-fetch // (i.e. via offline mode), then we need to re-fetch
// Also do this if it's a thread, because threads change pretty frequently and // Also do this if it's a thread, because threads change pretty frequently and
// we don't have a good way to update them. // we don't have a good way to update them.
let { const {
timelineItemSummaries, timelineItemSummaries,
timelineItemSummariesAreStale, timelineItemSummariesAreStale,
currentTimeline currentTimeline
@ -136,7 +136,7 @@ export async function showMoreItemsForTimeline (instanceName, timelineName) {
} }
export function showMoreItemsForCurrentTimeline () { export function showMoreItemsForCurrentTimeline () {
let { currentInstance, currentTimeline } = store.get() const { currentInstance, currentTimeline } = store.get()
return showMoreItemsForTimeline( return showMoreItemsForTimeline(
currentInstance, currentInstance,
currentTimeline currentTimeline
@ -145,11 +145,11 @@ export function showMoreItemsForCurrentTimeline () {
export async function showMoreItemsForThread (instanceName, timelineName) { export async function showMoreItemsForThread (instanceName, timelineName) {
mark('showMoreItemsForThread') mark('showMoreItemsForThread')
let itemSummariesToAdd = store.getForTimeline(instanceName, timelineName, 'timelineItemSummariesToAdd') const itemSummariesToAdd = store.getForTimeline(instanceName, timelineName, 'timelineItemSummariesToAdd')
let timelineItemSummaries = store.getForTimeline(instanceName, timelineName, 'timelineItemSummaries') const timelineItemSummaries = store.getForTimeline(instanceName, timelineName, 'timelineItemSummaries')
let timelineItemIds = new Set(timelineItemSummaries.map(_ => _.id)) const timelineItemIds = new Set(timelineItemSummaries.map(_ => _.id))
// TODO: update database and do the thread merge correctly // TODO: update database and do the thread merge correctly
for (let itemSummaryToAdd of itemSummariesToAdd) { for (const itemSummaryToAdd of itemSummariesToAdd) {
if (!timelineItemIds.has(itemSummaryToAdd.id)) { if (!timelineItemIds.has(itemSummaryToAdd.id)) {
timelineItemSummaries.push(itemSummaryToAdd) timelineItemSummaries.push(itemSummaryToAdd)
} }

View File

@ -2,11 +2,11 @@ import { auth, basename } from './utils'
import { post, WRITE_TIMEOUT } from '../_utils/ajax' import { post, WRITE_TIMEOUT } from '../_utils/ajax'
export async function blockAccount (instanceName, accessToken, accountId) { export async function blockAccount (instanceName, accessToken, accountId) {
let url = `${basename(instanceName)}/api/v1/accounts/${accountId}/block` const url = `${basename(instanceName)}/api/v1/accounts/${accountId}/block`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }
export async function unblockAccount (instanceName, accessToken, accountId) { export async function unblockAccount (instanceName, accessToken, accountId) {
let url = `${basename(instanceName)}/api/v1/accounts/${accountId}/unblock` const url = `${basename(instanceName)}/api/v1/accounts/${accountId}/unblock`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }

View File

@ -2,11 +2,11 @@ import { post, WRITE_TIMEOUT, paramsString, del } from '../_utils/ajax'
import { auth, basename } from './utils' import { auth, basename } from './utils'
export async function blockDomain (instanceName, accessToken, domain) { export async function blockDomain (instanceName, accessToken, domain) {
let url = `${basename(instanceName)}/api/v1/domain_blocks?${paramsString({ domain })}` const url = `${basename(instanceName)}/api/v1/domain_blocks?${paramsString({ domain })}`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }
export async function unblockDomain (instanceName, accessToken, domain) { export async function unblockDomain (instanceName, accessToken, domain) {
let url = `${basename(instanceName)}/api/v1/domain_blocks?${paramsString({ domain })}` const url = `${basename(instanceName)}/api/v1/domain_blocks?${paramsString({ domain })}`
return del(url, auth(accessToken), { timeout: WRITE_TIMEOUT }) return del(url, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }

View File

@ -2,6 +2,6 @@ import { auth, basename } from './utils'
import { del, WRITE_TIMEOUT } from '../_utils/ajax' import { del, WRITE_TIMEOUT } from '../_utils/ajax'
export async function deleteStatus (instanceName, accessToken, statusId) { export async function deleteStatus (instanceName, accessToken, statusId) {
let url = `${basename(instanceName)}/api/v1/statuses/${statusId}` const url = `${basename(instanceName)}/api/v1/statuses/${statusId}`
return del(url, auth(accessToken), { timeout: WRITE_TIMEOUT }) return del(url, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }

View File

@ -2,6 +2,6 @@ import { basename } from './utils'
import { DEFAULT_TIMEOUT, get } from '../_utils/ajax' import { DEFAULT_TIMEOUT, get } from '../_utils/ajax'
export async function getCustomEmoji (instanceName) { export async function getCustomEmoji (instanceName) {
let url = `${basename(instanceName)}/api/v1/custom_emojis` const url = `${basename(instanceName)}/api/v1/custom_emojis`
return get(url, null, { timeout: DEFAULT_TIMEOUT }) return get(url, null, { timeout: DEFAULT_TIMEOUT })
} }

View File

@ -2,11 +2,11 @@ import { post, WRITE_TIMEOUT } from '../_utils/ajax'
import { basename, auth } from './utils' import { basename, auth } from './utils'
export async function favoriteStatus (instanceName, accessToken, statusId) { export async function favoriteStatus (instanceName, accessToken, statusId) {
let url = `${basename(instanceName)}/api/v1/statuses/${statusId}/favourite` const url = `${basename(instanceName)}/api/v1/statuses/${statusId}/favourite`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }
export async function unfavoriteStatus (instanceName, accessToken, statusId) { export async function unfavoriteStatus (instanceName, accessToken, statusId) {
let url = `${basename(instanceName)}/api/v1/statuses/${statusId}/unfavourite` const url = `${basename(instanceName)}/api/v1/statuses/${statusId}/unfavourite`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }

View File

@ -2,11 +2,11 @@ import { post, WRITE_TIMEOUT } from '../_utils/ajax'
import { auth, basename } from './utils' import { auth, basename } from './utils'
export async function followAccount (instanceName, accessToken, accountId) { export async function followAccount (instanceName, accessToken, accountId) {
let url = `${basename(instanceName)}/api/v1/accounts/${accountId}/follow` const url = `${basename(instanceName)}/api/v1/accounts/${accountId}/follow`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }
export async function unfollowAccount (instanceName, accessToken, accountId) { export async function unfollowAccount (instanceName, accessToken, accountId) {
let url = `${basename(instanceName)}/api/v1/accounts/${accountId}/unfollow` const url = `${basename(instanceName)}/api/v1/accounts/${accountId}/unfollow`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }

View File

@ -2,6 +2,6 @@ import { get, DEFAULT_TIMEOUT } from '../_utils/ajax'
import { basename } from './utils' import { basename } from './utils'
export function getInstanceInfo (instanceName) { export function getInstanceInfo (instanceName) {
let url = `${basename(instanceName)}/api/v1/instance` const url = `${basename(instanceName)}/api/v1/instance`
return get(url, null, { timeout: DEFAULT_TIMEOUT }) return get(url, null, { timeout: DEFAULT_TIMEOUT })
} }

View File

@ -2,6 +2,6 @@ import { get, DEFAULT_TIMEOUT } from '../_utils/ajax'
import { auth, basename } from './utils' import { auth, basename } from './utils'
export function getLists (instanceName, accessToken) { export function getLists (instanceName, accessToken) {
let url = `${basename(instanceName)}/api/v1/lists` const url = `${basename(instanceName)}/api/v1/lists`
return get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT }) return get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT })
} }

View File

@ -2,16 +2,16 @@ import { auth, basename } from './utils'
import { post, put, MEDIA_WRITE_TIMEOUT, WRITE_TIMEOUT } from '../_utils/ajax' import { post, put, MEDIA_WRITE_TIMEOUT, WRITE_TIMEOUT } from '../_utils/ajax'
export async function uploadMedia (instanceName, accessToken, file, description) { export async function uploadMedia (instanceName, accessToken, file, description) {
let formData = new FormData() const formData = new FormData()
formData.append('file', file) formData.append('file', file)
if (description) { if (description) {
formData.append('description', description) formData.append('description', description)
} }
let url = `${basename(instanceName)}/api/v1/media` const url = `${basename(instanceName)}/api/v1/media`
return post(url, formData, auth(accessToken), { timeout: MEDIA_WRITE_TIMEOUT }) return post(url, formData, auth(accessToken), { timeout: MEDIA_WRITE_TIMEOUT })
} }
export async function putMediaMetadata (instanceName, accessToken, mediaId, description, focus) { export async function putMediaMetadata (instanceName, accessToken, mediaId, description, focus) {
let url = `${basename(instanceName)}/api/v1/media/${mediaId}` const url = `${basename(instanceName)}/api/v1/media/${mediaId}`
return put(url, { description, focus: (focus && focus.join(',')) }, auth(accessToken), { timeout: WRITE_TIMEOUT }) return put(url, { description, focus: (focus && focus.join(',')) }, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }

View File

@ -2,11 +2,11 @@ import { auth, basename } from './utils'
import { post, WRITE_TIMEOUT } from '../_utils/ajax' import { post, WRITE_TIMEOUT } from '../_utils/ajax'
export async function muteAccount (instanceName, accessToken, accountId, notifications) { export async function muteAccount (instanceName, accessToken, accountId, notifications) {
let url = `${basename(instanceName)}/api/v1/accounts/${accountId}/mute` const url = `${basename(instanceName)}/api/v1/accounts/${accountId}/mute`
return post(url, { notifications }, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, { notifications }, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }
export async function unmuteAccount (instanceName, accessToken, accountId) { export async function unmuteAccount (instanceName, accessToken, accountId) {
let url = `${basename(instanceName)}/api/v1/accounts/${accountId}/unmute` const url = `${basename(instanceName)}/api/v1/accounts/${accountId}/unmute`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }

View File

@ -2,11 +2,11 @@ import { auth, basename } from './utils'
import { post, WRITE_TIMEOUT } from '../_utils/ajax' import { post, WRITE_TIMEOUT } from '../_utils/ajax'
export async function muteConversation (instanceName, accessToken, statusId) { export async function muteConversation (instanceName, accessToken, statusId) {
let url = `${basename(instanceName)}/api/v1/statuses/${statusId}/mute` const url = `${basename(instanceName)}/api/v1/statuses/${statusId}/mute`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }
export async function unmuteConversation (instanceName, accessToken, statusId) { export async function unmuteConversation (instanceName, accessToken, statusId) {
let url = `${basename(instanceName)}/api/v1/statuses/${statusId}/unmute` const url = `${basename(instanceName)}/api/v1/statuses/${statusId}/unmute`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }

View File

@ -16,17 +16,17 @@ export function registerApplication (instanceName, redirectUri) {
} }
export function generateAuthLink (instanceName, clientId, redirectUri) { export function generateAuthLink (instanceName, clientId, redirectUri) {
let params = paramsString({ const params = paramsString({
'client_id': clientId, client_id: clientId,
'redirect_uri': redirectUri, redirect_uri: redirectUri,
'response_type': 'code', response_type: 'code',
'scope': SCOPES scope: SCOPES
}) })
return `${basename(instanceName)}/oauth/authorize?${params}` return `${basename(instanceName)}/oauth/authorize?${params}`
} }
export function getAccessTokenFromAuthCode (instanceName, clientId, clientSecret, code, redirectUri) { export function getAccessTokenFromAuthCode (instanceName, clientId, clientSecret, code, redirectUri) {
let url = `${basename(instanceName)}/oauth/token` const url = `${basename(instanceName)}/oauth/token`
return post(url, { return post(url, {
client_id: clientId, client_id: clientId,
client_secret: clientSecret, client_secret: clientSecret,

View File

@ -2,11 +2,11 @@ import { post, WRITE_TIMEOUT } from '../_utils/ajax'
import { auth, basename } from './utils' import { auth, basename } from './utils'
export async function pinStatus (instanceName, accessToken, statusId) { export async function pinStatus (instanceName, accessToken, statusId) {
let url = `${basename(instanceName)}/api/v1/statuses/${statusId}/pin` const url = `${basename(instanceName)}/api/v1/statuses/${statusId}/pin`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }
export async function unpinStatus (instanceName, accessToken, statusId) { export async function unpinStatus (instanceName, accessToken, statusId) {
let url = `${basename(instanceName)}/api/v1/statuses/${statusId}/unpin` const url = `${basename(instanceName)}/api/v1/statuses/${statusId}/unpin`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }

View File

@ -2,11 +2,11 @@ import { get, post, DEFAULT_TIMEOUT, WRITE_TIMEOUT } from '../_utils/ajax'
import { auth, basename } from './utils' import { auth, basename } from './utils'
export async function getPoll (instanceName, accessToken, pollId) { export async function getPoll (instanceName, accessToken, pollId) {
let url = `${basename(instanceName)}/api/v1/polls/${pollId}` const url = `${basename(instanceName)}/api/v1/polls/${pollId}`
return get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT }) return get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT })
} }
export async function voteOnPoll (instanceName, accessToken, pollId, choices) { export async function voteOnPoll (instanceName, accessToken, pollId, choices) {
let url = `${basename(instanceName)}/api/v1/polls/${pollId}/votes` const url = `${basename(instanceName)}/api/v1/polls/${pollId}/votes`
return post(url, { choices }, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, { choices }, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }

View File

@ -2,11 +2,11 @@ import { post } from '../_utils/ajax'
import { basename, auth } from './utils' import { basename, auth } from './utils'
export async function reblogStatus (instanceName, accessToken, statusId) { export async function reblogStatus (instanceName, accessToken, statusId) {
let url = `${basename(instanceName)}/api/v1/statuses/${statusId}/reblog` const url = `${basename(instanceName)}/api/v1/statuses/${statusId}/reblog`
return post(url, null, auth(accessToken)) return post(url, null, auth(accessToken))
} }
export async function unreblogStatus (instanceName, accessToken, statusId) { export async function unreblogStatus (instanceName, accessToken, statusId) {
let url = `${basename(instanceName)}/api/v1/statuses/${statusId}/unreblog` const url = `${basename(instanceName)}/api/v1/statuses/${statusId}/unreblog`
return post(url, null, auth(accessToken)) return post(url, null, auth(accessToken))
} }

View File

@ -2,7 +2,7 @@ import { basename, auth } from './utils'
import { get, paramsString, DEFAULT_TIMEOUT } from '../_utils/ajax' import { get, paramsString, DEFAULT_TIMEOUT } from '../_utils/ajax'
export async function getRelationship (instanceName, accessToken, accountId) { export async function getRelationship (instanceName, accessToken, accountId) {
let url = `${basename(instanceName)}/api/v1/accounts/relationships?${paramsString({ id: accountId })}` const url = `${basename(instanceName)}/api/v1/accounts/relationships?${paramsString({ id: accountId })}`
let res = await get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT }) const res = await get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT })
return res[0] return res[0]
} }

View File

@ -2,7 +2,7 @@ import { auth, basename } from './utils'
import { post } from '../_utils/ajax' import { post } from '../_utils/ajax'
export async function report (instanceName, accessToken, accountId, statusIds, comment, forward) { export async function report (instanceName, accessToken, accountId, statusIds, comment, forward) {
let url = `${basename(instanceName)}/api/v1/reports` const url = `${basename(instanceName)}/api/v1/reports`
return post(url, { return post(url, {
account_id: accountId, account_id: accountId,
status_ids: statusIds, status_ids: statusIds,

View File

@ -2,11 +2,11 @@ import { post, WRITE_TIMEOUT } from '../_utils/ajax'
import { auth, basename } from './utils' import { auth, basename } from './utils'
export async function approveFollowRequest (instanceName, accessToken, accountId) { export async function approveFollowRequest (instanceName, accessToken, accountId) {
let url = `${basename(instanceName)}/api/v1/follow_requests/${accountId}/authorize` const url = `${basename(instanceName)}/api/v1/follow_requests/${accountId}/authorize`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }
export async function rejectFollowRequest (instanceName, accessToken, accountId) { export async function rejectFollowRequest (instanceName, accessToken, accountId) {
let url = `${basename(instanceName)}/api/v1/follow_requests/${accountId}/reject` const url = `${basename(instanceName)}/api/v1/follow_requests/${accountId}/reject`
return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, null, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }

View File

@ -2,7 +2,7 @@ import { get, paramsString, DEFAULT_TIMEOUT } from '../_utils/ajax'
import { auth, basename } from './utils' import { auth, basename } from './utils'
export function search (instanceName, accessToken, query, resolve = true, limit = 5, signal = null) { export function search (instanceName, accessToken, query, resolve = true, limit = 5, signal = null) {
let url = `${basename(instanceName)}/api/v1/search?` + paramsString({ const url = `${basename(instanceName)}/api/v1/search?` + paramsString({
q: query, q: query,
resolve, resolve,
limit limit

View File

@ -2,6 +2,6 @@ import { auth, basename } from './utils'
import { post, WRITE_TIMEOUT } from '../_utils/ajax' import { post, WRITE_TIMEOUT } from '../_utils/ajax'
export function setShowReblogs (instanceName, accessToken, accountId, showReblogs) { export function setShowReblogs (instanceName, accessToken, accountId, showReblogs) {
let url = `${basename(instanceName)}/api/v1/accounts/${accountId}/follow` const url = `${basename(instanceName)}/api/v1/accounts/${accountId}/follow`
return post(url, { reblogs: !!showReblogs }, auth(accessToken), { timeout: WRITE_TIMEOUT }) return post(url, { reblogs: !!showReblogs }, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }

View File

@ -3,9 +3,9 @@ import { DEFAULT_TIMEOUT, get, post, WRITE_TIMEOUT } from '../_utils/ajax'
export async function postStatus (instanceName, accessToken, text, inReplyToId, mediaIds, export async function postStatus (instanceName, accessToken, text, inReplyToId, mediaIds,
sensitive, spoilerText, visibility, poll) { sensitive, spoilerText, visibility, poll) {
let url = `${basename(instanceName)}/api/v1/statuses` const url = `${basename(instanceName)}/api/v1/statuses`
let body = { const body = {
status: text, status: text,
in_reply_to_id: inReplyToId, in_reply_to_id: inReplyToId,
media_ids: mediaIds, media_ids: mediaIds,
@ -15,8 +15,8 @@ export async function postStatus (instanceName, accessToken, text, inReplyToId,
poll: poll poll: poll
} }
for (let key of Object.keys(body)) { for (const key of Object.keys(body)) {
let value = body[key] const value = body[key]
// remove any unnecessary fields, except 'status' which must at least be an empty string // remove any unnecessary fields, except 'status' which must at least be an empty string
if (key !== 'status' && (!value || (Array.isArray(value) && !value.length))) { if (key !== 'status' && (!value || (Array.isArray(value) && !value.length))) {
delete body[key] delete body[key]
@ -27,11 +27,11 @@ export async function postStatus (instanceName, accessToken, text, inReplyToId,
} }
export async function getStatusContext (instanceName, accessToken, statusId) { export async function getStatusContext (instanceName, accessToken, statusId) {
let url = `${basename(instanceName)}/api/v1/statuses/${statusId}/context` const url = `${basename(instanceName)}/api/v1/statuses/${statusId}/context`
return get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT }) return get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT })
} }
export async function getStatus (instanceName, accessToken, statusId) { export async function getStatus (instanceName, accessToken, statusId) {
let url = `${basename(instanceName)}/api/v1/statuses/${statusId}` const url = `${basename(instanceName)}/api/v1/statuses/${statusId}`
return get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT }) return get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT })
} }

View File

@ -22,7 +22,7 @@ export class TimelineStream extends EventEmitter {
this._teardownEvents() this._teardownEvents()
// events-light currently does not support removeAllListeners() // events-light currently does not support removeAllListeners()
// https://github.com/patrick-steele-idem/events-light/issues/2 // https://github.com/patrick-steele-idem/events-light/issues/2
for (let event of ['open', 'close', 'reconnect', 'message']) { for (const event of ['open', 'close', 'reconnect', 'message']) {
this.removeAllListeners(event) this.removeAllListeners(event)
} }
} }

View File

@ -22,10 +22,10 @@ function getStreamName (timeline) {
} }
export function getStreamUrl (streamingApi, accessToken, timeline) { export function getStreamUrl (streamingApi, accessToken, timeline) {
let url = `${streamingApi}/api/v1/streaming` const url = `${streamingApi}/api/v1/streaming`
let streamName = getStreamName(timeline) const streamName = getStreamName(timeline)
let params = { const params = {
stream: streamName stream: streamName
} }

View File

@ -26,7 +26,7 @@ function getTimelineUrlPath (timeline) {
} }
export async function getTimeline (instanceName, accessToken, timeline, maxId, since, limit) { export async function getTimeline (instanceName, accessToken, timeline, maxId, since, limit) {
let timelineUrlName = getTimelineUrlPath(timeline) const timelineUrlName = getTimelineUrlPath(timeline)
let url = `${basename(instanceName)}/api/v1/${timelineUrlName}` let url = `${basename(instanceName)}/api/v1/${timelineUrlName}`
if (timeline.startsWith('tag/')) { if (timeline.startsWith('tag/')) {
@ -37,7 +37,7 @@ export async function getTimeline (instanceName, accessToken, timeline, maxId, s
url += '/' + timeline.split('/')[1] url += '/' + timeline.split('/')[1]
} }
let params = {} const params = {}
if (since) { if (since) {
params.since_id = since params.since_id = since
} }

View File

@ -2,6 +2,6 @@ import { WRITE_TIMEOUT, patch } from '../_utils/ajax'
import { auth, basename } from './utils' import { auth, basename } from './utils'
export async function updateCredentials (instanceName, accessToken, accountData) { export async function updateCredentials (instanceName, accessToken, accountData) {
let url = `${basename(instanceName)}/api/v1/accounts/update_credentials` const url = `${basename(instanceName)}/api/v1/accounts/update_credentials`
return patch(url, accountData, auth(accessToken), { timeout: WRITE_TIMEOUT }) return patch(url, accountData, auth(accessToken), { timeout: WRITE_TIMEOUT })
} }

View File

@ -2,11 +2,11 @@ import { get, DEFAULT_TIMEOUT } from '../_utils/ajax'
import { auth, basename } from './utils' import { auth, basename } from './utils'
export function getVerifyCredentials (instanceName, accessToken) { export function getVerifyCredentials (instanceName, accessToken) {
let url = `${basename(instanceName)}/api/v1/accounts/verify_credentials` const url = `${basename(instanceName)}/api/v1/accounts/verify_credentials`
return get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT }) return get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT })
} }
export function getAccount (instanceName, accessToken, accountId) { export function getAccount (instanceName, accessToken, accountId) {
let url = `${basename(instanceName)}/api/v1/accounts/${accountId}` const url = `${basename(instanceName)}/api/v1/accounts/${accountId}`
return get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT }) return get(url, auth(accessToken), { timeout: DEFAULT_TIMEOUT })
} }

View File

@ -11,6 +11,6 @@ export function basename (instanceName) {
export function auth (accessToken) { export function auth (accessToken) {
return { return {
'Authorization': `Bearer ${accessToken}` Authorization: `Bearer ${accessToken}`
} }
} }

View File

@ -61,12 +61,12 @@
}, },
methods: { methods: {
onClickAction (event) { onClickAction (event) {
let { action, accountId } = event const { action, accountId } = event
action.onclick(accountId) action.onclick(accountId)
}, },
async refreshAccounts () { async refreshAccounts () {
let { accountsFetcher } = this.get() const { accountsFetcher } = this.get()
let accounts = await accountsFetcher() const accounts = await accountsFetcher()
this.set({ accounts: accounts }) this.set({ accounts: accounts })
} }
} }

View File

@ -53,7 +53,7 @@
onPointerDown (e) { onPointerDown (e) {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
let rect = this.refs.indicator.getBoundingClientRect() const rect = this.refs.indicator.getBoundingClientRect()
this.set({ this.set({
dragging: true, dragging: true,
dragOffsetX: e.clientX - rect.left, dragOffsetX: e.clientX - rect.left,
@ -64,13 +64,13 @@
if (this.get().dragging) { if (this.get().dragging) {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
let { indicatorWidth, indicatorHeight, dragOffsetX, dragOffsetY } = this.get() const { indicatorWidth, indicatorHeight, dragOffsetX, dragOffsetY } = this.get()
throttledRaf(() => { throttledRaf(() => {
let rect = this.refs.area.getBoundingClientRect() const rect = this.refs.area.getBoundingClientRect()
let offsetX = dragOffsetX - (indicatorWidth / 2) const offsetX = dragOffsetX - (indicatorWidth / 2)
let offsetY = dragOffsetY - (indicatorHeight / 2) const offsetY = dragOffsetY - (indicatorHeight / 2)
let x = clamp((e.clientX - rect.left - offsetX) / rect.width) const x = clamp((e.clientX - rect.left - offsetX) / rect.width)
let y = clamp((e.clientY - rect.top - offsetY) / rect.height) const y = clamp((e.clientY - rect.top - offsetY) / rect.height)
this.set({ x, y }) this.set({ x, y })
this.fire('change', { x, y }) this.fire('change', { x, y })
}) })
@ -90,9 +90,9 @@
if (!e.target.classList.contains('draggable-indicator')) { if (!e.target.classList.contains('draggable-indicator')) {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
let rect = this.refs.area.getBoundingClientRect() const rect = this.refs.area.getBoundingClientRect()
let x = clamp((e.clientX - rect.left) / rect.width) const x = clamp((e.clientX - rect.left) / rect.width)
let y = clamp((e.clientY - rect.top) / rect.height) const y = clamp((e.clientY - rect.top) / rect.height)
this.set({ x, y }) this.set({ x, y })
this.fire('change', { x, y }) this.fire('change', { x, y })
} }

View File

@ -93,7 +93,7 @@
export default { export default {
oncreate () { oncreate () {
let { clickListener, elementId } = this.get() const { clickListener, elementId } = this.get()
if (clickListener) { if (clickListener) {
this.onClick = this.onClick.bind(this) this.onClick = this.onClick.bind(this)
this.refs.node.addEventListener('click', this.onClick) this.refs.node.addEventListener('click', this.onClick)
@ -103,7 +103,7 @@
} }
}, },
ondestroy () { ondestroy () {
let { clickListener } = this.get() const { clickListener } = this.get()
if (clickListener) { if (clickListener) {
this.refs.node.removeEventListener('click', this.onClick) this.refs.node.removeEventListener('click', this.onClick)
} }

View File

@ -109,14 +109,14 @@
export default { export default {
oncreate () { oncreate () {
let { name } = this.get() const { name } = this.get()
let indicator = this.refs.indicator const indicator = this.refs.indicator
on('animateNavPart1', this, ({ fromPage, toPage }) => { on('animateNavPart1', this, ({ fromPage, toPage }) => {
if (fromPage !== name) { if (fromPage !== name) {
return return
} }
mark('animateNavPart1 gBCR') mark('animateNavPart1 gBCR')
let fromRect = indicator.getBoundingClientRect() const fromRect = indicator.getBoundingClientRect()
stop('animateNavPart1 gBCR') stop('animateNavPart1 gBCR')
emit('animateNavPart2', { fromRect, fromPage, toPage }) emit('animateNavPart2', { fromRect, fromPage, toPage })
}) })
@ -125,12 +125,12 @@
return return
} }
mark('animateNavPart2 gBCR') mark('animateNavPart2 gBCR')
let toRect = indicator.getBoundingClientRect() const toRect = indicator.getBoundingClientRect()
stop('animateNavPart2 gBCR') stop('animateNavPart2 gBCR')
let translateX = fromRect.left - toRect.left const translateX = fromRect.left - toRect.left
let scaleX = fromRect.width / toRect.width const scaleX = fromRect.width / toRect.width
indicator.style.transform = `translateX(${translateX}px) scaleX(${scaleX})` indicator.style.transform = `translateX(${translateX}px) scaleX(${scaleX})`
let onTransitionEnd = () => { const onTransitionEnd = () => {
indicator.removeEventListener('transitionend', onTransitionEnd) indicator.removeEventListener('transitionend', onTransitionEnd)
indicator.classList.remove('animate') indicator.classList.remove('animate')
} }
@ -163,7 +163,7 @@
}, },
methods: { methods: {
onClick (e) { onClick (e) {
let { selected } = this.get() const { selected } = this.get()
if (!selected) { if (!selected) {
return return
} }

View File

@ -26,11 +26,11 @@
methods: { methods: {
goto, goto,
async showShortcutHelpDialog () { async showShortcutHelpDialog () {
let showShortcutHelpDialog = await importShowShortcutHelpDialog() const showShortcutHelpDialog = await importShowShortcutHelpDialog()
showShortcutHelpDialog() showShortcutHelpDialog()
}, },
async showComposeDialog () { async showComposeDialog () {
let showComposeDialog = await importShowComposeDialog() const showComposeDialog = await importShowComposeDialog()
showComposeDialog() showComposeDialog()
} }
} }

View File

@ -25,9 +25,9 @@
export default { export default {
async oncreate () { async oncreate () {
let { currentSrc } = this.get() const { currentSrc } = this.get()
try { try {
let image = new Image() const image = new Image()
image.src = currentSrc image.src = currentSrc
await decodeImage(image) await decodeImage(image)
this.set({ loaded: true }) this.set({ loaded: true })

View File

@ -25,11 +25,11 @@
}, },
methods: { methods: {
animate (animation) { animate (animation) {
let { reduceMotion } = this.store.get() const { reduceMotion } = this.store.get()
if (!animation || reduceMotion) { if (!animation || reduceMotion) {
return return
} }
let svg = this.refs.svg const svg = this.refs.svg
animate(svg, animation) animate(svg, animation)
} }
} }

Before

Width:  |  Height:  |  Size: 790 B

After

Width:  |  Height:  |  Size: 794 B

View File

@ -60,7 +60,7 @@
toggle (e) { toggle (e) {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
let { shown, mouseover } = this.get() const { shown, mouseover } = this.get()
if (!mouseover) { if (!mouseover) {
this.set({ shown: !shown }) this.set({ shown: !shown })
} }

View File

@ -87,8 +87,8 @@
methods: { methods: {
onPinClick (e) { onPinClick (e) {
e.preventDefault() e.preventDefault()
let { currentInstance, pinnedPages } = this.store.get() const { currentInstance, pinnedPages } = this.store.get()
let { href } = this.get() const { href } = this.get()
pinnedPages[currentInstance] = href pinnedPages[currentInstance] = href
this.store.set({ pinnedPages: pinnedPages }) this.store.set({ pinnedPages: pinnedPages })
this.store.save() this.store.save()

View File

@ -95,7 +95,7 @@
}, },
methods: { methods: {
onClick (e) { onClick (e) {
let { realm, dialogId, href } = this.get() const { realm, dialogId, href } = this.get()
if (realm === 'dialog') { if (realm === 'dialog') {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()

View File

@ -105,7 +105,7 @@
export default { export default {
oncreate () { oncreate () {
let { realm, replySpoiler, replyVisibility } = this.get() const { realm, replySpoiler, replyVisibility } = this.get()
if (realm !== 'home' && realm !== 'dialog') { if (realm !== 'home' && realm !== 'dialog') {
// if this is a reply, populate the handle immediately // if this is a reply, populate the handle immediately
/* no await */ insertHandleForReply(realm) /* no await */ insertHandleForReply(realm)
@ -179,7 +179,7 @@
}, },
methods: { methods: {
doPostStatus () { doPostStatus () {
let { const {
text, text,
media, media,
postPrivacyKey, postPrivacyKey,
@ -190,17 +190,17 @@
inReplyToId, // delete-and-redraft replies, using standard id inReplyToId, // delete-and-redraft replies, using standard id
poll poll
} = this.get() } = this.get()
let sensitive = media.length && !!contentWarning const sensitive = media.length && !!contentWarning
let mediaIds = media.map(_ => _.data.id) const mediaIds = media.map(_ => _.data.id)
let mediaDescriptions = media.map(_ => _.description) const mediaDescriptions = media.map(_ => _.description)
let mediaFocalPoints = media.map(_ => [_.focusX, _.focusY]) const mediaFocalPoints = media.map(_ => [_.focusX, _.focusY])
let inReplyTo = inReplyToId || ((realm === 'home' || realm === 'dialog') ? null : realm) const inReplyTo = inReplyToId || ((realm === 'home' || realm === 'dialog') ? null : realm)
if (overLimit || (!text && !media.length)) { if (overLimit || (!text && !media.length)) {
return // do nothing if invalid return // do nothing if invalid
} }
let hasPoll = poll && poll.options && poll.options.length const hasPoll = poll && poll.options && poll.options.length
if (hasPoll) { if (hasPoll) {
// validate poll // validate poll
if (poll.options.length < 2 || !poll.options.every(Boolean)) { if (poll.options.length < 2 || !poll.options.every(Boolean)) {
@ -209,7 +209,7 @@
} }
// convert internal poll format to the format Mastodon's REST API uses // convert internal poll format to the format Mastodon's REST API uses
let pollToPost = hasPoll && { const pollToPost = hasPoll && {
expires_in: (poll.expiry || POLL_EXPIRY_DEFAULT).toString(), expires_in: (poll.expiry || POLL_EXPIRY_DEFAULT).toString(),
multiple: !!poll.multiple, multiple: !!poll.multiple,
options: poll.options options: poll.options

View File

@ -39,7 +39,7 @@
const saveText = debounce(() => scheduleIdleTask(() => this.store.save()), 1000) const saveText = debounce(() => scheduleIdleTask(() => this.store.save()), 1000)
this.observe('rawText', rawText => { this.observe('rawText', rawText => {
let { realm } = this.get() const { realm } = this.get()
this.store.setComposeData(realm, { this.store.setComposeData(realm, {
contentWarning: rawText contentWarning: rawText
}) })

View File

@ -76,9 +76,9 @@
}), }),
methods: { methods: {
async onFileDrop (e) { async onFileDrop (e) {
let { files } = e const { files } = e
let { realm } = this.get() const { realm } = this.get()
for (let file of files) { // upload one at a time to avoid hitting limits for (const file of files) { // upload one at a time to avoid hitting limits
await doMediaUpload(realm, file) await doMediaUpload(realm, file)
} }
} }

View File

@ -83,10 +83,10 @@
methods: { methods: {
observe, observe,
setupSyncFromStore () { setupSyncFromStore () {
let textarea = this.refs.textarea const textarea = this.refs.textarea
let firstTime = true let firstTime = true
this.observe('text', text => { this.observe('text', text => {
let { rawText } = this.get() const { rawText } = this.get()
if (rawText !== text) { if (rawText !== text) {
this.set({ rawText: text }) this.set({ rawText: text })
// this next autosize is required to resize after // this next autosize is required to resize after
@ -97,7 +97,7 @@
} }
if (firstTime) { if (firstTime) {
firstTime = false firstTime = false
let { autoFocus } = this.get() const { autoFocus } = this.get()
if (autoFocus) { if (autoFocus) {
requestAnimationFrame(() => textarea.focus({ preventScroll: true })) requestAnimationFrame(() => textarea.focus({ preventScroll: true }))
} }
@ -109,14 +109,14 @@
this.observe('rawText', rawText => { this.observe('rawText', rawText => {
mark('observe rawText') mark('observe rawText')
let { realm } = this.get() const { realm } = this.get()
this.store.setComposeData(realm, { text: rawText }) this.store.setComposeData(realm, { text: rawText })
saveStore() saveStore()
stop('observe rawText') stop('observe rawText')
}, { init: false }) }, { init: false })
}, },
setupAutosize () { setupAutosize () {
let textarea = this.refs.textarea const textarea = this.refs.textarea
requestAnimationFrame(() => { requestAnimationFrame(() => {
mark('autosize()') mark('autosize()')
autosize(textarea) autosize(textarea)
@ -135,7 +135,7 @@
}, },
onFocus () { onFocus () {
scheduleIdleTask(() => { scheduleIdleTask(() => {
let { realm } = this.get() const { realm } = this.get()
this.store.set({ currentComposeRealm: realm }) this.store.set({ currentComposeRealm: realm })
this.store.setForCurrentAutosuggest({ composeFocused: true }) this.store.setForCurrentAutosuggest({ composeFocused: true })
}) })
@ -146,7 +146,7 @@
}) })
}, },
onKeydown (e) { onKeydown (e) {
let { keyCode } = e const { keyCode } = e
// ctrl or cmd (on macs) was pressed; ctrl-enter means post a toot // ctrl or cmd (on macs) was pressed; ctrl-enter means post a toot
const ctrlPressed = e.getModifierState('Control') || e.getModifierState('Meta') const ctrlPressed = e.getModifierState('Control') || e.getModifierState('Meta')
switch (keyCode) { switch (keyCode) {
@ -172,7 +172,7 @@
} }
}, },
clickSelectedAutosuggestion (event) { clickSelectedAutosuggestion (event) {
let { const {
autosuggestShown, autosuggestShown,
autosuggestType autosuggestType
} = this.store.get() } = this.store.get()
@ -183,7 +183,7 @@
event.stopPropagation() event.stopPropagation()
const clickAutosuggestedItem = async () => { const clickAutosuggestedItem = async () => {
let { realm } = this.get() const { realm } = this.get()
/* autosuggestSelecting prevents a flash of searched content */ /* autosuggestSelecting prevents a flash of searched content */
this.store.setForCurrentAutosuggest({ autosuggestSelecting: true }) this.store.setForCurrentAutosuggest({ autosuggestSelecting: true })
if (autosuggestType === 'account') { if (autosuggestType === 'account') {
@ -217,7 +217,7 @@
event.stopPropagation() event.stopPropagation()
}, },
clearAutosuggestions (event) { clearAutosuggestions (event) {
let { autosuggestShown } = this.store.get() const { autosuggestShown } = this.store.get()
if (!autosuggestShown) { if (!autosuggestShown) {
return return
} }

View File

@ -25,13 +25,13 @@
export default { export default {
oncreate () { oncreate () {
let { lengthAsFraction } = this.get() const { lengthAsFraction } = this.get()
this.set({ lengthAsFractionDeferred: lengthAsFraction }) this.set({ lengthAsFractionDeferred: lengthAsFraction })
// perf improvement for keyboard input latency // perf improvement for keyboard input latency
this.observe('lengthAsFraction', () => { this.observe('lengthAsFraction', () => {
scheduleIdleTask(() => { scheduleIdleTask(() => {
mark('set lengthAsFractionDeferred') mark('set lengthAsFractionDeferred')
let { lengthAsFraction } = this.get() const { lengthAsFraction } = this.get()
this.set({ lengthAsFractionDeferred: lengthAsFraction }) this.set({ lengthAsFractionDeferred: lengthAsFraction })
stop('set lengthAsFractionDeferred') stop('set lengthAsFractionDeferred')
requestAnimationFrame(() => this.set({ shouldAnimate: true })) requestAnimationFrame(() => this.set({ shouldAnimate: true }))
@ -46,7 +46,7 @@
computed: { computed: {
lengthAsFraction: ({ length, $maxStatusChars }) => { lengthAsFraction: ({ length, $maxStatusChars }) => {
// We don't need to update the gauge for every decimal point, so round it to the nearest 0.02 // We don't need to update the gauge for every decimal point, so round it to the nearest 0.02
let int = Math.round(Math.min($maxStatusChars, length) / $maxStatusChars * 100) const int = Math.round(Math.min($maxStatusChars, length) / $maxStatusChars * 100)
return (int - (int % 2)) / 100 return (int - (int % 2)) / 100
} }
}, },

View File

@ -23,13 +23,13 @@
export default { export default {
oncreate () { oncreate () {
let { lengthToDisplay } = this.get() const { lengthToDisplay } = this.get()
this.set({ lengthToDisplayDeferred: lengthToDisplay }) this.set({ lengthToDisplayDeferred: lengthToDisplay })
// perf improvement for keyboard input latency // perf improvement for keyboard input latency
this.observe('lengthToDisplay', () => { this.observe('lengthToDisplay', () => {
scheduleIdleTask(() => { scheduleIdleTask(() => {
mark('set lengthToDisplayDeferred') mark('set lengthToDisplayDeferred')
let { lengthToDisplay } = this.get() const { lengthToDisplay } = this.get()
this.set({ lengthToDisplayDeferred: lengthToDisplay }) this.set({ lengthToDisplayDeferred: lengthToDisplay })
stop('set lengthToDisplayDeferred') stop('set lengthToDisplayDeferred')
}) })

View File

@ -172,13 +172,13 @@
setupSyncFromStore () { setupSyncFromStore () {
this.observe('media', media => { this.observe('media', media => {
media = media || [] media = media || []
let { index, rawText } = this.get() const { index, rawText } = this.get()
let text = get(media, [index, 'description'], '') const text = get(media, [index, 'description'], '')
if (rawText !== text) { if (rawText !== text) {
this.set({ rawText: text }) this.set({ rawText: text })
} }
let focusX = get(media, [index, 'focusX'], 0) const focusX = get(media, [index, 'focusX'], 0)
let focusY = get(media, [index, 'focusY'], 0) const focusY = get(media, [index, 'focusY'], 0)
this.set({ focusX, focusY }) this.set({ focusX, focusY })
}) })
}, },
@ -186,7 +186,7 @@
const saveStore = debounce(() => scheduleIdleTask(() => this.store.save()), 1000) const saveStore = debounce(() => scheduleIdleTask(() => this.store.save()), 1000)
this.observe('rawText', rawText => { this.observe('rawText', rawText => {
let { realm, index, media } = this.get() const { realm, index, media } = this.get()
if (media[index].description !== rawText) { if (media[index].description !== rawText) {
media[index].description = rawText media[index].description = rawText
this.store.setComposeData(realm, { media }) this.store.setComposeData(realm, { media })
@ -201,12 +201,12 @@
autosize.destroy(this.refs.textarea) autosize.destroy(this.refs.textarea)
}, },
onDeleteMedia () { onDeleteMedia () {
let { realm, index } = this.get() const { realm, index } = this.get()
deleteMedia(realm, index) deleteMedia(realm, index)
}, },
async onSetFocalPoint () { async onSetFocalPoint () {
let { realm, index } = this.get() const { realm, index } = this.get()
let showMediaFocalPointDialog = await importMediaFocalPointDialog() const showMediaFocalPointDialog = await importMediaFocalPointDialog()
showMediaFocalPointDialog(realm, index) showMediaFocalPointDialog(realm, index)
} }
}, },

View File

@ -83,15 +83,15 @@
function flushPollOptionsToDom (poll, realm) { function flushPollOptionsToDom (poll, realm) {
for (let i = 0; i < poll.options.length; i++) { for (let i = 0; i < poll.options.length; i++) {
let element = document.getElementById(`poll-option-${realm}-${i}`) const element = document.getElementById(`poll-option-${realm}-${i}`)
element.value = poll.options[i] element.value = poll.options[i]
} }
} }
export default { export default {
oncreate () { oncreate () {
let { realm } = this.get() const { realm } = this.get()
let poll = this.store.getComposeData(realm, 'poll') const poll = this.store.getComposeData(realm, 'poll')
flushPollOptionsToDom(poll, realm) flushPollOptionsToDom(poll, realm)
document.getElementById(`poll-option-multiple-${realm}`).checked = !!poll.multiple document.getElementById(`poll-option-multiple-${realm}`).checked = !!poll.multiple
this.set({ pollExpiryDefaultValue: poll.expiry || POLL_EXPIRY_DEFAULT }) this.set({ pollExpiryDefaultValue: poll.expiry || POLL_EXPIRY_DEFAULT })
@ -104,26 +104,26 @@
methods: { methods: {
onChange (i) { onChange (i) {
scheduleIdleTask(() => { scheduleIdleTask(() => {
let { realm } = this.get() const { realm } = this.get()
let element = document.getElementById(`poll-option-${realm}-${i}`) const element = document.getElementById(`poll-option-${realm}-${i}`)
let poll = this.store.getComposeData(realm, 'poll') const poll = this.store.getComposeData(realm, 'poll')
poll.options[i] = element.value poll.options[i] = element.value
this.store.setComposeData(realm, { poll }) this.store.setComposeData(realm, { poll })
}) })
}, },
onMultipleChange () { onMultipleChange () {
requestAnimationFrame(() => { requestAnimationFrame(() => {
let { realm } = this.get() const { realm } = this.get()
let element = document.getElementById(`poll-option-multiple-${realm}`) const element = document.getElementById(`poll-option-multiple-${realm}`)
let poll = this.store.getComposeData(realm, 'poll') const poll = this.store.getComposeData(realm, 'poll')
poll.multiple = !!element.checked poll.multiple = !!element.checked
this.store.setComposeData(realm, { poll }) this.store.setComposeData(realm, { poll })
}) })
}, },
onDeleteClick (i) { onDeleteClick (i) {
requestAnimationFrame(() => { requestAnimationFrame(() => {
let { realm } = this.get() const { realm } = this.get()
let poll = this.store.getComposeData(realm, 'poll') const poll = this.store.getComposeData(realm, 'poll')
poll.options.splice(i, 1) poll.options.splice(i, 1)
this.store.setComposeData(realm, { poll }) this.store.setComposeData(realm, { poll })
flushPollOptionsToDom(poll, realm) flushPollOptionsToDom(poll, realm)
@ -131,8 +131,8 @@
}, },
onAddClick () { onAddClick () {
requestAnimationFrame(() => { requestAnimationFrame(() => {
let { realm } = this.get() const { realm } = this.get()
let poll = this.store.getComposeData(realm, 'poll') const poll = this.store.getComposeData(realm, 'poll')
if (!poll.options.length !== 4) { if (!poll.options.length !== 4) {
poll.options.push('') poll.options.push('')
} }
@ -141,9 +141,9 @@
}, },
onExpiryChange (e) { onExpiryChange (e) {
requestAnimationFrame(() => { requestAnimationFrame(() => {
let { realm } = this.get() const { realm } = this.get()
let { value } = e.target const { value } = e.target
let poll = this.store.getComposeData(realm, 'poll') const poll = this.store.getComposeData(realm, 'poll')
poll.expiry = parseInt(value, 10) poll.expiry = parseInt(value, 10)
this.store.setComposeData(realm, { poll }) this.store.setComposeData(realm, { poll })
}) })

Some files were not shown because too many files have changed in this diff Show More