diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b711c7fc9..99c85dd36 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -34,23 +34,12 @@ check-changelog: - apk add git - sh ./tools/check-changelog -lint-eslint: +lint: stage: lint script: - yarn - - yarn ci-eslint - -lint-biome: - stage: lint - script: - - yarn - - yarn ci-biome - -lint-stylelint: - stage: lint - script: - - yarn - - yarn ci-stylelint + - yarn lint + - yarn stylelint test: stage: test diff --git a/CHANGELOG.md b/CHANGELOG.md index b3d38ea24..20c9c2693 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,27 +3,6 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). -## 2.10.0 -### Changed -- Temporary changes modal now shows actual countdown instead of fixed timeout -- Disabled elements are more disabled now -- Rearranged and split settings to make more sense and be less of a wall of text -- On mobile settings now take up full width and presented in navigation style -improved styles for settings - -### Added -- Most of the remaining AdminFE tabs were added into Admin Dashboard -- It's now possible to customize PWA Manfiest from PleromaFE -- Make every configuration option default-overridable by instance admins - -### Fixed -- Fixed settings not appearing if user never touched "show advanced" toggle -- Fix display of the broken/deleted/banned users -- Fixed incorrect emoji display in post interaction lists -- Fixed list title not being saved when editing -- Fixed poll notifications not being expandable - - ## 2.9.3 ### Fixed - Being unable to update profile @@ -95,8 +74,8 @@ This does not guarantee that browsers will or will not work. - Support displaying time in absolute format - Add draft management system - Compress most kinds of images on upload. -- Added option to always convert images to JPEG format instead of using WebP when compressing images. -- Added configurable image compression option in general settings, allowing users to control whether images are compressed before upload. +- Added option to always convert images to JPEG format instead of using WebP when compressing images. +- Added configurable image compression option in general settings, allowing users to control whether images are compressed before upload. - Inform users that Smithereen public polls are public - Splash screen + loading indicator to make process of identifying initialization issues and load performance - UI for making v3 themes and palettes, support for bundling v3 themes diff --git a/biome.json b/biome.json deleted file mode 100644 index 9b4ee2663..000000000 --- a/biome.json +++ /dev/null @@ -1,129 +0,0 @@ -{ - "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json", - "vcs": { - "enabled": true, - "clientKind": "git", - "useIgnoreFile": true - }, - "files": { - "includes": ["**", "!!**/dist", "!!tools/emojis.json"] - }, - "formatter": { - "enabled": true, - "indentStyle": "space" - }, - "linter": { - "enabled": true, - "domains": { - "vue": "recommended" - }, - "rules": { - "recommended": false, - "complexity": { - "noAdjacentSpacesInRegex": "error", - "noExtraBooleanCast": "error", - "noUselessCatch": "error", - "noUselessEscapeInRegex": "error" - }, - "correctness": { - "noConstAssign": "error", - "noConstantCondition": "error", - "noEmptyCharacterClassInRegex": "error", - "noEmptyPattern": "error", - "noGlobalObjectCalls": "error", - "noInvalidBuiltinInstantiation": "error", - "noInvalidConstructorSuper": "error", - "noNonoctalDecimalEscape": "error", - "noPrecisionLoss": "error", - "noSelfAssign": "error", - "noSetterReturn": "error", - "noSwitchDeclarations": "error", - "noUndeclaredVariables": "error", - "noUnreachable": "error", - "noUnreachableSuper": "error", - "noUnsafeFinally": "error", - "noUnsafeOptionalChaining": "error", - "noUnusedLabels": "error", - "noUnusedPrivateClassMembers": "error", - "noUnusedVariables": "error", - "useIsNan": "error", - "useValidForDirection": "error", - "useValidTypeof": "error", - "useYield": "error" - }, - "suspicious": { - "noAsyncPromiseExecutor": "error", - "noCatchAssign": "error", - "noClassAssign": "error", - "noCompareNegZero": "error", - "noConstantBinaryExpressions": "error", - "noControlCharactersInRegex": "error", - "noDebugger": "error", - "noDuplicateCase": "error", - "noDuplicateClassMembers": "error", - "noDuplicateElseIf": "error", - "noDuplicateObjectKeys": "error", - "noDuplicateParameters": "error", - "noEmptyBlockStatements": "error", - "noFallthroughSwitchClause": "error", - "noFunctionAssign": "error", - "noGlobalAssign": "error", - "noImportAssign": "error", - "noIrregularWhitespace": "error", - "noMisleadingCharacterClass": "error", - "noPrototypeBuiltins": "error", - "noRedeclare": "error", - "noShadowRestrictedNames": "error", - "noSparseArray": "error", - "noUnsafeNegation": "error", - "noUselessRegexBackrefs": "error", - "noWith": "error", - "useGetterReturn": "error" - } - } - }, - "javascript": { - "formatter": { - "quoteStyle": "single", - "semicolons": "asNeeded" - }, - "globals": [] - }, - "overrides": [ - { - "includes": ["**/*.spec.js", "test/fixtures/*.js"], - "javascript": { - "globals": [ - "vi", - "describe", - "it", - "test", - "expect", - "before", - "beforeEach", - "after", - "afterEach" - ] - } - }, - { - "includes": ["**/*.vue"], - "linter": { - "rules": { - "style": { - "useConst": "off", - "useImportType": "off" - }, - "correctness": { - "noUnusedVariables": "off", - "noUnusedImports": "off" - } - } - } - } - ], - "assist": { - "enabled": true, - "actions": { "source": { "organizeImports": "on" } } - } -} diff --git a/build/check-versions.mjs b/build/check-versions.mjs index 8c5968a30..73c1eeb15 100644 --- a/build/check-versions.mjs +++ b/build/check-versions.mjs @@ -1,5 +1,5 @@ -import chalk from 'chalk' import semver from 'semver' +import chalk from 'chalk' import packageConfig from '../package.json' with { type: 'json' } @@ -7,8 +7,8 @@ var versionRequirements = [ { name: 'node', currentVersion: semver.clean(process.version), - versionRequirement: packageConfig.engines.node, - }, + versionRequirement: packageConfig.engines.node + } ] export default function () { @@ -16,22 +16,15 @@ export default function () { for (let i = 0; i < versionRequirements.length; i++) { const mod = versionRequirements[i] if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { - warnings.push( - mod.name + - ': ' + - chalk.red(mod.currentVersion) + - ' should be ' + - chalk.green(mod.versionRequirement), + warnings.push(mod.name + ': ' + + chalk.red(mod.currentVersion) + ' should be ' + + chalk.green(mod.versionRequirement) ) } } if (warnings.length) { - console.warn( - chalk.yellow( - '\nTo use this template, you must update following to modules:\n', - ), - ) + console.warn(chalk.yellow('\nTo use this template, you must update following to modules:\n')) for (let i = 0; i < warnings.length; i++) { const warning = warnings[i] console.warn(' ' + warning) diff --git a/build/commit_hash.js b/build/commit_hash.js index c60355804..c104af5d9 100644 --- a/build/commit_hash.js +++ b/build/commit_hash.js @@ -1,8 +1,8 @@ import childProcess from 'child_process' -export const getCommitHash = () => { - const subst = '$Format:%h$' - if (!subst.match(/Format:/)) { +export const getCommitHash = (() => { + const subst = "$Format:%h$" + if(!subst.match(/Format:/)) { return subst } else { try { @@ -15,4 +15,4 @@ export const getCommitHash = () => { return 'UNKNOWN' } } -} +}) diff --git a/build/copy_plugin.js b/build/copy_plugin.js index 4f020f359..a783fe7ff 100644 --- a/build/copy_plugin.js +++ b/build/copy_plugin.js @@ -1,8 +1,8 @@ -import { cp } from 'node:fs/promises' -import { resolve } from 'node:path' import serveStatic from 'serve-static' +import { resolve } from 'node:path' +import { cp } from 'node:fs/promises' -const getPrefix = (s) => { +const getPrefix = s => { const padEnd = s.endsWith('/') ? s : s + '/' return padEnd.startsWith('/') ? padEnd : '/' + padEnd } @@ -13,31 +13,28 @@ const copyPlugin = ({ inUrl, inFs }) => { let copyTarget const handler = serveStatic(inFs) - return [ - { - name: 'copy-plugin-serve', - apply: 'serve', - configureServer(server) { - server.middlewares.use(prefix, handler) - }, + return [{ + name: 'copy-plugin-serve', + apply: 'serve', + configureServer (server) { + server.middlewares.use(prefix, handler) + } + }, { + name: 'copy-plugin-build', + apply: 'build', + configResolved (config) { + copyTarget = resolve(config.root, config.build.outDir, subdir) }, - { - name: 'copy-plugin-build', - apply: 'build', - configResolved(config) { - copyTarget = resolve(config.root, config.build.outDir, subdir) - }, - closeBundle: { - order: 'post', - sequential: true, - async handler() { - console.info(`Copying '${inFs}' to ${copyTarget}...`) - await cp(inFs, copyTarget, { recursive: true }) - console.info('Done.') - }, - }, - }, - ] + closeBundle: { + order: 'post', + sequential: true, + async handler () { + console.log(`Copying '${inFs}' to ${copyTarget}...`) + await cp(inFs, copyTarget, { recursive: true }) + console.log('Done.') + } + } + }] } export default copyPlugin diff --git a/build/emojis_plugin.js b/build/emojis_plugin.js index 43a665e50..aed52066d 100644 --- a/build/emojis_plugin.js +++ b/build/emojis_plugin.js @@ -1,22 +1,21 @@ -import { access } from 'node:fs/promises' import { resolve } from 'node:path' -import { languages } from '../src/i18n/languages.js' +import { access } from 'node:fs/promises' +import { languages, langCodeToCldrName } from '../src/i18n/languages.js' const annotationsImportPrefix = '@kazvmoe-infra/unicode-emoji-json/annotations/' const specialAnnotationsLocale = { - ja_easy: 'ja', + ja_easy: 'ja' } -const internalToAnnotationsLocale = (internal) => - specialAnnotationsLocale[internal] || internal +const internalToAnnotationsLocale = (internal) => specialAnnotationsLocale[internal] || internal // This gets all the annotations that are accessible (whose language // can be chosen in the settings). Data for other languages are // discarded because there is no way for it to be fetched. const getAllAccessibleAnnotations = async (projectRoot) => { - const imports = ( - await Promise.all( - languages.map(async (lang) => { + const imports = (await Promise.all( + languages + .map(async lang => { const destLang = internalToAnnotationsLocale(lang) const importModule = `${annotationsImportPrefix}${destLang}.json` const importFile = resolve(projectRoot, 'node_modules', importModule) @@ -24,14 +23,11 @@ const getAllAccessibleAnnotations = async (projectRoot) => { await access(importFile) return `'${lang}': () => import('${importModule}')` } catch (e) { - console.error(e) return } - }), - ) - ) - .filter((k) => k) - .join(',\n') + }))) + .filter(k => k) + .join(',\n') return ` export const annotationsLoader = { @@ -47,21 +43,21 @@ const emojisPlugin = () => { let projectRoot return { name: 'emojis-plugin', - configResolved(conf) { + configResolved (conf) { projectRoot = conf.root }, - resolveId(id) { + resolveId (id) { if (id === emojiAnnotationsId) { return emojiAnnotationsIdResolved } return null }, - async load(id) { + async load (id) { if (id === emojiAnnotationsIdResolved) { return await getAllAccessibleAnnotations(projectRoot) } return null - }, + } } } diff --git a/build/msw_plugin.js b/build/msw_plugin.js index c4e9098c5..f544348fc 100644 --- a/build/msw_plugin.js +++ b/build/msw_plugin.js @@ -1,5 +1,5 @@ -import { readFile } from 'node:fs/promises' import { resolve } from 'node:path' +import { readFile } from 'node:fs/promises' const target = 'node_modules/msw/lib/mockServiceWorker.js' @@ -8,10 +8,10 @@ const mswPlugin = () => { return { name: 'msw-plugin', apply: 'serve', - configResolved(conf) { + configResolved (conf) { projectRoot = conf.root }, - configureServer(server) { + configureServer (server) { server.middlewares.use(async (req, res, next) => { if (req.path === '/mockServiceWorker.js') { const file = await readFile(resolve(projectRoot, target)) @@ -21,7 +21,7 @@ const mswPlugin = () => { next() } }) - }, + } } } diff --git a/build/service_worker_messages.js b/build/service_worker_messages.js index 0ebd2b471..c078e8563 100644 --- a/build/service_worker_messages.js +++ b/build/service_worker_messages.js @@ -1,11 +1,11 @@ +import { languages, langCodeToJsonName } from '../src/i18n/languages.js' import { readFile } from 'node:fs/promises' import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' -import { langCodeToJsonName, languages } from '../src/i18n/languages.js' const i18nDir = resolve( dirname(dirname(fileURLToPath(import.meta.url))), - 'src/i18n', + 'src/i18n' ) export const i18nFiles = languages.reduce((acc, lang) => { @@ -16,15 +16,13 @@ export const i18nFiles = languages.reduce((acc, lang) => { }, {}) export const generateServiceWorkerMessages = async () => { - const msgArray = await Promise.all( - Object.entries(i18nFiles).map(async ([lang, file]) => { - const fileContent = await readFile(file, 'utf-8') - const msg = { - notifications: JSON.parse(fileContent).notifications || {}, - } - return [lang, msg] - }), - ) + const msgArray = await Promise.all(Object.entries(i18nFiles).map(async ([lang, file]) => { + const fileContent = await readFile(file, 'utf-8') + const msg = { + notifications: JSON.parse(fileContent).notifications || {} + } + return [lang, msg] + })) return msgArray.reduce((acc, [lang, msg]) => { acc[lang] = msg return acc diff --git a/build/sw_plugin.js b/build/sw_plugin.js index 88520ba31..a2c792b7d 100644 --- a/build/sw_plugin.js +++ b/build/sw_plugin.js @@ -1,12 +1,9 @@ -import { readFile } from 'node:fs/promises' -import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' -import * as esbuild from 'esbuild' +import { dirname, resolve } from 'node:path' +import { readFile } from 'node:fs/promises' import { build } from 'vite' -import { - generateServiceWorkerMessages, - i18nFiles, -} from './service_worker_messages.js' +import * as esbuild from 'esbuild' +import { generateServiceWorkerMessages, i18nFiles } from './service_worker_messages.js' const getSWMessagesAsText = async () => { const messages = await generateServiceWorkerMessages() @@ -17,10 +14,14 @@ const projectRoot = dirname(dirname(fileURLToPath(import.meta.url))) const swEnvName = 'virtual:pleroma-fe/service_worker_env' const swEnvNameResolved = '\0' + swEnvName const getDevSwEnv = () => `self.serviceWorkerOption = { assets: [] };` -const getProdSwEnv = ({ assets }) => - `self.serviceWorkerOption = { assets: ${JSON.stringify(assets)} };` +const getProdSwEnv = ({ assets }) => `self.serviceWorkerOption = { assets: ${JSON.stringify(assets)} };` -export const devSwPlugin = ({ swSrc, swDest, transformSW, alias }) => { +export const devSwPlugin = ({ + swSrc, + swDest, + transformSW, + alias +}) => { const swFullSrc = resolve(projectRoot, swSrc) const esbuildAlias = {} Object.entries(alias).forEach(([source, dest]) => { @@ -30,10 +31,9 @@ export const devSwPlugin = ({ swSrc, swDest, transformSW, alias }) => { return { name: 'dev-sw-plugin', apply: 'serve', - configResolved() { - /* no-op */ + configResolved (conf) { }, - resolveId(id) { + resolveId (id) { const name = id.startsWith('/') ? id.slice(1) : id if (name === swDest) { return swFullSrc @@ -42,7 +42,7 @@ export const devSwPlugin = ({ swSrc, swDest, transformSW, alias }) => { } return null }, - async load(id) { + async load (id) { if (id === swFullSrc) { return readFile(swFullSrc, 'utf-8') } else if (id === swEnvNameResolved) { @@ -55,7 +55,7 @@ export const devSwPlugin = ({ swSrc, swDest, transformSW, alias }) => { * during dev, and firefox does not support ESM as service worker * https://bugzilla.mozilla.org/show_bug.cgi?id=1360870 */ - async transform(code, id) { + async transform (code, id) { if (id === swFullSrc && transformSW) { const res = await esbuild.build({ entryPoints: [swSrc], @@ -63,54 +63,52 @@ export const devSwPlugin = ({ swSrc, swDest, transformSW, alias }) => { write: false, outfile: 'sw-pleroma.js', alias: esbuildAlias, - plugins: [ - { - name: 'vite-like-root-resolve', - setup(b) { - b.onResolve({ filter: new RegExp(/^\//) }, (args) => ({ - path: resolve(projectRoot, args.path.slice(1)), + plugins: [{ + name: 'vite-like-root-resolve', + setup (b) { + b.onResolve( + { filter: new RegExp(/^\//) }, + args => ({ + path: resolve(projectRoot, args.path.slice(1)) + }) + ) + } + }, { + name: 'sw-messages', + setup (b) { + b.onResolve( + { filter: new RegExp('^' + swMessagesName + '$') }, + args => ({ + path: args.path, + namespace: 'sw-messages' })) - }, - }, - { - name: 'sw-messages', - setup(b) { - b.onResolve( - { filter: new RegExp('^' + swMessagesName + '$') }, - (args) => ({ - path: args.path, - namespace: 'sw-messages', - }), - ) - b.onLoad( - { filter: /.*/, namespace: 'sw-messages' }, - async () => ({ - contents: await getSWMessagesAsText(), - }), - ) - }, - }, - { - name: 'sw-env', - setup(b) { - b.onResolve( - { filter: new RegExp('^' + swEnvName + '$') }, - (args) => ({ - path: args.path, - namespace: 'sw-env', - }), - ) - b.onLoad({ filter: /.*/, namespace: 'sw-env' }, () => ({ - contents: getDevSwEnv(), + b.onLoad( + { filter: /.*/, namespace: 'sw-messages' }, + async () => ({ + contents: await getSWMessagesAsText() })) - }, - }, - ], + } + }, { + name: 'sw-env', + setup (b) { + b.onResolve( + { filter: new RegExp('^' + swEnvName + '$') }, + args => ({ + path: args.path, + namespace: 'sw-env' + })) + b.onLoad( + { filter: /.*/, namespace: 'sw-env' }, + () => ({ + contents: getDevSwEnv() + })) + } + }] }) const text = res.outputFiles[0].text return text } - }, + } } } @@ -120,13 +118,16 @@ export const devSwPlugin = ({ swSrc, swDest, transformSW, alias }) => { // however, we must compile the service worker to iife because of browser support. // Run another vite build just for the service worker targeting iife at // the end of the build. -export const buildSwPlugin = ({ swSrc, swDest }) => { +export const buildSwPlugin = ({ + swSrc, + swDest, +}) => { let config return { name: 'build-sw-plugin', enforce: 'post', apply: 'build', - configResolved(resolvedConfig) { + configResolved (resolvedConfig) { config = { define: resolvedConfig.define, resolve: resolvedConfig.resolve, @@ -137,50 +138,50 @@ export const buildSwPlugin = ({ swSrc, swDest }) => { lib: { entry: swSrc, formats: ['iife'], - name: 'sw_pleroma', + name: 'sw_pleroma' }, emptyOutDir: false, rollupOptions: { output: { - entryFileNames: swDest, - }, - }, + entryFileNames: swDest + } + } }, - configFile: false, + configFile: false } }, generateBundle: { order: 'post', sequential: true, - async handler(_, bundle) { + async handler (_, bundle) { const assets = Object.keys(bundle) - .filter((name) => !/\.map$/.test(name)) - .map((name) => '/' + name) + .filter(name => !/\.map$/.test(name)) + .map(name => '/' + name) config.plugins.push({ name: 'build-sw-env-plugin', - resolveId(id) { + resolveId (id) { if (id === swEnvName) { return swEnvNameResolved } return null }, - load(id) { + load (id) { if (id === swEnvNameResolved) { return getProdSwEnv({ assets }) } return null - }, + } }) - }, + } }, closeBundle: { order: 'post', sequential: true, - async handler() { - console.info('Building service worker for production') + async handler () { + console.log('Building service worker for production') await build(config) - }, - }, + } + } } } @@ -190,9 +191,9 @@ const swMessagesNameResolved = '\0' + swMessagesName export const swMessagesPlugin = () => { return { name: 'sw-messages-plugin', - resolveId(id) { + resolveId (id) { if (id === swMessagesName) { - Object.values(i18nFiles).forEach((f) => { + Object.values(i18nFiles).forEach(f => { this.addWatchFile(f) }) return swMessagesNameResolved @@ -200,11 +201,11 @@ export const swMessagesPlugin = () => { return null } }, - async load(id) { + async load (id) { if (id === swMessagesNameResolved) { return await getSWMessagesAsText() } return null - }, + } } } diff --git a/build/update-emoji.js b/build/update-emoji.js index 4ff7e1de8..5d578ba61 100644 --- a/build/update-emoji.js +++ b/build/update-emoji.js @@ -1,21 +1,22 @@ -import emojis from '@kazvmoe-infra/unicode-emoji-json/data-by-group.json' with { - type: 'json', -} + +import emojis from '@kazvmoe-infra/unicode-emoji-json/data-by-group.json' with { type: 'json' } import fs from 'fs' -Object.keys(emojis).map((k) => { - emojis[k].map((e) => { - delete e.unicode_version - delete e.emoji_version - delete e.skin_tone_support_unicode_version +Object.keys(emojis) + .map(k => { + emojis[k].map(e => { + delete e.unicode_version + delete e.emoji_version + delete e.skin_tone_support_unicode_version + }) }) -}) const res = {} -Object.keys(emojis).map((k) => { - const groupId = k.replace('&', 'and').replace(/ /g, '-').toLowerCase() - res[groupId] = emojis[k] -}) +Object.keys(emojis) + .map(k => { + const groupId = k.replace('&', 'and').replace(/ /g, '-').toLowerCase() + res[groupId] = emojis[k] + }) console.info('Updating emojis...') fs.writeFileSync('src/assets/emoji.json', JSON.stringify(res)) diff --git a/changelog.d/admin_tab.add b/changelog.d/admin_tab.add new file mode 100644 index 000000000..421ce57cd --- /dev/null +++ b/changelog.d/admin_tab.add @@ -0,0 +1 @@ +Most of the remaining AdminFE tabs into Admin Dashboard diff --git a/changelog.d/broken.fix b/changelog.d/broken.fix new file mode 100644 index 000000000..7e58091b4 --- /dev/null +++ b/changelog.d/broken.fix @@ -0,0 +1,2 @@ +Fix display of the broken/deleted/banned users + diff --git a/changelog.d/everything-instance-default.add b/changelog.d/everything-instance-default.add new file mode 100644 index 000000000..6c4475905 --- /dev/null +++ b/changelog.d/everything-instance-default.add @@ -0,0 +1 @@ +Make every configuration option default-overridable by instance admins diff --git a/changelog.d/biome.skip b/changelog.d/finalfix-fr.skip similarity index 100% rename from changelog.d/biome.skip rename to changelog.d/finalfix-fr.skip diff --git a/changelog.d/finalfix.skip b/changelog.d/finalfix.skip new file mode 100644 index 000000000..e69de29bb diff --git a/changelog.d/settings-shuffle.change b/changelog.d/settings-shuffle.change new file mode 100644 index 000000000..f1d9ecf89 --- /dev/null +++ b/changelog.d/settings-shuffle.change @@ -0,0 +1,3 @@ +rearranged and split settings to make more sense and be less of a wall of text +on mobile settings now take up full width and presented in navigation style +improved styles for settings diff --git a/eslint.config.mjs b/eslint.config.mjs index 417ff8cf3..01bdb2038 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,34 +1,37 @@ -import js from '@eslint/js' -import { defineConfig, globalIgnores } from 'eslint/config' -import vue from 'eslint-plugin-vue' -import globals from 'globals' +import vue from "eslint-plugin-vue"; +import js from "@eslint/js"; +import globals from "globals"; -export default defineConfig([ + +export default [ ...vue.configs['flat/recommended'], - globalIgnores(['**/*.js', 'build/', 'dist/', 'config/']), + js.configs.recommended, { - files: ['src/**/*.vue'], - plugins: { js }, - extends: ['js/recommended'], + files: ["**/*.js", "**/*.mjs", "**/*.vue"], + ignores: ["build/*.js", "config/*.js"], + languageOptions: { ecmaVersion: 2024, - sourceType: 'module', + sourceType: "module", parserOptions: { - parser: '@babel/eslint-parser', + parser: "@babel/eslint-parser", }, globals: { ...globals.browser, ...globals.vitest, ...globals.chai, ...globals.commonjs, - ...globals.serviceworker, - }, + ...globals.serviceworker + } }, rules: { + 'arrow-parens': 0, + 'generator-star-spacing': 0, + 'no-debugger': 0, 'vue/require-prop-types': 0, 'vue/multi-word-component-names': 0, - }, - }, -]) + } + } +] diff --git a/package.json b/package.json index 33a1d719f..21d75f0fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pleroma_fe", - "version": "2.10.0", + "version": "2.9.3", "description": "Pleroma frontend, the default frontend of Pleroma social network server", "author": "Pleroma contributors ", "private": false, @@ -12,11 +12,9 @@ "unit:watch": "node build/update-emoji.js && vitest", "e2e": "node test/e2e/runner.js", "test": "yarn run unit && yarn run e2e", - "ci-biome": "yarn exec biome check", - "ci-eslint": "yarn exec eslint", - "ci-stylelint": "yarn exec stylelint '**/*.scss' '**/*.vue'", - "lint": "yarn ci-biome; yarn ci-eslint; yarn ci-stylelint", - "lint-fix": "yarn exec eslint --fix; yarn exec stylelint '**/*.scss' '**/*.vue' --fix; biome check --write" + "stylelint": "yarn exec stylelint '**/*.scss' '**/*.vue'", + "lint": "eslint src test/unit/specs test/e2e/specs", + "lint-fix": "eslint --fix src test/unit/specs test/e2e/specs" }, "dependencies": { "@babel/runtime": "7.28.4", @@ -51,17 +49,16 @@ "uuid": "11.1.0", "vue": "3.5.22", "vue-i18n": "11", - "vue-router": "4.6.4", + "vue-router": "4.5.1", "vue-virtual-scroller": "^2.0.0-beta.7", "vuex": "4.1.0" }, "devDependencies": { - "@babel/core": "7.28.5", - "@babel/eslint-parser": "7.28.5", - "@babel/plugin-transform-runtime": "7.28.5", - "@babel/preset-env": "7.28.5", + "@babel/core": "7.28.4", + "@babel/eslint-parser": "7.28.4", + "@babel/plugin-transform-runtime": "7.28.3", + "@babel/preset-env": "7.28.3", "@babel/register": "7.28.3", - "@biomejs/biome": "2.3.11", "@ungap/event-target": "0.2.4", "@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue-jsx": "^4.1.1", @@ -79,13 +76,14 @@ "connect-history-api-fallback": "2.0.0", "cross-spawn": "7.0.6", "custom-event-polyfill": "1.0.7", - "eslint": "9.39.2", + "eslint": "9.37.0", + "vue-eslint-parser": "10.2.0", "eslint-config-standard": "17.1.0", "eslint-formatter-friendly": "7.0.0", "eslint-plugin-import": "2.32.0", "eslint-plugin-n": "17.23.1", "eslint-plugin-promise": "7.2.1", - "eslint-plugin-vue": "10.6.2", + "eslint-plugin-vue": "10.5.0", "eventsource-polyfill": "0.9.6", "express": "5.1.0", "function-bind": "1.1.2", @@ -94,7 +92,7 @@ "lodash": "4.17.21", "msw": "2.10.5", "nightwatch": "3.12.2", - "playwright": "1.57.0", + "playwright": "1.55.0", "postcss": "8.5.6", "postcss-html": "^1.5.0", "postcss-scss": "^4.0.6", @@ -114,8 +112,7 @@ "vite": "^6.1.0", "vite-plugin-eslint2": "^5.0.3", "vite-plugin-stylelint": "^6.0.0", - "vitest": "^3.0.7", - "vue-eslint-parser": "10.2.0" + "vitest": "^3.0.7" }, "type": "module", "engines": { diff --git a/postcss.config.js b/postcss.config.js index b7fc12838..95ebbf2a6 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,5 +1,7 @@ import autoprefixer from 'autoprefixer' export default { - plugins: [autoprefixer], + plugins: [ + autoprefixer + ] } diff --git a/public/static/palettes/index.json b/public/static/palettes/index.json index 3c4e37e44..2cd110d1e 100644 --- a/public/static/palettes/index.json +++ b/public/static/palettes/index.json @@ -1,26 +1,6 @@ { - "pleroma-dark": [ - "Pleroma Dark", - "#121a24", - "#182230", - "#b9b9ba", - "#d8a070", - "#d31014", - "#0fa00f", - "#0095ff", - "#ffa500" - ], - "pleroma-light": [ - "Pleroma Light", - "#f2f4f6", - "#dbe0e8", - "#304055", - "#f86f0f", - "#d31014", - "#0fa00f", - "#0095ff", - "#ffa500" - ], + "pleroma-dark": [ "Pleroma Dark", "#121a24", "#182230", "#b9b9ba", "#d8a070", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ], + "pleroma-light": [ "Pleroma Light", "#f2f4f6", "#dbe0e8", "#304055", "#f86f0f", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ], "classic-dark": { "name": "Classic Dark", "bg": "#161c20", @@ -32,28 +12,8 @@ "cBlue": "#0095ff", "cOrange": "#ffa500" }, - "bird": [ - "Bird", - "#f8fafd", - "#e6ecf0", - "#14171a", - "#0084b8", - "#e0245e", - "#17bf63", - "#1b95e0", - "#fab81e" - ], - "pleroma-amoled": [ - "Pleroma Dark AMOLED", - "#000000", - "#111111", - "#b0b0b1", - "#d8a070", - "#aa0000", - "#0fa00f", - "#0095ff", - "#d59500" - ], + "bird": [ "Bird", "#f8fafd", "#e6ecf0", "#14171a", "#0084b8", "#e0245e", "#17bf63", "#1b95e0", "#fab81e"], + "pleroma-amoled": [ "Pleroma Dark AMOLED", "#000000", "#111111", "#b0b0b1", "#d8a070", "#aa0000", "#0fa00f", "#0095ff", "#d59500"], "tomorrow-night": { "name": "Tomorrow Night", "bg": "#1d1f21", @@ -76,28 +36,8 @@ "cGreen": "#50FA7B", "cOrange": "#FFB86C" }, - "ir-black": [ - "Ir Black", - "#000000", - "#242422", - "#b5b3aa", - "#ff6c60", - "#FF6C60", - "#A8FF60", - "#96CBFE", - "#FFFFB6" - ], - "monokai": [ - "Monokai", - "#272822", - "#383830", - "#f8f8f2", - "#f92672", - "#F92672", - "#a6e22e", - "#66d9ef", - "#f4bf75" - ], + "ir-black": [ "Ir Black", "#000000", "#242422", "#b5b3aa", "#ff6c60", "#FF6C60", "#A8FF60", "#96CBFE", "#FFFFB6" ], + "monokai": [ "Monokai", "#272822", "#383830", "#f8f8f2", "#f92672", "#F92672", "#a6e22e", "#66d9ef", "#f4bf75" ], "purple-stream": { "name": "Purple stream", "bg": "#17171A", diff --git a/public/static/splash.css b/public/static/splash.css index caf57dacb..f56f33d07 100644 --- a/public/static/splash.css +++ b/public/static/splash.css @@ -65,17 +65,16 @@ body { z-index: 2; grid-template-rows: repeat(8, 1fr); grid-template-columns: repeat(5, 1fr); - grid-template-areas: - "P P . L L" - "P P . L L" - "P P . L L" - "P P . L L" - "P P . . ." - "P P . . ." - "P P . E E" - "P P . E E"; + grid-template-areas: "P P . L L" + "P P . L L" + "P P . L L" + "P P . L L" + "P P . . ." + "P P . . ." + "P P . E E" + "P P . E E"; - --logoChunkSize: calc(2em * 0.5 * var(--scale)); + --logoChunkSize: calc(2em * 0.5 * var(--scale)) } .chunk { @@ -85,7 +84,7 @@ body { #chunk-P { grid-area: P; - border-top-left-radius: calc(var(--logoChunkSize) / 2); + border-top-left-radius: calc(var(--logoChunkSize) / 2); } #chunk-L { diff --git a/renovate.json b/renovate.json index 4bd832f5f..39a2b6e9a 100644 --- a/renovate.json +++ b/renovate.json @@ -1,4 +1,6 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": ["config:base"] + "extends": [ + "config:base" + ] } diff --git a/src/App.js b/src/App.js index 83e7f8ee5..0027d908a 100644 --- a/src/App.js +++ b/src/App.js @@ -1,35 +1,34 @@ -import { throttle } from 'lodash' -import { defineAsyncComponent } from 'vue' -import { mapGetters } from 'vuex' -import DesktopNav from './components/desktop_nav/desktop_nav.vue' -import EditStatusModal from './components/edit_status_modal/edit_status_modal.vue' -import FeaturesPanel from './components/features_panel/features_panel.vue' -import GlobalNoticeList from './components/global_notice_list/global_notice_list.vue' -import InstanceSpecificPanel from './components/instance_specific_panel/instance_specific_panel.vue' -import MediaModal from './components/media_modal/media_modal.vue' -import MobileNav from './components/mobile_nav/mobile_nav.vue' -import MobilePostStatusButton from './components/mobile_post_status_button/mobile_post_status_button.vue' -import NavPanel from './components/nav_panel/nav_panel.vue' -import PostStatusModal from './components/post_status_modal/post_status_modal.vue' -import ShoutPanel from './components/shout_panel/shout_panel.vue' -import SideDrawer from './components/side_drawer/side_drawer.vue' -import StatusHistoryModal from './components/status_history_modal/status_history_modal.vue' import UserPanel from './components/user_panel/user_panel.vue' -import UserReportingModal from './components/user_reporting_modal/user_reporting_modal.vue' +import NavPanel from './components/nav_panel/nav_panel.vue' +import InstanceSpecificPanel from './components/instance_specific_panel/instance_specific_panel.vue' +import FeaturesPanel from './components/features_panel/features_panel.vue' import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue' +import ShoutPanel from './components/shout_panel/shout_panel.vue' +import MediaModal from './components/media_modal/media_modal.vue' +import SideDrawer from './components/side_drawer/side_drawer.vue' +import MobilePostStatusButton from './components/mobile_post_status_button/mobile_post_status_button.vue' +import MobileNav from './components/mobile_nav/mobile_nav.vue' +import DesktopNav from './components/desktop_nav/desktop_nav.vue' +import UserReportingModal from './components/user_reporting_modal/user_reporting_modal.vue' +import EditStatusModal from './components/edit_status_modal/edit_status_modal.vue' +import PostStatusModal from './components/post_status_modal/post_status_modal.vue' +import StatusHistoryModal from './components/status_history_modal/status_history_modal.vue' +import GlobalNoticeList from './components/global_notice_list/global_notice_list.vue' import { getOrCreateServiceWorker } from './services/sw/sw' -import { windowHeight, windowWidth } from './services/window_utils/window_utils' -import { useInterfaceStore } from './stores/interface' +import { windowWidth, windowHeight } from './services/window_utils/window_utils' +import { mapGetters } from 'vuex' +import { defineAsyncComponent } from 'vue' import { useShoutStore } from './stores/shout' +import { useInterfaceStore } from './stores/interface' + +import { throttle } from 'lodash' export default { name: 'app', components: { UserPanel, NavPanel, - Notifications: defineAsyncComponent( - () => import('./components/notifications/notifications.vue'), - ), + Notifications: defineAsyncComponent(() => import('./components/notifications/notifications.vue')), InstanceSpecificPanel, FeaturesPanel, WhoToFollowPanel, @@ -39,33 +38,29 @@ export default { MobilePostStatusButton, MobileNav, DesktopNav, - SettingsModal: defineAsyncComponent( - () => import('./components/settings_modal/settings_modal.vue'), - ), - UpdateNotification: defineAsyncComponent( - () => import('./components/update_notification/update_notification.vue'), - ), + SettingsModal: defineAsyncComponent(() => import('./components/settings_modal/settings_modal.vue')), + UpdateNotification: defineAsyncComponent(() => import('./components/update_notification/update_notification.vue')), UserReportingModal, PostStatusModal, EditStatusModal, StatusHistoryModal, - GlobalNoticeList, + GlobalNoticeList }, data: () => ({ - mobileActivePanel: 'timeline', + mobileActivePanel: 'timeline' }), watch: { - themeApplied() { + themeApplied () { this.removeSplash() }, - currentTheme() { + currentTheme () { this.setThemeBodyClass() }, - layoutType() { + layoutType () { document.getElementById('modal').classList = ['-' + this.layoutType] - }, + } }, - created() { + created () { // Load the locale from the storage const val = this.$store.getters.mergedConfig.interfaceLanguage this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val }) @@ -75,7 +70,7 @@ export default { this.updateScrollState = throttle(this.scrollHandler, 200) this.updateMobileState = throttle(this.resizeHandler, 200) }, - mounted() { + mounted () { window.addEventListener('resize', this.updateMobileState) this.scrollParent.addEventListener('scroll', this.updateScrollState) @@ -85,145 +80,108 @@ export default { } getOrCreateServiceWorker() }, - unmounted() { + unmounted () { window.removeEventListener('resize', this.updateMobileState) this.scrollParent.removeEventListener('scroll', this.updateScrollState) }, computed: { - themeApplied() { + themeApplied () { return useInterfaceStore().themeApplied }, - currentTheme() { + currentTheme () { if (useInterfaceStore().styleDataUsed) { - const styleMeta = useInterfaceStore().styleDataUsed.find( - (x) => x.component === '@meta', - ) + const styleMeta = useInterfaceStore().styleDataUsed.find(x => x.component === '@meta') if (styleMeta !== undefined) { - return styleMeta.directives.name.replaceAll(' ', '-').toLowerCase() + return styleMeta.directives.name.replaceAll(" ", "-").toLowerCase() } } return 'stock' }, - layoutModalClass() { + layoutModalClass () { return '-' + this.layoutType }, - classes() { + classes () { return [ { '-reverse': this.reverseLayout, '-no-sticky-headers': this.noSticky, - '-has-new-post-button': this.newPostButtonShown, + '-has-new-post-button': this.newPostButtonShown }, - '-' + this.layoutType, + '-' + this.layoutType ] }, - navClasses() { + navClasses () { const { navbarColumnStretch } = this.$store.getters.mergedConfig return [ '-' + this.layoutType, - ...(navbarColumnStretch ? ['-column-stretch'] : []), + ...(navbarColumnStretch ? ['-column-stretch'] : []) ] }, - currentUser() { - return this.$store.state.users.currentUser - }, - userBackground() { - return this.currentUser.background_image - }, - instanceBackground() { + currentUser () { return this.$store.state.users.currentUser }, + userBackground () { return this.currentUser.background_image }, + instanceBackground () { return this.mergedConfig.hideInstanceWallpaper ? null : this.$store.state.instance.background }, - background() { - return this.userBackground || this.instanceBackground - }, - bgStyle() { + background () { return this.userBackground || this.instanceBackground }, + bgStyle () { if (this.background) { return { - '--body-background-image': `url(${this.background})`, + '--body-background-image': `url(${this.background})` } } }, - shout() { - return useShoutStore().joined - }, - suggestionsEnabled() { - return this.$store.state.instance.suggestionsEnabled - }, - showInstanceSpecificPanel() { - return ( - this.$store.state.instance.showInstanceSpecificPanel && + shout () { return useShoutStore().joined }, + suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled }, + showInstanceSpecificPanel () { + return this.$store.state.instance.showInstanceSpecificPanel && !this.$store.getters.mergedConfig.hideISP && this.$store.state.instance.instanceSpecificPanelContent - ) }, - isChats() { + isChats () { return this.$route.name === 'chat' || this.$route.name === 'chats' }, - isListEdit() { + isListEdit () { return this.$route.name === 'lists-edit' }, - newPostButtonShown() { + newPostButtonShown () { if (this.isChats) return false if (this.isListEdit) return false - return ( - this.$store.getters.mergedConfig.alwaysShowNewPostButton || - this.layoutType === 'mobile' - ) + return this.$store.getters.mergedConfig.alwaysShowNewPostButton || this.layoutType === 'mobile' }, - showFeaturesPanel() { - return this.$store.state.instance.showFeaturesPanel - }, - editingAvailable() { - return this.$store.state.instance.editingAvailable - }, - shoutboxPosition() { + showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel }, + editingAvailable () { return this.$store.state.instance.editingAvailable }, + shoutboxPosition () { return this.$store.getters.mergedConfig.alwaysShowNewPostButton || false }, - hideShoutbox() { + hideShoutbox () { return this.$store.getters.mergedConfig.hideShoutbox }, - layoutType() { - return useInterfaceStore().layoutType - }, - privateMode() { - return this.$store.state.instance.private - }, - reverseLayout() { - const { thirdColumnMode, sidebarRight: reverseSetting } = - this.$store.getters.mergedConfig + layoutType () { return useInterfaceStore().layoutType }, + privateMode () { return this.$store.state.instance.private }, + reverseLayout () { + const { thirdColumnMode, sidebarRight: reverseSetting } = this.$store.getters.mergedConfig if (this.layoutType !== 'wide') { return reverseSetting } else { - return thirdColumnMode === 'notifications' - ? reverseSetting - : !reverseSetting + return thirdColumnMode === 'notifications' ? reverseSetting : !reverseSetting } }, - noSticky() { - return this.$store.getters.mergedConfig.disableStickyHeaders - }, - showScrollbars() { - return this.$store.getters.mergedConfig.showScrollbars - }, - scrollParent() { - return window /* this.$refs.appContentRef */ - }, - ...mapGetters(['mergedConfig']), + noSticky () { return this.$store.getters.mergedConfig.disableStickyHeaders }, + showScrollbars () { return this.$store.getters.mergedConfig.showScrollbars }, + scrollParent () { return window; /* this.$refs.appContentRef */ }, + ...mapGetters(['mergedConfig']) }, methods: { - resizeHandler() { + resizeHandler () { useInterfaceStore().setLayoutWidth(windowWidth()) useInterfaceStore().setLayoutHeight(windowHeight()) }, - scrollHandler() { - const scrollPosition = - this.scrollParent === window - ? window.scrollY - : this.scrollParent.scrollTop + scrollHandler () { + const scrollPosition = this.scrollParent === window ? window.scrollY : this.scrollParent.scrollTop if (scrollPosition != 0) { this.$refs.appContentRef.classList.add(['-scrolled']) @@ -231,10 +189,10 @@ export default { this.$refs.appContentRef.classList.remove(['-scrolled']) } }, - setThemeBodyClass() { + setThemeBodyClass () { const themeName = this.currentTheme const classList = Array.from(document.body.classList) - const oldTheme = classList.filter((c) => c.startsWith('theme-')) + const oldTheme = classList.filter(c => c.startsWith('theme-')) if (themeName !== null && themeName !== '') { const newTheme = `theme-${themeName.toLowerCase()}` @@ -250,10 +208,8 @@ export default { document.body.classList.remove(...oldTheme) } }, - removeSplash() { - document.querySelector('#status').textContent = this.$t( - 'splash.fun_' + Math.ceil(Math.random() * 4), - ) + removeSplash () { + document.querySelector('#status').textContent = this.$t('splash.fun_' + Math.ceil(Math.random() * 4)) const splashscreenRoot = document.querySelector('#splash') splashscreenRoot.addEventListener('transitionend', () => { splashscreenRoot.remove() @@ -263,6 +219,6 @@ export default { }, 600) splashscreenRoot.classList.add('hidden') document.querySelector('#app').classList.remove('hidden') - }, - }, + } + } } diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 1a2be5bd7..ad994af6a 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -1,39 +1,30 @@ /* global process */ - -import vClickOutside from 'click-outside-vue3' import { createApp } from 'vue' import { createRouter, createWebHistory } from 'vue-router' +import vClickOutside from 'click-outside-vue3' import VueVirtualScroller from 'vue-virtual-scroller' import 'vue-virtual-scroller/dist/vue-virtual-scroller.css' -import { config } from '@fortawesome/fontawesome-svg-core' -import { - FontAwesomeIcon, - FontAwesomeLayers, -} from '@fortawesome/vue-fontawesome' - +import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome' +import { config } from '@fortawesome/fontawesome-svg-core'; config.autoAddCss = false +import App from '../App.vue' +import routes from './routes' import VBodyScrollLock from 'src/directives/body_scroll_lock' -import { - instanceDefaultConfig, - staticOrApiConfigDefault, -} from 'src/modules/default_config_state.js' -import { useAnnouncementsStore } from 'src/stores/announcements' -import { useAuthFlowStore } from 'src/stores/auth_flow' + +import { windowWidth, windowHeight } from '../services/window_utils/window_utils' +import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' +import { applyConfig } from '../services/style_setter/style_setter.js' +import FaviconService from '../services/favicon_service/favicon_service.js' +import { initServiceWorker, updateFocus } from '../services/sw/sw.js' + +import { useOAuthStore } from 'src/stores/oauth' import { useI18nStore } from 'src/stores/i18n' import { useInterfaceStore } from 'src/stores/interface' -import { useOAuthStore } from 'src/stores/oauth' -import App from '../App.vue' -import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' -import FaviconService from '../services/favicon_service/favicon_service.js' -import { applyConfig } from '../services/style_setter/style_setter.js' -import { initServiceWorker, updateFocus } from '../services/sw/sw.js' -import { - windowHeight, - windowWidth, -} from '../services/window_utils/window_utils' -import routes from './routes' +import { useAnnouncementsStore } from 'src/stores/announcements' +import { useAuthFlowStore } from 'src/stores/auth_flow' +import { staticOrApiConfigDefault, instanceDefaultConfig } from 'src/modules/default_config_state.js' let staticInitialResults = null @@ -42,9 +33,7 @@ const parsedInitialResults = () => { return null } if (!staticInitialResults) { - staticInitialResults = JSON.parse( - document.getElementById('initial-results').textContent, - ) + staticInitialResults = JSON.parse(document.getElementById('initial-results').textContent) } return staticInitialResults } @@ -66,7 +55,7 @@ const preloadFetch = async (request) => { return { ok: true, json: () => requestData, - text: () => requestData, + text: () => requestData } } @@ -78,35 +67,17 @@ const getInstanceConfig = async ({ store }) => { const textlimit = data.max_toot_chars const vapidPublicKey = data.pleroma.vapid_public_key - store.dispatch('setInstanceOption', { - name: 'pleromaExtensionsAvailable', - value: data.pleroma, - }) - store.dispatch('setInstanceOption', { - name: 'textlimit', - value: textlimit, - }) - store.dispatch('setInstanceOption', { - name: 'accountApprovalRequired', - value: data.approval_required, - }) - store.dispatch('setInstanceOption', { - name: 'birthdayRequired', - value: !!data.pleroma?.metadata.birthday_required, - }) - store.dispatch('setInstanceOption', { - name: 'birthdayMinAge', - value: data.pleroma?.metadata.birthday_min_age || 0, - }) + store.dispatch('setInstanceOption', { name: 'pleromaExtensionsAvailable', value: data.pleroma }) + store.dispatch('setInstanceOption', { name: 'textlimit', value: textlimit }) + store.dispatch('setInstanceOption', { name: 'accountApprovalRequired', value: data.approval_required }) + store.dispatch('setInstanceOption', { name: 'birthdayRequired', value: !!data.pleroma?.metadata.birthday_required }) + store.dispatch('setInstanceOption', { name: 'birthdayMinAge', value: data.pleroma?.metadata.birthday_min_age || 0 }) if (vapidPublicKey) { - store.dispatch('setInstanceOption', { - name: 'vapidPublicKey', - value: vapidPublicKey, - }) + store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey }) } } else { - throw res + throw (res) } } catch (error) { console.error('Could not load instance config, potentially fatal') @@ -123,12 +94,10 @@ const getBackendProvidedConfig = async () => { const data = await res.json() return data.pleroma_fe } else { - throw res + throw (res) } } catch (error) { - console.error( - 'Could not load backend-provided frontend config, potentially fatal', - ) + console.error('Could not load backend-provided frontend config, potentially fatal') console.error(error) } } @@ -139,7 +108,7 @@ const getStaticConfig = async () => { if (res.ok) { return res.json() } else { - throw res + throw (res) } } catch (error) { console.warn('Failed to load static/config.json, continuing without it.') @@ -180,7 +149,7 @@ const getTOS = async ({ store }) => { const html = await res.text() store.dispatch('setInstanceOption', { name: 'tos', value: html }) } else { - throw res + throw (res) } } catch (e) { console.warn("Can't load TOS\n", e) @@ -192,12 +161,9 @@ const getInstancePanel = async ({ store }) => { const res = await preloadFetch('/instance/panel.html') if (res.ok) { const html = await res.text() - store.dispatch('setInstanceOption', { - name: 'instanceSpecificPanelContent', - value: html, - }) + store.dispatch('setInstanceOption', { name: 'instanceSpecificPanelContent', value: html }) } else { - throw res + throw (res) } } catch (e) { console.warn("Can't load instance panel\n", e) @@ -209,27 +175,25 @@ const getStickers = async ({ store }) => { const res = await window.fetch('/static/stickers.json') if (res.ok) { const values = await res.json() - const stickers = ( - await Promise.all( - Object.entries(values).map(async ([name, path]) => { - const resPack = await window.fetch(path + 'pack.json') - let meta = {} - if (resPack.ok) { - meta = await resPack.json() - } - return { - pack: name, - path, - meta, - } - }), - ) - ).sort((a, b) => { + const stickers = (await Promise.all( + Object.entries(values).map(async ([name, path]) => { + const resPack = await window.fetch(path + 'pack.json') + let meta = {} + if (resPack.ok) { + meta = await resPack.json() + } + return { + pack: name, + path, + meta + } + }) + )).sort((a, b) => { return a.meta.title.localeCompare(b.meta.title) }) store.dispatch('setInstanceOption', { name: 'stickers', value: stickers }) } else { - throw res + throw (res) } } catch (e) { console.warn("Can't load stickers\n", e) @@ -239,19 +203,13 @@ const getStickers = async ({ store }) => { const getAppSecret = async ({ store }) => { const oauth = useOAuthStore() if (oauth.userToken) { - store.commit( - 'setBackendInteractor', - backendInteractorService(oauth.getToken), - ) + store.commit('setBackendInteractor', backendInteractorService(oauth.getToken)) } } const resolveStaffAccounts = ({ store, accounts }) => { - const nicknames = accounts.map((uri) => uri.split('/').pop()) - store.dispatch('setInstanceOption', { - name: 'staffAccounts', - value: nicknames, - }) + const nicknames = accounts.map(uri => uri.split('/').pop()) + store.dispatch('setInstanceOption', { name: 'staffAccounts', value: nicknames }) } const getNodeInfo = async ({ store }) => { @@ -262,167 +220,77 @@ const getNodeInfo = async ({ store }) => { const data = await res.json() const metadata = data.metadata const features = metadata.features - store.dispatch('setInstanceOption', { - name: 'name', - value: metadata.nodeName, - }) - store.dispatch('setInstanceOption', { - name: 'registrationOpen', - value: data.openRegistrations, - }) - store.dispatch('setInstanceOption', { - name: 'mediaProxyAvailable', - value: features.includes('media_proxy'), - }) - store.dispatch('setInstanceOption', { - name: 'safeDM', - value: features.includes('safe_dm_mentions'), - }) - store.dispatch('setInstanceOption', { - name: 'shoutAvailable', - value: features.includes('chat'), - }) - store.dispatch('setInstanceOption', { - name: 'pleromaChatMessagesAvailable', - value: features.includes('pleroma_chat_messages'), - }) + store.dispatch('setInstanceOption', { name: 'name', value: metadata.nodeName }) + store.dispatch('setInstanceOption', { name: 'registrationOpen', value: data.openRegistrations }) + store.dispatch('setInstanceOption', { name: 'mediaProxyAvailable', value: features.includes('media_proxy') }) + store.dispatch('setInstanceOption', { name: 'safeDM', value: features.includes('safe_dm_mentions') }) + store.dispatch('setInstanceOption', { name: 'shoutAvailable', value: features.includes('chat') }) + store.dispatch('setInstanceOption', { name: 'pleromaChatMessagesAvailable', value: features.includes('pleroma_chat_messages') }) store.dispatch('setInstanceOption', { name: 'pleromaCustomEmojiReactionsAvailable', value: features.includes('pleroma_custom_emoji_reactions') || - features.includes('custom_emoji_reactions'), - }) - store.dispatch('setInstanceOption', { - name: 'pleromaBookmarkFoldersAvailable', - value: features.includes('pleroma:bookmark_folders'), - }) - store.dispatch('setInstanceOption', { - name: 'gopherAvailable', - value: features.includes('gopher'), - }) - store.dispatch('setInstanceOption', { - name: 'pollsAvailable', - value: features.includes('polls'), - }) - store.dispatch('setInstanceOption', { - name: 'editingAvailable', - value: features.includes('editing'), - }) - store.dispatch('setInstanceOption', { - name: 'pollLimits', - value: metadata.pollLimits, - }) - store.dispatch('setInstanceOption', { - name: 'mailerEnabled', - value: metadata.mailerEnabled, - }) - store.dispatch('setInstanceOption', { - name: 'quotingAvailable', - value: features.includes('quote_posting'), - }) - store.dispatch('setInstanceOption', { - name: 'groupActorAvailable', - value: features.includes('pleroma:group_actors'), - }) - store.dispatch('setInstanceOption', { - name: 'blockExpiration', - value: features.includes('pleroma:block_expiration'), - }) - store.dispatch('setInstanceOption', { - name: 'localBubbleInstances', - value: metadata.localBubbleInstances ?? [], + features.includes('custom_emoji_reactions') }) + store.dispatch('setInstanceOption', { name: 'pleromaBookmarkFoldersAvailable', value: features.includes('pleroma:bookmark_folders') }) + store.dispatch('setInstanceOption', { name: 'gopherAvailable', value: features.includes('gopher') }) + store.dispatch('setInstanceOption', { name: 'pollsAvailable', value: features.includes('polls') }) + store.dispatch('setInstanceOption', { name: 'editingAvailable', value: features.includes('editing') }) + store.dispatch('setInstanceOption', { name: 'pollLimits', value: metadata.pollLimits }) + store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled }) + store.dispatch('setInstanceOption', { name: 'quotingAvailable', value: features.includes('quote_posting') }) + store.dispatch('setInstanceOption', { name: 'groupActorAvailable', value: features.includes('pleroma:group_actors') }) + store.dispatch('setInstanceOption', { name: 'blockExpiration', value: features.includes('pleroma:block_expiration') }) + store.dispatch('setInstanceOption', { name: 'localBubbleInstances', value: metadata.localBubbleInstances ?? [] }) const uploadLimits = metadata.uploadLimits - store.dispatch('setInstanceOption', { - name: 'uploadlimit', - value: parseInt(uploadLimits.general), - }) - store.dispatch('setInstanceOption', { - name: 'avatarlimit', - value: parseInt(uploadLimits.avatar), - }) - store.dispatch('setInstanceOption', { - name: 'backgroundlimit', - value: parseInt(uploadLimits.background), - }) - store.dispatch('setInstanceOption', { - name: 'bannerlimit', - value: parseInt(uploadLimits.banner), - }) - store.dispatch('setInstanceOption', { - name: 'fieldsLimits', - value: metadata.fieldsLimits, - }) + store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadLimits.general) }) + store.dispatch('setInstanceOption', { name: 'avatarlimit', value: parseInt(uploadLimits.avatar) }) + store.dispatch('setInstanceOption', { name: 'backgroundlimit', value: parseInt(uploadLimits.background) }) + store.dispatch('setInstanceOption', { name: 'bannerlimit', value: parseInt(uploadLimits.banner) }) + store.dispatch('setInstanceOption', { name: 'fieldsLimits', value: metadata.fieldsLimits }) - store.dispatch('setInstanceOption', { - name: 'restrictedNicknames', - value: metadata.restrictedNicknames, - }) - store.dispatch('setInstanceOption', { - name: 'postFormats', - value: metadata.postFormats, - }) + store.dispatch('setInstanceOption', { name: 'restrictedNicknames', value: metadata.restrictedNicknames }) + store.dispatch('setInstanceOption', { name: 'postFormats', value: metadata.postFormats }) const suggestions = metadata.suggestions - store.dispatch('setInstanceOption', { - name: 'suggestionsEnabled', - value: suggestions.enabled, - }) - store.dispatch('setInstanceOption', { - name: 'suggestionsWeb', - value: suggestions.web, - }) + store.dispatch('setInstanceOption', { name: 'suggestionsEnabled', value: suggestions.enabled }) + store.dispatch('setInstanceOption', { name: 'suggestionsWeb', value: suggestions.web }) const software = data.software - store.dispatch('setInstanceOption', { - name: 'backendVersion', - value: software.version, - }) - store.dispatch('setInstanceOption', { - name: 'backendRepository', - value: software.repository, - }) + store.dispatch('setInstanceOption', { name: 'backendVersion', value: software.version }) + store.dispatch('setInstanceOption', { name: 'backendRepository', value: software.repository }) const priv = metadata.private store.dispatch('setInstanceOption', { name: 'private', value: priv }) const frontendVersion = window.___pleromafe_commit_hash - store.dispatch('setInstanceOption', { - name: 'frontendVersion', - value: frontendVersion, - }) + store.dispatch('setInstanceOption', { name: 'frontendVersion', value: frontendVersion }) const federation = metadata.federation store.dispatch('setInstanceOption', { name: 'tagPolicyAvailable', - value: - typeof federation.mrf_policies === 'undefined' - ? false - : metadata.federation.mrf_policies.includes('TagPolicy'), + value: typeof federation.mrf_policies === 'undefined' + ? false + : metadata.federation.mrf_policies.includes('TagPolicy') }) - store.dispatch('setInstanceOption', { - name: 'federationPolicy', - value: federation, - }) + store.dispatch('setInstanceOption', { name: 'federationPolicy', value: federation }) store.dispatch('setInstanceOption', { name: 'federating', - value: - typeof federation.enabled === 'undefined' ? true : federation.enabled, + value: typeof federation.enabled === 'undefined' + ? true + : federation.enabled }) const accountActivationRequired = metadata.accountActivationRequired - store.dispatch('setInstanceOption', { - name: 'accountActivationRequired', - value: accountActivationRequired, - }) + store.dispatch('setInstanceOption', { name: 'accountActivationRequired', value: accountActivationRequired }) const accounts = metadata.staffAccounts resolveStaffAccounts({ store, accounts }) } else { - throw res + throw (res) } } catch (e) { console.warn('Could not load nodeinfo') @@ -432,10 +300,7 @@ const getNodeInfo = async ({ store }) => { const setConfig = async ({ store }) => { // apiConfig, staticConfig - const configInfos = await Promise.all([ - getBackendProvidedConfig({ store }), - getStaticConfig(), - ]) + const configInfos = await Promise.all([getBackendProvidedConfig({ store }), getStaticConfig()]) const apiConfig = configInfos[0] const staticConfig = configInfos[1] @@ -466,37 +331,29 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => { if (process.env.NODE_ENV === 'development') { // do some checks to avoid common errors if (!Object.keys(allStores).length) { - throw new Error( - 'No stores are available. Check the code in src/boot/after_store.js', - ) + throw new Error('No stores are available. Check the code in src/boot/after_store.js') } } await Promise.all( - Object.entries(allStores).map(async ([name, mod]) => { - const isStoreName = (name) => name.startsWith('use') - if (process.env.NODE_ENV === 'development') { - if (Object.keys(mod).filter(isStoreName).length !== 1) { - throw new Error( - 'Each store file must export exactly one store as a named export. Check your code in src/stores/', - ) + Object.entries(allStores) + .map(async ([name, mod]) => { + const isStoreName = name => name.startsWith('use') + if (process.env.NODE_ENV === 'development') { + if (Object.keys(mod).filter(isStoreName).length !== 1) { + throw new Error('Each store file must export exactly one store as a named export. Check your code in src/stores/') + } } - } - const storeFuncName = Object.keys(mod).find(isStoreName) - if (storeFuncName && typeof mod[storeFuncName] === 'function') { - const p = mod[storeFuncName]().$persistLoaded - if (!(p instanceof Promise)) { - throw new Error( - `${name} store's $persistLoaded is not a Promise. The persist plugin is not applied.`, - ) + const storeFuncName = Object.keys(mod).find(isStoreName) + if (storeFuncName && typeof mod[storeFuncName] === 'function') { + const p = mod[storeFuncName]().$persistLoaded + if (!(p instanceof Promise)) { + throw new Error(`${name} store's $persistLoaded is not a Promise. The persist plugin is not applied.`) + } + await p + } else { + throw new Error(`Store module ${name} does not export a 'use...' function`) } - await p - } else { - throw new Error( - `Store module ${name} does not export a 'use...' function`, - ) - } - }), - ) + })) } try { @@ -507,10 +364,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => { } if (storageError) { - useInterfaceStore().pushGlobalNotice({ - messageKey: 'errors.storage_unavailable', - level: 'error', - }) + useInterfaceStore().pushGlobalNotice({ messageKey: 'errors.storage_unavailable', level: 'error' }) } useInterfaceStore().setLayoutWidth(windowWidth()) @@ -522,19 +376,12 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => { window.addEventListener('focus', () => updateFocus()) const overrides = window.___pleromafe_dev_overrides || {} - const server = - typeof overrides.target !== 'undefined' - ? overrides.target - : window.location.origin + const server = (typeof overrides.target !== 'undefined') ? overrides.target : window.location.origin store.dispatch('setInstanceOption', { name: 'server', value: server }) await setConfig({ store }) try { - await useInterfaceStore() - .applyTheme() - .catch((e) => { - console.error('Error setting theme', e) - }) + await useInterfaceStore().applyTheme().catch((e) => { console.error('Error setting theme', e) }) } catch (e) { window.splashError(e) return Promise.reject(e) @@ -548,8 +395,8 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => { checkOAuthToken({ store }), getInstancePanel({ store }), getNodeInfo({ store }), - getInstanceConfig({ store }), - ]).catch((e) => Promise.reject(e)) + getInstanceConfig({ store }) + ]).catch(e => Promise.reject(e)) // Start fetching things that don't need to block the UI store.dispatch('fetchMutes') @@ -562,11 +409,11 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => { history: createWebHistory(), routes: routes(store), scrollBehavior: (to, _from, savedPosition) => { - if (to.matched.some((m) => m.meta.dontScroll)) { + if (to.matched.some(m => m.meta.dontScroll)) { return false } return savedPosition || { left: 0, top: 0 } - }, + } }) useI18nStore().setI18n(i18n) diff --git a/src/boot/routes.js b/src/boot/routes.js index c601531a9..02abf8ce6 100644 --- a/src/boot/routes.js +++ b/src/boot/routes.js @@ -1,35 +1,35 @@ -import About from 'components/about/about.vue' -import AnnouncementsPage from 'components/announcements_page/announcements_page.vue' -import AuthForm from 'components/auth_form/auth_form.js' -import BookmarkTimeline from 'components/bookmark_timeline/bookmark_timeline.vue' -import BubbleTimeline from 'components/bubble_timeline/bubble_timeline.vue' -import Chat from 'components/chat/chat.vue' -import ChatList from 'components/chat_list/chat_list.vue' -import ConversationPage from 'components/conversation-page/conversation-page.vue' -import DMs from 'components/dm_timeline/dm_timeline.vue' -import Drafts from 'components/drafts/drafts.vue' -import FollowRequests from 'components/follow_requests/follow_requests.vue' -import FriendsTimeline from 'components/friends_timeline/friends_timeline.vue' -import Interactions from 'components/interactions/interactions.vue' -import Lists from 'components/lists/lists.vue' -import ListsEdit from 'components/lists_edit/lists_edit.vue' -import ListsTimeline from 'components/lists_timeline/lists_timeline.vue' -import Notifications from 'components/notifications/notifications.vue' -import OAuthCallback from 'components/oauth_callback/oauth_callback.vue' -import PasswordReset from 'components/password_reset/password_reset.vue' -import PublicAndExternalTimeline from 'components/public_and_external_timeline/public_and_external_timeline.vue' import PublicTimeline from 'components/public_timeline/public_timeline.vue' -import Registration from 'components/registration/registration.vue' -import RemoteUserResolver from 'components/remote_user_resolver/remote_user_resolver.vue' -import Search from 'components/search/search.vue' -import ShoutPanel from 'components/shout_panel/shout_panel.vue' +import BubbleTimeline from 'components/bubble_timeline/bubble_timeline.vue' +import PublicAndExternalTimeline from 'components/public_and_external_timeline/public_and_external_timeline.vue' +import FriendsTimeline from 'components/friends_timeline/friends_timeline.vue' import TagTimeline from 'components/tag_timeline/tag_timeline.vue' +import BookmarkTimeline from 'components/bookmark_timeline/bookmark_timeline.vue' +import ConversationPage from 'components/conversation-page/conversation-page.vue' +import Interactions from 'components/interactions/interactions.vue' +import DMs from 'components/dm_timeline/dm_timeline.vue' +import ChatList from 'components/chat_list/chat_list.vue' +import Chat from 'components/chat/chat.vue' import UserProfile from 'components/user_profile/user_profile.vue' +import Search from 'components/search/search.vue' +import Registration from 'components/registration/registration.vue' +import PasswordReset from 'components/password_reset/password_reset.vue' +import FollowRequests from 'components/follow_requests/follow_requests.vue' +import OAuthCallback from 'components/oauth_callback/oauth_callback.vue' +import Notifications from 'components/notifications/notifications.vue' +import AuthForm from 'components/auth_form/auth_form.js' +import ShoutPanel from 'components/shout_panel/shout_panel.vue' import WhoToFollow from 'components/who_to_follow/who_to_follow.vue' +import About from 'components/about/about.vue' +import RemoteUserResolver from 'components/remote_user_resolver/remote_user_resolver.vue' +import Lists from 'components/lists/lists.vue' +import ListsTimeline from 'components/lists_timeline/lists_timeline.vue' +import ListsEdit from 'components/lists_edit/lists_edit.vue' import NavPanel from 'src/components/nav_panel/nav_panel.vue' -import BookmarkFolderEdit from '../components/bookmark_folder_edit/bookmark_folder_edit.vue' -import BookmarkFolders from '../components/bookmark_folders/bookmark_folders.vue' +import AnnouncementsPage from 'components/announcements_page/announcements_page.vue' import QuotesTimeline from '../components/quotes_timeline/quotes_timeline.vue' +import Drafts from 'components/drafts/drafts.vue' +import BookmarkFolders from '../components/bookmark_folders/bookmark_folders.vue' +import BookmarkFolderEdit from '../components/bookmark_folder_edit/bookmark_folder_edit.vue' export default (store) => { const validateAuthenticatedRoute = (to, from, next) => { @@ -45,124 +45,46 @@ export default (store) => { name: 'root', path: '/', redirect: () => { - return ( - (store.state.users.currentUser - ? store.state.instance.redirectRootLogin - : store.state.instance.redirectRootNoLogin) || '/main/all' - ) - }, - }, - { - name: 'public-external-timeline', - path: '/main/all', - component: PublicAndExternalTimeline, - }, - { - name: 'public-timeline', - path: '/main/public', - component: PublicTimeline, - }, - { - name: 'friends', - path: '/main/friends', - component: FriendsTimeline, - beforeEnter: validateAuthenticatedRoute, + return (store.state.users.currentUser + ? store.state.instance.redirectRootLogin + : store.state.instance.redirectRootNoLogin) || '/main/all' + } }, + { name: 'public-external-timeline', path: '/main/all', component: PublicAndExternalTimeline }, + { name: 'public-timeline', path: '/main/public', component: PublicTimeline }, + { name: 'friends', path: '/main/friends', component: FriendsTimeline, beforeEnter: validateAuthenticatedRoute }, { name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline }, { name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline }, { name: 'bubble', path: '/bubble', component: BubbleTimeline }, - { - name: 'conversation', - path: '/notice/:id', - component: ConversationPage, - meta: { dontScroll: true }, - }, + { name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } }, { name: 'quotes', path: '/notice/:id/quotes', component: QuotesTimeline }, { name: 'remote-user-profile-acct', path: '/remote-users/:_(@)?:username([^/@]+)@:hostname([^/@]+)', component: RemoteUserResolver, - beforeEnter: validateAuthenticatedRoute, + beforeEnter: validateAuthenticatedRoute }, { name: 'remote-user-profile', path: '/remote-users/:hostname/:username', component: RemoteUserResolver, - beforeEnter: validateAuthenticatedRoute, - }, - { - name: 'external-user-profile', - path: '/users/$:id', - component: UserProfile, - }, - { - name: 'interactions', - path: '/users/:username/interactions', - component: Interactions, - beforeEnter: validateAuthenticatedRoute, - }, - { - name: 'dms', - path: '/users/:username/dms', - component: DMs, - beforeEnter: validateAuthenticatedRoute, + beforeEnter: validateAuthenticatedRoute }, + { name: 'external-user-profile', path: '/users/$:id', component: UserProfile }, + { name: 'interactions', path: '/users/:username/interactions', component: Interactions, beforeEnter: validateAuthenticatedRoute }, + { name: 'dms', path: '/users/:username/dms', component: DMs, beforeEnter: validateAuthenticatedRoute }, { name: 'registration', path: '/registration', component: Registration }, - { - name: 'password-reset', - path: '/password-reset', - component: PasswordReset, - props: true, - }, - { - name: 'registration-token', - path: '/registration/:token', - component: Registration, - }, - { - name: 'friend-requests', - path: '/friend-requests', - component: FollowRequests, - beforeEnter: validateAuthenticatedRoute, - }, - { - name: 'notifications', - path: '/:username/notifications', - component: Notifications, - props: () => ({ disableTeleport: true }), - beforeEnter: validateAuthenticatedRoute, - }, + { name: 'password-reset', path: '/password-reset', component: PasswordReset, props: true }, + { name: 'registration-token', path: '/registration/:token', component: Registration }, + { name: 'friend-requests', path: '/friend-requests', component: FollowRequests, beforeEnter: validateAuthenticatedRoute }, + { name: 'notifications', path: '/:username/notifications', component: Notifications, props: () => ({ disableTeleport: true }), beforeEnter: validateAuthenticatedRoute }, { name: 'login', path: '/login', component: AuthForm }, - { - name: 'shout-panel', - path: '/shout-panel', - component: ShoutPanel, - props: () => ({ floating: false }), - }, - { - name: 'oauth-callback', - path: '/oauth-callback', - component: OAuthCallback, - props: (route) => ({ code: route.query.code }), - }, - { - name: 'search', - path: '/search', - component: Search, - props: (route) => ({ query: route.query.query }), - }, - { - name: 'who-to-follow', - path: '/who-to-follow', - component: WhoToFollow, - beforeEnter: validateAuthenticatedRoute, - }, + { name: 'shout-panel', path: '/shout-panel', component: ShoutPanel, props: () => ({ floating: false }) }, + { name: 'oauth-callback', path: '/oauth-callback', component: OAuthCallback, props: (route) => ({ code: route.query.code }) }, + { name: 'search', path: '/search', component: Search, props: (route) => ({ query: route.query.query }) }, + { name: 'who-to-follow', path: '/who-to-follow', component: WhoToFollow, beforeEnter: validateAuthenticatedRoute }, { name: 'about', path: '/about', component: About }, - { - name: 'announcements', - path: '/announcements', - component: AnnouncementsPage, - }, + { name: 'announcements', path: '/announcements', component: AnnouncementsPage }, { name: 'drafts', path: '/drafts', component: Drafts }, { name: 'user-profile', path: '/users/:name', component: UserProfile }, { name: 'legacy-user-profile', path: '/:name', component: UserProfile }, @@ -170,51 +92,17 @@ export default (store) => { { name: 'lists-timeline', path: '/lists/:id', component: ListsTimeline }, { name: 'lists-edit', path: '/lists/:id/edit', component: ListsEdit }, { name: 'lists-new', path: '/lists/new', component: ListsEdit }, - { - name: 'edit-navigation', - path: '/nav-edit', - component: NavPanel, - props: () => ({ forceExpand: true, forceEditMode: true }), - beforeEnter: validateAuthenticatedRoute, - }, - { - name: 'bookmark-folders', - path: '/bookmark_folders', - component: BookmarkFolders, - }, - { - name: 'bookmark-folder-new', - path: '/bookmarks/new-folder', - component: BookmarkFolderEdit, - }, - { - name: 'bookmark-folder', - path: '/bookmarks/:id', - component: BookmarkTimeline, - }, - { - name: 'bookmark-folder-edit', - path: '/bookmarks/:id/edit', - component: BookmarkFolderEdit, - }, + { name: 'edit-navigation', path: '/nav-edit', component: NavPanel, props: () => ({ forceExpand: true, forceEditMode: true }), beforeEnter: validateAuthenticatedRoute }, + { name: 'bookmark-folders', path: '/bookmark_folders', component: BookmarkFolders }, + { name: 'bookmark-folder-new', path: '/bookmarks/new-folder', component: BookmarkFolderEdit }, + { name: 'bookmark-folder', path: '/bookmarks/:id', component: BookmarkTimeline }, + { name: 'bookmark-folder-edit', path: '/bookmarks/:id/edit', component: BookmarkFolderEdit } ] if (store.state.instance.pleromaChatMessagesAvailable) { routes = routes.concat([ - { - name: 'chat', - path: '/users/:username/chats/:recipient_id', - component: Chat, - meta: { dontScroll: false }, - beforeEnter: validateAuthenticatedRoute, - }, - { - name: 'chats', - path: '/users/:username/chats', - component: ChatList, - meta: { dontScroll: false }, - beforeEnter: validateAuthenticatedRoute, - }, + { name: 'chat', path: '/users/:username/chats/:recipient_id', component: Chat, meta: { dontScroll: false }, beforeEnter: validateAuthenticatedRoute }, + { name: 'chats', path: '/users/:username/chats', component: ChatList, meta: { dontScroll: false }, beforeEnter: validateAuthenticatedRoute } ]) } diff --git a/src/components/about/about.js b/src/components/about/about.js index d091dfd0a..1df258450 100644 --- a/src/components/about/about.js +++ b/src/components/about/about.js @@ -1,8 +1,8 @@ -import FeaturesPanel from '../features_panel/features_panel.vue' import InstanceSpecificPanel from '../instance_specific_panel/instance_specific_panel.vue' -import MRFTransparencyPanel from '../mrf_transparency_panel/mrf_transparency_panel.vue' -import StaffPanel from '../staff_panel/staff_panel.vue' +import FeaturesPanel from '../features_panel/features_panel.vue' import TermsOfServicePanel from '../terms_of_service_panel/terms_of_service_panel.vue' +import StaffPanel from '../staff_panel/staff_panel.vue' +import MRFTransparencyPanel from '../mrf_transparency_panel/mrf_transparency_panel.vue' const About = { components: { @@ -10,20 +10,16 @@ const About = { FeaturesPanel, TermsOfServicePanel, StaffPanel, - MRFTransparencyPanel, + MRFTransparencyPanel }, computed: { - showFeaturesPanel() { - return this.$store.state.instance.showFeaturesPanel - }, - showInstanceSpecificPanel() { - return ( - this.$store.state.instance.showInstanceSpecificPanel && + showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel }, + showInstanceSpecificPanel () { + return this.$store.state.instance.showInstanceSpecificPanel && !this.$store.getters.mergedConfig.hideISP && this.$store.state.instance.instanceSpecificPanelContent - ) - }, - }, + } + } } export default About diff --git a/src/components/account_actions/account_actions.js b/src/components/account_actions/account_actions.js index 184c2b623..2ac74ea76 100644 --- a/src/components/account_actions/account_actions.js +++ b/src/components/account_actions/account_actions.js @@ -1,21 +1,27 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faEllipsisV } from '@fortawesome/free-solid-svg-icons' -import UserListMenu from 'src/components/user_list_menu/user_list_menu.vue' -import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue' -import { useReportsStore } from 'src/stores/reports' import { mapState } from 'vuex' -import ConfirmModal from '../confirm_modal/confirm_modal.vue' -import Popover from '../popover/popover.vue' import ProgressButton from '../progress_button/progress_button.vue' +import Popover from '../popover/popover.vue' +import UserListMenu from 'src/components/user_list_menu/user_list_menu.vue' +import ConfirmModal from '../confirm_modal/confirm_modal.vue' +import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faEllipsisV +} from '@fortawesome/free-solid-svg-icons' +import { useReportsStore } from 'src/stores/reports' -library.add(faEllipsisV) +library.add( + faEllipsisV +) const AccountActions = { - props: ['user', 'relationship'], - data() { + props: [ + 'user', 'relationship' + ], + data () { return { showingConfirmBlock: false, - showingConfirmRemoveFollower: false, + showingConfirmRemoveFollower: false } }, components: { @@ -23,25 +29,25 @@ const AccountActions = { Popover, UserListMenu, ConfirmModal, - UserTimedFilterModal, + UserTimedFilterModal }, methods: { - showConfirmRemoveUserFromFollowers() { + showConfirmRemoveUserFromFollowers () { this.showingConfirmRemoveFollower = true }, - hideConfirmRemoveUserFromFollowers() { + hideConfirmRemoveUserFromFollowers () { this.showingConfirmRemoveFollower = false }, - hideConfirmBlock() { + hideConfirmBlock () { this.showingConfirmBlock = false }, - showRepeats() { + showRepeats () { this.$store.dispatch('showReblogs', this.user.id) }, - hideRepeats() { + hideRepeats () { this.$store.dispatch('hideReblogs', this.user.id) }, - blockUser() { + blockUser () { if (this.$refs.timedBlockDialog) { this.$refs.timedBlockDialog.optionallyPrompt() } else { @@ -52,50 +58,46 @@ const AccountActions = { } } }, - doBlockUser() { + doBlockUser () { this.$store.dispatch('blockUser', { id: this.user.id }) this.hideConfirmBlock() }, - unblockUser() { + unblockUser () { this.$store.dispatch('unblockUser', this.user.id) }, - removeUserFromFollowers() { + removeUserFromFollowers () { if (!this.shouldConfirmRemoveUserFromFollowers) { this.doRemoveUserFromFollowers() } else { this.showConfirmRemoveUserFromFollowers() } }, - doRemoveUserFromFollowers() { + doRemoveUserFromFollowers () { this.$store.dispatch('removeUserFromFollowers', this.user.id) this.hideConfirmRemoveUserFromFollowers() }, - reportUser() { + reportUser () { useReportsStore().openUserReportingModal({ userId: this.user.id }) }, - openChat() { + openChat () { this.$router.push({ name: 'chat', - params: { - username: this.$store.state.users.currentUser.screen_name, - recipient_id: this.user.id, - }, + params: { username: this.$store.state.users.currentUser.screen_name, recipient_id: this.user.id } }) - }, + } }, computed: { - shouldConfirmBlock() { + shouldConfirmBlock () { return this.$store.getters.mergedConfig.modalOnBlock }, - shouldConfirmRemoveUserFromFollowers() { + shouldConfirmRemoveUserFromFollowers () { return this.$store.getters.mergedConfig.modalOnRemoveUserFromFollowers }, ...mapState({ - blockExpirationSupported: (state) => state.instance.blockExpiration, - pleromaChatMessagesAvailable: (state) => - state.instance.pleromaChatMessagesAvailable, - }), - }, + blockExpirationSupported: state => state.instance.blockExpiration, + pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable + }) + } } export default AccountActions diff --git a/src/components/alert.style.js b/src/components/alert.style.js index 8a6f842ed..868514764 100644 --- a/src/components/alert.style.js +++ b/src/components/alert.style.js @@ -1,51 +1,57 @@ export default { name: 'Alert', selector: '.alert', - validInnerComponents: ['Text', 'Icon', 'Link', 'Border', 'ButtonUnstyled'], + validInnerComponents: [ + 'Text', + 'Icon', + 'Link', + 'Border', + 'ButtonUnstyled' + ], variants: { normal: '.neutral', error: '.error', warning: '.warning', - success: '.success', + success: '.success' }, editor: { border: 1, - aspect: '3 / 1', + aspect: '3 / 1' }, defaultRules: [ { directives: { background: '--text', opacity: 0.5, - blur: '9px', - }, + blur: '9px' + } }, { parent: { - component: 'Alert', + component: 'Alert' }, component: 'Border', directives: { - textColor: '--parent', - }, + textColor: '--parent' + } }, { variant: 'error', directives: { - background: '--cRed', - }, + background: '--cRed' + } }, { variant: 'warning', directives: { - background: '--cOrange', - }, + background: '--cOrange' + } }, { variant: 'success', directives: { - background: '--cGreen', - }, - }, - ], + background: '--cGreen' + } + } + ] } diff --git a/src/components/announcement/announcement.js b/src/components/announcement/announcement.js index 356852cff..d1b8257d8 100644 --- a/src/components/announcement/announcement.js +++ b/src/components/announcement/announcement.js @@ -1,128 +1,109 @@ -import { useAnnouncementsStore } from 'src/stores/announcements' import { mapState } from 'vuex' -import localeService from '../../services/locale/locale.service.js' import AnnouncementEditor from '../announcement_editor/announcement_editor.vue' import RichContent from '../rich_content/rich_content.jsx' +import localeService from '../../services/locale/locale.service.js' +import { useAnnouncementsStore } from 'src/stores/announcements' const Announcement = { components: { AnnouncementEditor, - RichContent, + RichContent }, - data() { + data () { return { editing: false, editedAnnouncement: { content: '', startsAt: undefined, endsAt: undefined, - allDay: undefined, + allDay: undefined }, - editError: '', + editError: '' } }, props: { - announcement: Object, + announcement: Object }, computed: { ...mapState({ - currentUser: (state) => state.users.currentUser, + currentUser: state => state.users.currentUser }), - canEditAnnouncement() { - return ( - this.currentUser && - this.currentUser.privileges.includes( - 'announcements_manage_announcements', - ) - ) + canEditAnnouncement () { + return this.currentUser && this.currentUser.privileges.includes('announcements_manage_announcements') }, - content() { + content () { return this.announcement.content }, - isRead() { + isRead () { return this.announcement.read }, - publishedAt() { + publishedAt () { const time = this.announcement.published_at if (!time) { return } - return this.formatTimeOrDate( - time, - localeService.internalToBrowserLocale(this.$i18n.locale), - ) + return this.formatTimeOrDate(time, localeService.internalToBrowserLocale(this.$i18n.locale)) }, - startsAt() { + startsAt () { const time = this.announcement.starts_at if (!time) { return } - return this.formatTimeOrDate( - time, - localeService.internalToBrowserLocale(this.$i18n.locale), - ) + return this.formatTimeOrDate(time, localeService.internalToBrowserLocale(this.$i18n.locale)) }, - endsAt() { + endsAt () { const time = this.announcement.ends_at if (!time) { return } - return this.formatTimeOrDate( - time, - localeService.internalToBrowserLocale(this.$i18n.locale), - ) + return this.formatTimeOrDate(time, localeService.internalToBrowserLocale(this.$i18n.locale)) }, - inactive() { + inactive () { return this.announcement.inactive - }, + } }, methods: { - markAsRead() { + markAsRead () { if (!this.isRead) { - return useAnnouncementsStore().markAnnouncementAsRead( - this.announcement.id, - ) + return useAnnouncementsStore().markAnnouncementAsRead(this.announcement.id) } }, - deleteAnnouncement() { + deleteAnnouncement () { return useAnnouncementsStore().deleteAnnouncement(this.announcement.id) }, - formatTimeOrDate(time, locale) { + formatTimeOrDate (time, locale) { const d = new Date(time) - return this.announcement.all_day - ? d.toLocaleDateString(locale) - : d.toLocaleString(locale) + return this.announcement.all_day ? d.toLocaleDateString(locale) : d.toLocaleString(locale) }, - enterEditMode() { + enterEditMode () { this.editedAnnouncement.content = this.announcement.pleroma.raw_content this.editedAnnouncement.startsAt = this.announcement.starts_at this.editedAnnouncement.endsAt = this.announcement.ends_at this.editedAnnouncement.allDay = this.announcement.all_day this.editing = true }, - submitEdit() { - useAnnouncementsStore() - .editAnnouncement({ - id: this.announcement.id, - ...this.editedAnnouncement, - }) + submitEdit () { + useAnnouncementsStore().editAnnouncement({ + id: this.announcement.id, + ...this.editedAnnouncement + }) .then(() => { this.editing = false }) - .catch((error) => { + .catch(error => { this.editError = error.error }) }, - cancelEdit() { + cancelEdit () { this.editing = false }, - clearError() { + clearError () { this.editError = undefined - }, - }, + } + } } export default Announcement diff --git a/src/components/announcement_editor/announcement_editor.js b/src/components/announcement_editor/announcement_editor.js index 6d22ac1fd..79a03afe1 100644 --- a/src/components/announcement_editor/announcement_editor.js +++ b/src/components/announcement_editor/announcement_editor.js @@ -2,12 +2,12 @@ import Checkbox from '../checkbox/checkbox.vue' const AnnouncementEditor = { components: { - Checkbox, + Checkbox }, props: { announcement: Object, - disabled: Boolean, - }, + disabled: Boolean + } } export default AnnouncementEditor diff --git a/src/components/announcements_page/announcements_page.js b/src/components/announcements_page/announcements_page.js index d3429613c..9ce0b45f5 100644 --- a/src/components/announcements_page/announcements_page.js +++ b/src/components/announcements_page/announcements_page.js @@ -1,65 +1,59 @@ -import { useAnnouncementsStore } from 'src/stores/announcements' import { mapState } from 'vuex' import Announcement from '../announcement/announcement.vue' import AnnouncementEditor from '../announcement_editor/announcement_editor.vue' +import { useAnnouncementsStore } from 'src/stores/announcements' const AnnouncementsPage = { components: { Announcement, - AnnouncementEditor, + AnnouncementEditor }, - data() { + data () { return { newAnnouncement: { content: '', startsAt: undefined, endsAt: undefined, - allDay: false, + allDay: false }, posting: false, - error: undefined, + error: undefined } }, - mounted() { + mounted () { useAnnouncementsStore().fetchAnnouncements() }, computed: { ...mapState({ - currentUser: (state) => state.users.currentUser, + currentUser: state => state.users.currentUser }), - announcements() { + announcements () { return useAnnouncementsStore().announcements }, - canPostAnnouncement() { - return ( - this.currentUser && - this.currentUser.privileges.includes( - 'announcements_manage_announcements', - ) - ) - }, + canPostAnnouncement () { + return this.currentUser && this.currentUser.privileges.includes('announcements_manage_announcements') + } }, methods: { - postAnnouncement() { + postAnnouncement () { this.posting = true - useAnnouncementsStore() - .postAnnouncement(this.newAnnouncement) + useAnnouncementsStore().postAnnouncement(this.newAnnouncement) .then(() => { this.newAnnouncement.content = '' this.startsAt = undefined this.endsAt = undefined }) - .catch((error) => { + .catch(error => { this.error = error.error }) .finally(() => { this.posting = false }) }, - clearError() { + clearError () { this.error = undefined - }, - }, + } + } } export default AnnouncementsPage diff --git a/src/components/async_component_error/async_component_error.vue b/src/components/async_component_error/async_component_error.vue index baf430950..2ff8974c1 100644 --- a/src/components/async_component_error/async_component_error.vue +++ b/src/components/async_component_error/async_component_error.vue @@ -21,10 +21,10 @@ export default { emits: ['resetAsyncComponent'], methods: { - retry() { + retry () { this.$emit('resetAsyncComponent') - }, - }, + } + } } diff --git a/src/components/attachment/attachment.js b/src/components/attachment/attachment.js index 8c7700c8a..21d793930 100644 --- a/src/components/attachment/attachment.js +++ b/src/components/attachment/attachment.js @@ -1,24 +1,24 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { - faAlignRight, - faFile, - faImage, - faMusic, - faPencilAlt, - faPlayCircle, - faSearchPlus, - faStop, - faTimes, - faTrashAlt, - faVideo, -} from '@fortawesome/free-solid-svg-icons' -import { useMediaViewerStore } from 'src/stores/media_viewer' -import { mapGetters } from 'vuex' +import StillImage from '../still-image/still-image.vue' +import Flash from '../flash/flash.vue' +import VideoAttachment from '../video_attachment/video_attachment.vue' import nsfwImage from '../../assets/nsfw.png' import fileTypeService from '../../services/file_type/file_type.service.js' -import Flash from '../flash/flash.vue' -import StillImage from '../still-image/still-image.vue' -import VideoAttachment from '../video_attachment/video_attachment.vue' +import { mapGetters } from 'vuex' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faFile, + faMusic, + faImage, + faVideo, + faPlayCircle, + faTimes, + faStop, + faSearchPlus, + faTrashAlt, + faPencilAlt, + faAlignRight +} from '@fortawesome/free-solid-svg-icons' +import { useMediaViewerStore } from 'src/stores/media_viewer' library.add( faFile, @@ -31,7 +31,7 @@ library.add( faSearchPlus, faTrashAlt, faPencilAlt, - faAlignRight, + faAlignRight ) const Attachment = { @@ -46,74 +46,72 @@ const Attachment = { 'remove', 'shiftUp', 'shiftDn', - 'edit', + 'edit' ], - data() { + data () { return { localDescription: this.description || this.attachment.description, nsfwImage: this.$store.state.instance.nsfwCensorImage || nsfwImage, hideNsfwLocal: this.$store.getters.mergedConfig.hideNsfw, preloadImage: this.$store.getters.mergedConfig.preloadImage, loading: false, - img: - fileTypeService.fileType(this.attachment.mimetype) === 'image' && - document.createElement('img'), + img: fileTypeService.fileType(this.attachment.mimetype) === 'image' && document.createElement('img'), modalOpen: false, showHidden: false, flashLoaded: false, - showDescription: false, + showDescription: false } }, components: { Flash, StillImage, - VideoAttachment, + VideoAttachment }, computed: { - classNames() { + classNames () { return [ { '-loading': this.loading, '-nsfw-placeholder': this.hidden, '-editable': this.edit !== undefined, - '-compact': this.compact, + '-compact': this.compact }, '-type-' + this.type, this.size && '-size-' + this.size, - `-${this.useContainFit ? 'contain' : 'cover'}-fit`, + `-${this.useContainFit ? 'contain' : 'cover'}-fit` ] }, - usePlaceholder() { + usePlaceholder () { return this.size === 'hide' }, - useContainFit() { + useContainFit () { return this.$store.getters.mergedConfig.useContainFit }, - placeholderName() { + placeholderName () { if (this.attachment.description === '' || !this.attachment.description) { return this.type.toUpperCase() } return this.attachment.description }, - placeholderIconClass() { + placeholderIconClass () { if (this.type === 'image') return 'image' if (this.type === 'video') return 'video' if (this.type === 'audio') return 'music' return 'file' }, - referrerpolicy() { + referrerpolicy () { return this.$store.state.instance.mediaProxyAvailable ? '' : 'no-referrer' }, - type() { + type () { return fileTypeService.fileType(this.attachment.mimetype) }, - hidden() { + hidden () { return this.nsfw && this.hideNsfwLocal && !this.showHidden }, - isEmpty() { - return this.type === 'html' && !this.attachment.oembed + isEmpty () { + return (this.type === 'html' && !this.attachment.oembed) }, - useModal() { + useModal () { let modalTypes = [] switch (this.size) { case 'hide': @@ -128,26 +126,26 @@ const Attachment = { } return modalTypes.includes(this.type) }, - videoTag() { + videoTag () { return this.useModal ? 'button' : 'span' }, - ...mapGetters(['mergedConfig']), + ...mapGetters(['mergedConfig']) }, watch: { - 'attachment.description'(newVal) { + 'attachment.description' (newVal) { this.localDescription = newVal }, - localDescription(newVal) { + localDescription (newVal) { this.onEdit(newVal) - }, + } }, methods: { - linkClicked({ target }) { + linkClicked ({ target }) { if (target.tagName === 'A') { window.open(target.href, '_blank') } }, - openModal() { + openModal () { if (this.useModal) { this.$emit('setMedia') useMediaViewerStore().setCurrentMedia(this.attachment) @@ -155,35 +153,34 @@ const Attachment = { window.open(this.attachment.url) } }, - openModalForce() { + openModalForce () { this.$emit('setMedia') useMediaViewerStore().setCurrentMedia(this.attachment) }, - onEdit(event) { + onEdit (event) { this.edit && this.edit(this.attachment, event) }, - onRemove() { + onRemove () { this.remove && this.remove(this.attachment) }, - onShiftUp() { + onShiftUp () { this.shiftUp && this.shiftUp(this.attachment) }, - onShiftDn() { + onShiftDn () { this.shiftDn && this.shiftDn(this.attachment) }, - stopFlash() { + stopFlash () { this.$refs.flash.closePlayer() }, - setFlashLoaded(event) { + setFlashLoaded (event) { this.flashLoaded = event }, - toggleDescription() { + toggleDescription () { this.showDescription = !this.showDescription }, - toggleHidden(event) { + toggleHidden (event) { if ( - this.mergedConfig.useOneClickNsfw && - !this.showHidden && + (this.mergedConfig.useOneClickNsfw && !this.showHidden) && (this.type !== 'video' || this.mergedConfig.playVideosInModal) ) { this.openModal(event) @@ -204,12 +201,12 @@ const Attachment = { this.showHidden = !this.showHidden } }, - onImageLoad(image) { + onImageLoad (image) { const width = image.naturalWidth const height = image.naturalHeight this.$emit('naturalSizeLoad', { id: this.attachment.id, width, height }) - }, - }, + } + } } export default Attachment diff --git a/src/components/auth_form/auth_form.js b/src/components/auth_form/auth_form.js index 1e9b86c57..243cbf574 100644 --- a/src/components/auth_form/auth_form.js +++ b/src/components/auth_form/auth_form.js @@ -1,32 +1,28 @@ -import { mapState } from 'pinia' -import { useAuthFlowStore } from 'src/stores/auth_flow' import { h, resolveComponent } from 'vue' import LoginForm from '../login_form/login_form.vue' import MFARecoveryForm from '../mfa_form/recovery_form.vue' import MFATOTPForm from '../mfa_form/totp_form.vue' +import { mapState } from 'pinia' +import { useAuthFlowStore } from 'src/stores/auth_flow' const AuthForm = { name: 'AuthForm', - render() { + render () { return h(resolveComponent(this.authForm)) }, computed: { - authForm() { - if (this.requiredTOTP) { - return 'MFATOTPForm' - } - if (this.requiredRecovery) { - return 'MFARecoveryForm' - } + authForm () { + if (this.requiredTOTP) { return 'MFATOTPForm' } + if (this.requiredRecovery) { return 'MFARecoveryForm' } return 'LoginForm' }, - ...mapState(useAuthFlowStore, ['requiredTOTP', 'requiredRecovery']), + ...mapState(useAuthFlowStore, ['requiredTOTP', 'requiredRecovery']) }, components: { MFARecoveryForm, MFATOTPForm, - LoginForm, - }, + LoginForm + } } export default AuthForm diff --git a/src/components/autosuggest/autosuggest.js b/src/components/autosuggest/autosuggest.js index 37b7706db..f58f17bb6 100644 --- a/src/components/autosuggest/autosuggest.js +++ b/src/components/autosuggest/autosuggest.js @@ -2,55 +2,51 @@ const debounceMilliseconds = 500 export default { props: { - query: { - // function to query results and return a promise + query: { // function to query results and return a promise type: Function, - required: true, + required: true }, - filter: { - // function to filter results in real time - type: Function, + filter: { // function to filter results in real time + type: Function }, placeholder: { type: String, - default: 'Search...', - }, + default: 'Search...' + } }, - data() { + data () { return { term: '', timeout: null, results: [], - resultsVisible: false, + resultsVisible: false } }, computed: { - filtered() { + filtered () { return this.filter ? this.filter(this.results) : this.results - }, + } }, watch: { - term(val) { + term (val) { this.fetchResults(val) - }, + } }, methods: { - fetchResults(term) { + fetchResults (term) { clearTimeout(this.timeout) this.timeout = setTimeout(() => { this.results = [] if (term) { - this.query(term).then((results) => { - this.results = results - }) + this.query(term).then((results) => { this.results = results }) } }, debounceMilliseconds) }, - onInputClick() { + onInputClick () { this.resultsVisible = true }, - onClickOutside() { + onClickOutside () { this.resultsVisible = false - }, - }, + } + } } diff --git a/src/components/avatar_list/avatar_list.js b/src/components/avatar_list/avatar_list.js index aad157686..9b6301b22 100644 --- a/src/components/avatar_list/avatar_list.js +++ b/src/components/avatar_list/avatar_list.js @@ -1,25 +1,21 @@ -import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import UserAvatar from '../user_avatar/user_avatar.vue' +import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' const AvatarList = { props: ['users'], computed: { - slicedUsers() { + slicedUsers () { return this.users ? this.users.slice(0, 15) : [] - }, + } }, components: { - UserAvatar, + UserAvatar }, methods: { - userProfileLink(user) { - return generateProfileLink( - user.id, - user.screen_name, - this.$store.state.instance.restrictedNicknames, - ) - }, - }, + userProfileLink (user) { + return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames) + } + } } export default AvatarList diff --git a/src/components/badge.style.js b/src/components/badge.style.js index ab28429cc..0697cac6c 100644 --- a/src/components/badge.style.js +++ b/src/components/badge.style.js @@ -1,27 +1,30 @@ export default { name: 'Badge', selector: '.badge', - validInnerComponents: ['Text', 'Icon'], + validInnerComponents: [ + 'Text', + 'Icon' + ], variants: { - notification: '.-notification', + notification: '.-notification' }, defaultRules: [ { component: 'Root', directives: { - '--badgeNotification': 'color | --cRed', - }, + '--badgeNotification': 'color | --cRed' + } }, { directives: { - background: '--cGreen', - }, + background: '--cGreen' + } }, { variant: 'notification', directives: { - background: '--cRed', - }, - }, - ], + background: '--cRed' + } + } + ] } diff --git a/src/components/basic_user_card/basic_user_card.js b/src/components/basic_user_card/basic_user_card.js index cc4cbce44..31de2d75f 100644 --- a/src/components/basic_user_card/basic_user_card.js +++ b/src/components/basic_user_card/basic_user_card.js @@ -1,26 +1,24 @@ -import RichContent from 'src/components/rich_content/rich_content.jsx' -import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' +import UserPopover from '../user_popover/user_popover.vue' import UserAvatar from '../user_avatar/user_avatar.vue' import UserLink from '../user_link/user_link.vue' -import UserPopover from '../user_popover/user_popover.vue' +import RichContent from 'src/components/rich_content/rich_content.jsx' +import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' const BasicUserCard = { - props: ['user'], + props: [ + 'user' + ], components: { UserPopover, UserAvatar, RichContent, - UserLink, + UserLink }, methods: { - userProfileLink(user) { - return generateProfileLink( - user.id, - user.screen_name, - this.$store.state.instance.restrictedNicknames, - ) - }, - }, + userProfileLink (user) { + return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames) + } + } } export default BasicUserCard diff --git a/src/components/block_card/block_card.js b/src/components/block_card/block_card.js index 754c2fb12..9a618db3f 100644 --- a/src/components/block_card/block_card.js +++ b/src/components/block_card/block_card.js @@ -5,44 +5,42 @@ import BasicUserCard from '../basic_user_card/basic_user_card.vue' const BlockCard = { props: ['userId'], computed: { - user() { + user () { return this.$store.getters.findUser(this.userId) }, - relationship() { + relationship () { return this.$store.getters.relationship(this.userId) }, - blocked() { + blocked () { return this.relationship.blocking }, - blockExpiryAvailable() { + blockExpiryAvailable () { return this.user.block_expires_at !== undefined }, - blockExpiry() { + blockExpiry () { return this.user.block_expires_at == null ? this.$t('user_card.block_expires_forever') - : this.$t('user_card.block_expires_at', [ - new Date(this.user.mute_expires_at).toLocaleString(), - ]) + : this.$t('user_card.block_expires_at', [new Date(this.user.mute_expires_at).toLocaleString()]) }, ...mapState({ - blockExpirationSupported: (state) => state.instance.blockExpiration, - }), + blockExpirationSupported: state => state.instance.blockExpiration, + }) }, components: { - BasicUserCard, + BasicUserCard }, methods: { - unblockUser() { + unblockUser () { this.$store.dispatch('unblockUser', this.user.id) }, - blockUser() { + blockUser () { if (this.blockExpirationSupported) { this.$refs.timedBlockDialog.optionallyPrompt() } else { this.$store.dispatch('blockUser', { id: this.user.id }) } - }, - }, + } + } } export default BlockCard diff --git a/src/components/bookmark_folder_card/bookmark_folder_card.js b/src/components/bookmark_folder_card/bookmark_folder_card.js index 37b3f2e5e..bf274d9d7 100644 --- a/src/components/bookmark_folder_card/bookmark_folder_card.js +++ b/src/components/bookmark_folder_card/bookmark_folder_card.js @@ -1,15 +1,22 @@ import { library } from '@fortawesome/fontawesome-svg-core' -import { faEllipsisH } from '@fortawesome/free-solid-svg-icons' +import { + faEllipsisH +} from '@fortawesome/free-solid-svg-icons' -library.add(faEllipsisH) +library.add( + faEllipsisH +) const BookmarkFolderCard = { - props: ['folder', 'allBookmarks'], + props: [ + 'folder', + 'allBookmarks' + ], computed: { - firstLetter() { + firstLetter () { return this.folder ? this.folder.name[0] : null - }, - }, + } + } } export default BookmarkFolderCard diff --git a/src/components/bookmark_folder_edit/bookmark_folder_edit.js b/src/components/bookmark_folder_edit/bookmark_folder_edit.js index a658a0f40..bb96585bf 100644 --- a/src/components/bookmark_folder_edit/bookmark_folder_edit.js +++ b/src/components/bookmark_folder_edit/bookmark_folder_edit.js @@ -1,10 +1,10 @@ -import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders' -import { useInterfaceStore } from 'src/stores/interface' -import apiService from '../../services/api/api.service' import EmojiPicker from '../emoji_picker/emoji_picker.vue' +import apiService from '../../services/api/api.service' +import { useInterfaceStore } from 'src/stores/interface' +import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders' const BookmarkFolderEdit = { - data() { + data () { return { name: '', nameDraft: '', @@ -13,59 +13,54 @@ const BookmarkFolderEdit = { emojiDraft: '', emojiUrlDraft: null, emojiPickerExpanded: false, - reallyDelete: false, + reallyDelete: false } }, components: { - EmojiPicker, + EmojiPicker }, - created() { + created () { if (!this.id) return const credentials = this.$store.state.users.currentUser.credentials - apiService.fetchBookmarkFolders({ credentials }).then((folders) => { - const folder = folders.find((folder) => folder.id === this.id) - if (!folder) return + apiService.fetchBookmarkFolders({ credentials }) + .then((folders) => { + const folder = folders.find(folder => folder.id === this.id) + if (!folder) return - this.nameDraft = this.name = folder.name - this.emojiDraft = this.emoji = folder.emoji - this.emojiUrlDraft = this.emojiUrl = folder.emoji_url - }) + this.nameDraft = this.name = folder.name + this.emojiDraft = this.emoji = folder.emoji + this.emojiUrlDraft = this.emojiUrl = folder.emoji_url + }) }, computed: { - id() { + id () { return this.$route.params.id - }, + } }, methods: { - selectEmoji(event) { + selectEmoji (event) { this.emojiDraft = event.insertion this.emojiUrlDraft = event.insertionUrl }, - showEmojiPicker() { + showEmojiPicker () { if (!this.emojiPickerExpanded) { this.$refs.picker.showPicker() } }, - onShowPicker() { + onShowPicker () { this.emojiPickerExpanded = true }, - onClosePicker() { + onClosePicker () { this.emojiPickerExpanded = false }, - updateFolder() { - useBookmarkFoldersStore() - .updateBookmarkFolder({ - folderId: this.id, - name: this.nameDraft, - emoji: this.emojiDraft, - }) + updateFolder () { + useBookmarkFoldersStore().updateBookmarkFolder({ folderId: this.id, name: this.nameDraft, emoji: this.emojiDraft }) .then(() => { this.$router.push({ name: 'bookmark-folders' }) }) }, - createFolder() { - useBookmarkFoldersStore() - .createBookmarkFolder({ name: this.nameDraft, emoji: this.emojiDraft }) + createFolder () { + useBookmarkFoldersStore().createBookmarkFolder({ name: this.nameDraft, emoji: this.emojiDraft }) .then(() => { this.$router.push({ name: 'bookmark-folders' }) }) @@ -73,15 +68,15 @@ const BookmarkFolderEdit = { useInterfaceStore().pushGlobalNotice({ messageKey: 'bookmark_folders.error', messageArgs: [e.message], - level: 'error', + level: 'error' }) }) }, - deleteFolder() { + deleteFolder () { useBookmarkFoldersStore().deleteBookmarkFolder({ folderId: this.id }) this.$router.push({ name: 'bookmark-folders' }) - }, - }, + } + } } export default BookmarkFolderEdit diff --git a/src/components/bookmark_folders/bookmark_folders.js b/src/components/bookmark_folders/bookmark_folders.js index 8e09abb31..096f3769d 100644 --- a/src/components/bookmark_folders/bookmark_folders.js +++ b/src/components/bookmark_folders/bookmark_folders.js @@ -1,28 +1,28 @@ -import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders' import BookmarkFolderCard from '../bookmark_folder_card/bookmark_folder_card.vue' +import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders' const BookmarkFolders = { - data() { + data () { return { - isNew: false, + isNew: false } }, components: { - BookmarkFolderCard, + BookmarkFolderCard }, computed: { - bookmarkFolders() { + bookmarkFolders () { return useBookmarkFoldersStore().allFolders - }, + } }, methods: { - cancelNewFolder() { + cancelNewFolder () { this.isNew = false }, - newFolder() { + newFolder () { this.isNew = true - }, - }, + } + } } export default BookmarkFolders diff --git a/src/components/bookmark_folders_menu/bookmark_folders_menu_content.js b/src/components/bookmark_folders_menu/bookmark_folders_menu_content.js index cc8135334..dc46b91b3 100644 --- a/src/components/bookmark_folders_menu/bookmark_folders_menu_content.js +++ b/src/components/bookmark_folders_menu/bookmark_folders_menu_content.js @@ -1,18 +1,20 @@ import { mapState } from 'pinia' -import { getBookmarkFolderEntries } from 'src/components/navigation/filter.js' import NavigationEntry from 'src/components/navigation/navigation_entry.vue' +import { getBookmarkFolderEntries } from 'src/components/navigation/filter.js' import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders' export const BookmarkFoldersMenuContent = { - props: ['showPin'], + props: [ + 'showPin' + ], components: { - NavigationEntry, + NavigationEntry }, computed: { ...mapState(useBookmarkFoldersStore, { - folders: getBookmarkFolderEntries, - }), - }, + folders: getBookmarkFolderEntries + }) + } } export default BookmarkFoldersMenuContent diff --git a/src/components/bookmark_timeline/bookmark_timeline.js b/src/components/bookmark_timeline/bookmark_timeline.js index a241b6ac7..9571d630f 100644 --- a/src/components/bookmark_timeline/bookmark_timeline.js +++ b/src/components/bookmark_timeline/bookmark_timeline.js @@ -1,38 +1,32 @@ import Timeline from '../timeline/timeline.vue' const Bookmarks = { - created() { + created () { this.$store.commit('clearTimeline', { timeline: 'bookmarks' }) - this.$store.dispatch('startFetchingTimeline', { - timeline: 'bookmarks', - bookmarkFolderId: this.folderId || null, - }) + this.$store.dispatch('startFetchingTimeline', { timeline: 'bookmarks', bookmarkFolderId: this.folderId || null }) }, components: { - Timeline, + Timeline }, computed: { - folderId() { + folderId () { return this.$route.params.id }, - timeline() { + timeline () { return this.$store.state.statuses.timelines.bookmarks - }, + } }, watch: { - folderId() { + folderId () { this.$store.commit('clearTimeline', { timeline: 'bookmarks' }) this.$store.dispatch('stopFetchingTimeline', 'bookmarks') - this.$store.dispatch('startFetchingTimeline', { - timeline: 'bookmarks', - bookmarkFolderId: this.folderId || null, - }) - }, + this.$store.dispatch('startFetchingTimeline', { timeline: 'bookmarks', bookmarkFolderId: this.folderId || null }) + } }, - unmounted() { + unmounted () { this.$store.commit('clearTimeline', { timeline: 'bookmarks' }) this.$store.dispatch('stopFetchingTimeline', 'bookmarks') - }, + } } export default Bookmarks diff --git a/src/components/border.style.js b/src/components/border.style.js index e7cc31c57..7f2c30163 100644 --- a/src/components/border.style.js +++ b/src/components/border.style.js @@ -6,8 +6,8 @@ export default { { directives: { textColor: '$mod(--parent 10)', - textAuto: 'no-auto', - }, - }, - ], + textAuto: 'no-auto' + } + } + ] } diff --git a/src/components/bubble_timeline/bubble_timeline.js b/src/components/bubble_timeline/bubble_timeline.js index d3835e0e8..6f73dd2b8 100644 --- a/src/components/bubble_timeline/bubble_timeline.js +++ b/src/components/bubble_timeline/bubble_timeline.js @@ -1,20 +1,18 @@ import Timeline from '../timeline/timeline.vue' - const BubbleTimeline = { components: { - Timeline, + Timeline }, computed: { - timeline() { - return this.$store.state.statuses.timelines.bubble - }, + timeline () { return this.$store.state.statuses.timelines.bubble } }, - created() { + created () { this.$store.dispatch('startFetchingTimeline', { timeline: 'bubble' }) }, - unmounted() { + unmounted () { this.$store.dispatch('stopFetchingTimeline', 'bubble') - }, + } + } export default BubbleTimeline diff --git a/src/components/button.style.js b/src/components/button.style.js index 3fb308b89..5cffefd91 100644 --- a/src/components/button.style.js +++ b/src/components/button.style.js @@ -12,22 +12,25 @@ export default { focused: ':focus-within', pressed: ':active', hover: ':is(:hover, :focus-visible):not(:disabled)', - disabled: ':disabled', + disabled: ':disabled' }, // Variants are mutually exclusive, each component implicitly has "normal" variant, and all other variants inherit from it. variants: { // Variants save on computation time since adding new variant just adds one more "set". // normal: '', // you can override normal variant, it will be appenended to the main class danger: '.-danger', - transparent: '.-transparent', + transparent: '.-transparent' // Overall the compuation difficulty is N*((1/6)M^3+M) where M is number of distinct states and N is number of variants. // This (currently) is further multipled by number of places where component can exist. }, editor: { - aspect: '2 / 1', + aspect: '2 / 1' }, // This lists all other components that can possibly exist within one. Recursion is currently not supported (and probably won't be supported ever). - validInnerComponents: ['Text', 'Icon'], + validInnerComponents: [ + 'Text', + 'Icon' + ], // Default rules, used as "default theme", essentially. defaultRules: [ { @@ -36,11 +39,9 @@ export default { '--buttonDefaultHoverGlow': 'shadow | 0 0 1 2 --text / 0.4', '--buttonDefaultFocusGlow': 'shadow | 0 0 1 2 --link / 0.5', '--buttonDefaultShadow': 'shadow | 0 0 2 #000000', - '--buttonDefaultBevel': - 'shadow | $borderSide(#FFFFFF top 0.2 1), $borderSide(#000000 bottom 0.2 1)', - '--buttonPressedBevel': - 'shadow | inset 0 0 4 #000000, $borderSide(#FFFFFF bottom 0.2 1), $borderSide(#000000 top 0.2 1)', - }, + '--buttonDefaultBevel': 'shadow | $borderSide(#FFFFFF top 0.2 1), $borderSide(#000000 bottom 0.2 1)', + '--buttonPressedBevel': 'shadow | inset 0 0 4 #000000, $borderSide(#FFFFFF bottom 0.2 1), $borderSide(#000000 top 0.2 1)' + } }, { // component: 'Button', // no need to specify components every time unless you're specifying how other component should look @@ -48,128 +49,128 @@ export default { directives: { background: '--fg', shadow: ['--buttonDefaultShadow', '--buttonDefaultBevel'], - roundness: 3, - }, + roundness: 3 + } }, { variant: 'danger', directives: { - background: '--cRed', - }, + background: '--cRed' + } }, { variant: 'transparent', directives: { - opacity: 0.5, - }, + opacity: 0.5 + } }, { component: 'Text', parent: { component: 'Button', - variant: 'transparent', + variant: 'transparent' }, directives: { - textColor: '--text', - }, + textColor: '--text' + } }, { component: 'Icon', parent: { component: 'Button', - variant: 'transparent', + variant: 'transparent' }, directives: { - textColor: '--text', - }, + textColor: '--text' + } }, { state: ['hover'], directives: { - shadow: ['--buttonDefaultHoverGlow', '--buttonDefaultBevel'], - }, + shadow: ['--buttonDefaultHoverGlow', '--buttonDefaultBevel'] + } }, { state: ['focused'], directives: { - shadow: ['--buttonDefaultFocusGlow', '--buttonDefaultBevel'], - }, + shadow: ['--buttonDefaultFocusGlow', '--buttonDefaultBevel'] + } }, { state: ['pressed'], directives: { - shadow: ['--buttonDefaultShadow', '--buttonPressedBevel'], - }, + shadow: ['--buttonDefaultShadow', '--buttonPressedBevel'] + } }, { state: ['pressed', 'hover'], directives: { - shadow: ['--buttonPressedBevel', '--buttonDefaultHoverGlow'], - }, + shadow: ['--buttonPressedBevel', '--buttonDefaultHoverGlow'] + } }, { state: ['toggled'], directives: { background: '--accent,-24.2', - shadow: ['--buttonDefaultShadow', '--buttonPressedBevel'], - }, + shadow: ['--buttonDefaultShadow', '--buttonPressedBevel'] + } }, { state: ['toggled', 'hover'], directives: { background: '--accent,-24.2', - shadow: ['--buttonDefaultHoverGlow', '--buttonPressedBevel'], - }, + shadow: ['--buttonDefaultHoverGlow', '--buttonPressedBevel'] + } }, { state: ['toggled', 'focused'], directives: { background: '--accent,-24.2', - shadow: ['--buttonDefaultHoverGlow', '--buttonPressedBevel'], - }, + shadow: ['--buttonDefaultHoverGlow', '--buttonPressedBevel'] + } }, { state: ['toggled', 'hover', 'focused'], directives: { background: '--accent,-24.2', - shadow: ['--buttonDefaultHoverGlow', '--buttonPressedBevel'], - }, + shadow: ['--buttonDefaultHoverGlow', '--buttonPressedBevel'] + } }, { state: ['toggled', 'disabled'], directives: { background: '$blend(--accent 0.25 --parent)', - shadow: ['--buttonPressedBevel'], - }, + shadow: ['--buttonPressedBevel'] + } }, { state: ['disabled'], directives: { background: '$blend(--inheritedBackground 0.25 --parent)', - shadow: ['--buttonDefaultBevel'], - }, + shadow: ['--buttonDefaultBevel'] + } }, { component: 'Text', parent: { component: 'Button', - state: ['disabled'], + state: ['disabled'] }, directives: { textOpacity: 0.25, - textOpacityMode: 'blend', - }, + textOpacityMode: 'blend' + } }, { component: 'Icon', parent: { component: 'Button', - state: ['disabled'], + state: ['disabled'] }, directives: { textOpacity: 0.25, - textOpacityMode: 'blend', - }, - }, - ], + textOpacityMode: 'blend' + } + } + ] } diff --git a/src/components/button_unstyled.style.js b/src/components/button_unstyled.style.js index c35fb8f69..9e1a2ca90 100644 --- a/src/components/button_unstyled.style.js +++ b/src/components/button_unstyled.style.js @@ -7,86 +7,91 @@ export default { toggled: '.toggled', disabled: ':disabled', hover: ':is(:hover, :focus-visible):not(:disabled)', - focused: ':focus-within:not(:is(:focus-visible))', + focused: ':focus-within:not(:is(:focus-visible))' }, - validInnerComponents: ['Text', 'Link', 'Icon', 'Badge'], + validInnerComponents: [ + 'Text', + 'Link', + 'Icon', + 'Badge' + ], defaultRules: [ { directives: { - shadow: [], - }, + shadow: [] + } }, { component: 'Icon', parent: { component: 'ButtonUnstyled', - state: ['hover'], + state: ['hover'] }, directives: { - textColor: '--parent--text', - }, + textColor: '--parent--text' + } }, { component: 'Icon', parent: { component: 'ButtonUnstyled', - state: ['toggled'], + state: ['toggled'] }, directives: { - textColor: '--parent--text', - }, + textColor: '--parent--text' + } }, { component: 'Icon', parent: { component: 'ButtonUnstyled', - state: ['toggled', 'hover'], + state: ['toggled', 'hover'] }, directives: { - textColor: '--parent--text', - }, + textColor: '--parent--text' + } }, { component: 'Icon', parent: { component: 'ButtonUnstyled', - state: ['toggled', 'focused'], + state: ['toggled', 'focused'] }, directives: { - textColor: '--parent--text', - }, + textColor: '--parent--text' + } }, { component: 'Icon', parent: { component: 'ButtonUnstyled', - state: ['toggled', 'focused', 'hover'], + state: ['toggled', 'focused', 'hover'] }, directives: { - textColor: '--parent--text', - }, + textColor: '--parent--text' + } }, { component: 'Text', parent: { component: 'ButtonUnstyled', - state: ['disabled'], + state: ['disabled'] }, directives: { textOpacity: 0.25, - textOpacityMode: 'blend', - }, + textOpacityMode: 'blend' + } }, { component: 'Icon', parent: { component: 'ButtonUnstyled', - state: ['disabled'], + state: ['disabled'] }, directives: { textOpacity: 0.25, - textOpacityMode: 'blend', - }, - }, - ], + textOpacityMode: 'blend' + } + } + ] } diff --git a/src/components/chat/chat.js b/src/components/chat/chat.js index 2a0d91761..56f389e60 100644 --- a/src/components/chat/chat.js +++ b/src/components/chat/chat.js @@ -1,24 +1,25 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faChevronDown, faChevronLeft } from '@fortawesome/free-solid-svg-icons' import _ from 'lodash' -import { mapState as mapPiniaState } from 'pinia' -import { useInterfaceStore } from 'src/stores/interface.js' -import { mapGetters, mapState } from 'vuex' import { WSConnectionStatus } from '../../services/api/api.service.js' -import chatService from '../../services/chat_service/chat_service.js' -import { buildFakeMessage } from '../../services/chat_utils/chat_utils.js' -import { promiseInterval } from '../../services/promise_interval/promise_interval.js' +import { mapGetters, mapState } from 'vuex' +import { mapState as mapPiniaState } from 'pinia' import ChatMessage from '../chat_message/chat_message.vue' -import ChatTitle from '../chat_title/chat_title.vue' import PostStatusForm from '../post_status_form/post_status_form.vue' +import ChatTitle from '../chat_title/chat_title.vue' +import chatService from '../../services/chat_service/chat_service.js' +import { promiseInterval } from '../../services/promise_interval/promise_interval.js' +import { getScrollPosition, getNewTopPosition, isBottomedOut, isScrollable } from './chat_layout_utils.js' +import { library } from '@fortawesome/fontawesome-svg-core' import { - getNewTopPosition, - getScrollPosition, - isBottomedOut, - isScrollable, -} from './chat_layout_utils.js' + faChevronDown, + faChevronLeft +} from '@fortawesome/free-solid-svg-icons' +import { buildFakeMessage } from '../../services/chat_utils/chat_utils.js' +import { useInterfaceStore } from 'src/stores/interface.js' -library.add(faChevronDown, faChevronLeft) +library.add( + faChevronDown, + faChevronLeft +) const BOTTOMED_OUT_OFFSET = 10 const JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET = 10 @@ -30,95 +31,78 @@ const Chat = { components: { ChatMessage, ChatTitle, - PostStatusForm, + PostStatusForm }, - data() { + data () { return { jumpToBottomButtonVisible: false, hoveredMessageChainId: undefined, lastScrollPosition: {}, scrollableContainerHeight: '100%', errorLoadingChat: false, - messageRetriers: {}, + messageRetriers: {} } }, - created() { + created () { this.startFetching() window.addEventListener('resize', this.handleResize) }, - mounted() { + mounted () { window.addEventListener('scroll', this.handleScroll) if (typeof document.hidden !== 'undefined') { - document.addEventListener( - 'visibilitychange', - this.handleVisibilityChange, - false, - ) + document.addEventListener('visibilitychange', this.handleVisibilityChange, false) } this.$nextTick(() => { this.handleResize() }) }, - unmounted() { + unmounted () { window.removeEventListener('scroll', this.handleScroll) window.removeEventListener('resize', this.handleResize) - if (typeof document.hidden !== 'undefined') - document.removeEventListener( - 'visibilitychange', - this.handleVisibilityChange, - false, - ) + if (typeof document.hidden !== 'undefined') document.removeEventListener('visibilitychange', this.handleVisibilityChange, false) this.$store.dispatch('clearCurrentChat') }, computed: { - recipient() { + recipient () { return this.currentChat && this.currentChat.account }, - recipientId() { + recipientId () { return this.$route.params.recipient_id }, - formPlaceholder() { + formPlaceholder () { if (this.recipient) { - return this.$t('chats.message_user', { - nickname: this.recipient.screen_name_ui, - }) + return this.$t('chats.message_user', { nickname: this.recipient.screen_name_ui }) } else { return '' } }, - chatViewItems() { + chatViewItems () { return chatService.getView(this.currentChatMessageService) }, - newMessageCount() { - return ( - this.currentChatMessageService && - this.currentChatMessageService.newMessageCount - ) + newMessageCount () { + return this.currentChatMessageService && this.currentChatMessageService.newMessageCount }, - streamingEnabled() { - return ( - this.mergedConfig.useStreamingApi && - this.mastoUserSocketStatus === WSConnectionStatus.JOINED - ) + streamingEnabled () { + return this.mergedConfig.useStreamingApi && this.mastoUserSocketStatus === WSConnectionStatus.JOINED }, ...mapGetters([ 'currentChat', 'currentChatMessageService', 'findOpenedChatByRecipientId', - 'mergedConfig', + 'mergedConfig' ]), ...mapPiniaState(useInterfaceStore, { - mobileLayout: (store) => store.layoutType === 'mobile', + mobileLayout: store => store.layoutType === 'mobile' }), ...mapState({ - backendInteractor: (state) => state.api.backendInteractor, - mastoUserSocketStatus: (state) => state.api.mastoUserSocketStatus, - currentUser: (state) => state.users.currentUser, - }), + backendInteractor: state => state.api.backendInteractor, + mastoUserSocketStatus: state => state.api.mastoUserSocketStatus, + currentUser: state => state.users.currentUser + }) }, watch: { - chatViewItems() { + chatViewItems () { // We don't want to scroll to the bottom on a new message when the user is viewing older messages. // Therefore we need to know whether the scroll position was at the bottom before the DOM update. const bottomedOutBeforeUpdate = this.bottomedOut(BOTTOMED_OUT_OFFSET) @@ -131,23 +115,23 @@ const Chat = { $route: function () { this.startFetching() }, - mastoUserSocketStatus(newValue) { + mastoUserSocketStatus (newValue) { if (newValue === WSConnectionStatus.JOINED) { this.fetchChat({ isFirstFetch: true }) } - }, + } }, methods: { // Used to animate the avatar near the first message of the message chain when any message belonging to the chain is hovered - onMessageHover({ isHovered, messageChainId }) { + onMessageHover ({ isHovered, messageChainId }) { this.hoveredMessageChainId = isHovered ? messageChainId : undefined }, - onFilesDropped() { + onFilesDropped () { this.$nextTick(() => { this.handleResize() }) }, - handleVisibilityChange() { + handleVisibilityChange () { this.$nextTick(() => { if (!document.hidden && this.bottomedOut(BOTTOMED_OUT_OFFSET)) { this.scrollDown({ forceRead: true }) @@ -155,7 +139,7 @@ const Chat = { }) }, // "Sticks" scroll to bottom instead of top, helps with OSK resizing the viewport - handleResize(opts = {}) { + handleResize (opts = {}) { const { delayed = false } = opts if (delayed) { @@ -176,56 +160,40 @@ const Chat = { this.lastScrollPosition = getScrollPosition() }) }, - scrollDown(options = {}) { + scrollDown (options = {}) { const { behavior = 'auto', forceRead = false } = options this.$nextTick(() => { - window.scrollTo({ - top: document.documentElement.scrollHeight, - behavior, - }) + window.scrollTo({ top: document.documentElement.scrollHeight, behavior }) }) if (forceRead) { this.readChat() } }, - readChat() { - if ( - !( - this.currentChatMessageService && this.currentChatMessageService.maxId - ) - ) { - return - } - if (document.hidden) { - return - } + readChat () { + if (!(this.currentChatMessageService && this.currentChatMessageService.maxId)) { return } + if (document.hidden) { return } const lastReadId = this.currentChatMessageService.maxId this.$store.dispatch('readChat', { id: this.currentChat.id, - lastReadId, + lastReadId }) }, - bottomedOut(offset) { + bottomedOut (offset) { return isBottomedOut(offset) }, - reachedTop() { + reachedTop () { return window.scrollY <= 0 }, - cullOlderCheck() { + cullOlderCheck () { window.setTimeout(() => { if (this.bottomedOut(JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET)) { - this.$store.dispatch( - 'cullOlderMessages', - this.currentChatMessageService.chatId, - ) + this.$store.dispatch('cullOlderMessages', this.currentChatMessageService.chatId) } }, 5000) }, handleScroll: _.throttle(function () { this.lastScrollPosition = getScrollPosition() - if (!this.currentChat) { - return - } + if (!this.currentChat) { return } if (this.reachedTop()) { this.fetchChat({ maxId: this.currentChatMessageService.minId }) @@ -245,27 +213,22 @@ const Chat = { this.jumpToBottomButtonVisible = true } }, 200), - handleScrollUp(positionBeforeLoading) { + handleScrollUp (positionBeforeLoading) { const positionAfterLoading = getScrollPosition() window.scrollTo({ - top: getNewTopPosition(positionBeforeLoading, positionAfterLoading), + top: getNewTopPosition(positionBeforeLoading, positionAfterLoading) }) }, - fetchChat({ isFirstFetch = false, fetchLatest = false, maxId }) { + fetchChat ({ isFirstFetch = false, fetchLatest = false, maxId }) { const chatMessageService = this.currentChatMessageService - if (!chatMessageService) { - return - } - if (fetchLatest && this.streamingEnabled) { - return - } + if (!chatMessageService) { return } + if (fetchLatest && this.streamingEnabled) { return } const chatId = chatMessageService.chatId const fetchOlderMessages = !!maxId const sinceId = fetchLatest && chatMessageService.maxId - return this.backendInteractor - .chatMessages({ id: chatId, maxId, sinceId }) + return this.backendInteractor.chatMessages({ id: chatId, maxId, sinceId }) .then((messages) => { // Clear the current chat in case we're recovering from a ws connection loss. if (isFirstFetch) { @@ -273,34 +236,28 @@ const Chat = { } const positionBeforeUpdate = getScrollPosition() - this.$store - .dispatch('addChatMessages', { chatId, messages }) - .then(() => { - this.$nextTick(() => { - if (fetchOlderMessages) { - this.handleScrollUp(positionBeforeUpdate) - } + this.$store.dispatch('addChatMessages', { chatId, messages }).then(() => { + this.$nextTick(() => { + if (fetchOlderMessages) { + this.handleScrollUp(positionBeforeUpdate) + } - // In vertical screens, the first batch of fetched messages may not always take the - // full height of the scrollable container. - // If this is the case, we want to fetch the messages until the scrollable container - // is fully populated so that the user has the ability to scroll up and load the history. - if (!isScrollable() && messages.length > 0) { - this.fetchChat({ - maxId: this.currentChatMessageService.minId, - }) - } - }) + // In vertical screens, the first batch of fetched messages may not always take the + // full height of the scrollable container. + // If this is the case, we want to fetch the messages until the scrollable container + // is fully populated so that the user has the ability to scroll up and load the history. + if (!isScrollable() && messages.length > 0) { + this.fetchChat({ maxId: this.currentChatMessageService.minId }) + } }) + }) }) }, - async startFetching() { + async startFetching () { let chat = this.findOpenedChatByRecipientId(this.recipientId) if (!chat) { try { - chat = await this.backendInteractor.getOrCreateChat({ - accountId: this.recipientId, - }) + chat = await this.backendInteractor.getOrCreateChat({ accountId: this.recipientId }) } catch (e) { console.error('Error creating or getting a chat', e) this.errorLoadingChat = true @@ -314,14 +271,13 @@ const Chat = { this.doStartFetching() } }, - doStartFetching() { + doStartFetching () { this.$store.dispatch('startFetchingCurrentChat', { - fetcher: () => - promiseInterval(() => this.fetchChat({ fetchLatest: true }), 5000), + fetcher: () => promiseInterval(() => this.fetchChat({ fetchLatest: true }), 5000) }) this.fetchChat({ isFirstFetch: true }) }, - handleAttachmentPosting() { + handleAttachmentPosting () { this.$nextTick(() => { this.handleResize() // When the posting form size changes because of a media attachment, we need an extra resize @@ -329,11 +285,11 @@ const Chat = { this.scrollDown({ forceRead: true }) }) }, - sendMessage({ status, media, idempotencyKey }) { + sendMessage ({ status, media, idempotencyKey }) { const params = { id: this.currentChat.id, content: status, - idempotencyKey, + idempotencyKey } if (media[0]) { @@ -345,72 +301,52 @@ const Chat = { chatId: this.currentChat.id, content: status, userId: this.currentUser.id, - idempotencyKey, + idempotencyKey }) - this.$store - .dispatch('addChatMessages', { - chatId: this.currentChat.id, - messages: [fakeMessage], - }) - .then(() => { - this.handleAttachmentPosting() - }) - - return this.doSendMessage({ - params, - fakeMessage, - retriesLeft: MAX_RETRIES, + this.$store.dispatch('addChatMessages', { + chatId: this.currentChat.id, + messages: [fakeMessage] + }).then(() => { + this.handleAttachmentPosting() }) + + return this.doSendMessage({ params, fakeMessage, retriesLeft: MAX_RETRIES }) }, - doSendMessage({ params, fakeMessage, retriesLeft = MAX_RETRIES }) { + doSendMessage ({ params, fakeMessage, retriesLeft = MAX_RETRIES }) { if (retriesLeft <= 0) return - this.backendInteractor - .sendChatMessage(params) - .then((data) => { + this.backendInteractor.sendChatMessage(params) + .then(data => { this.$store.dispatch('addChatMessages', { chatId: this.currentChat.id, updateMaxId: false, - messages: [{ ...data, fakeId: fakeMessage.id }], + messages: [{ ...data, fakeId: fakeMessage.id }] }) return data }) - .catch((error) => { + .catch(error => { console.error('Error sending message', error) this.$store.dispatch('handleMessageError', { chatId: this.currentChat.id, fakeId: fakeMessage.id, - isRetry: retriesLeft !== MAX_RETRIES, + isRetry: retriesLeft !== MAX_RETRIES }) - if ( - (error.statusCode >= 500 && error.statusCode < 600) || - error.message === 'Failed to fetch' - ) { - this.messageRetriers[fakeMessage.id] = setTimeout( - () => { - this.doSendMessage({ - params, - fakeMessage, - retriesLeft: retriesLeft - 1, - }) - }, - 1000 * 2 ** (MAX_RETRIES - retriesLeft), - ) + if ((error.statusCode >= 500 && error.statusCode < 600) || error.message === 'Failed to fetch') { + this.messageRetriers[fakeMessage.id] = setTimeout(() => { + this.doSendMessage({ params, fakeMessage, retriesLeft: retriesLeft - 1 }) + }, 1000 * (2 ** (MAX_RETRIES - retriesLeft))) } return {} }) return Promise.resolve(fakeMessage) }, - goBack() { - this.$router.push({ - name: 'chats', - params: { username: this.currentUser.screen_name }, - }) - }, - }, + goBack () { + this.$router.push({ name: 'chats', params: { username: this.currentUser.screen_name } }) + } + } } export default Chat diff --git a/src/components/chat/chat.style.js b/src/components/chat/chat.style.js index 55cf657c2..9ae2b7d71 100644 --- a/src/components/chat/chat.style.js +++ b/src/components/chat/chat.style.js @@ -1,13 +1,19 @@ export default { name: 'Chat', selector: '.chat-message-list', - validInnerComponents: ['Text', 'Link', 'Icon', 'Avatar', 'ChatMessage'], + validInnerComponents: [ + 'Text', + 'Link', + 'Icon', + 'Avatar', + 'ChatMessage' + ], defaultRules: [ { directives: { background: '--bg', - blur: '5px', - }, - }, - ], + blur: '5px' + } + } + ] } diff --git a/src/components/chat/chat_layout_utils.js b/src/components/chat/chat_layout_utils.js index 10d0a5e45..c187892d9 100644 --- a/src/components/chat/chat_layout_utils.js +++ b/src/components/chat/chat_layout_utils.js @@ -3,17 +3,14 @@ export const getScrollPosition = () => { return { scrollTop: window.scrollY, scrollHeight: document.documentElement.scrollHeight, - offsetHeight: window.innerHeight, + offsetHeight: window.innerHeight } } // A helper function that is used to keep the scroll position fixed as the new elements are added to the top // Takes two scroll positions, before and after the update. export const getNewTopPosition = (previousPosition, newPosition) => { - return ( - previousPosition.scrollTop + - (newPosition.scrollHeight - previousPosition.scrollHeight) - ) + return previousPosition.scrollTop + (newPosition.scrollHeight - previousPosition.scrollHeight) } export const isBottomedOut = (offset = 0) => { diff --git a/src/components/chat_list/chat_list.js b/src/components/chat_list/chat_list.js index 8081d0670..95708d1dd 100644 --- a/src/components/chat_list/chat_list.js +++ b/src/components/chat_list/chat_list.js @@ -1,4 +1,4 @@ -import { mapGetters, mapState } from 'vuex' +import { mapState, mapGetters } from 'vuex' import ChatListItem from '../chat_list_item/chat_list_item.vue' import ChatNew from '../chat_new/chat_new.vue' import List from '../list/list.vue' @@ -7,31 +7,31 @@ const ChatList = { components: { ChatListItem, List, - ChatNew, + ChatNew }, computed: { ...mapState({ - currentUser: (state) => state.users.currentUser, + currentUser: state => state.users.currentUser }), - ...mapGetters(['sortedChatList']), + ...mapGetters(['sortedChatList']) }, - data() { + data () { return { - isNew: false, + isNew: false } }, - created() { + created () { this.$store.dispatch('fetchChats', { latest: true }) }, methods: { - cancelNewChat() { + cancelNewChat () { this.isNew = false this.$store.dispatch('fetchChats', { latest: true }) }, - newChat() { + newChat () { this.isNew = true - }, - }, + } + } } export default ChatList diff --git a/src/components/chat_list_item/chat_list_item.js b/src/components/chat_list_item/chat_list_item.js index ba8f5528b..8f8c491f5 100644 --- a/src/components/chat_list_item/chat_list_item.js +++ b/src/components/chat_list_item/chat_list_item.js @@ -1,33 +1,31 @@ -import fileType from 'src/services/file_type/file_type.service' import { mapState } from 'vuex' -import AvatarList from '../avatar_list/avatar_list.vue' -import ChatTitle from '../chat_title/chat_title.vue' import StatusBody from '../status_content/status_content.vue' -import Timeago from '../timeago/timeago.vue' +import fileType from 'src/services/file_type/file_type.service' import UserAvatar from '../user_avatar/user_avatar.vue' +import AvatarList from '../avatar_list/avatar_list.vue' +import Timeago from '../timeago/timeago.vue' +import ChatTitle from '../chat_title/chat_title.vue' const ChatListItem = { name: 'ChatListItem', - props: ['chat'], + props: [ + 'chat' + ], components: { UserAvatar, AvatarList, Timeago, ChatTitle, - StatusBody, + StatusBody }, computed: { ...mapState({ - currentUser: (state) => state.users.currentUser, + currentUser: state => state.users.currentUser }), - attachmentInfo() { - if (this.chat.lastMessage.attachments.length === 0) { - return - } + attachmentInfo () { + if (this.chat.lastMessage.attachments.length === 0) { return } - const types = this.chat.lastMessage.attachments.map((file) => - fileType.fileType(file.mimetype), - ) + const types = this.chat.lastMessage.attachments.map(file => fileType.fileType(file.mimetype)) if (types.includes('video')) { return this.$t('file_type.video') } else if (types.includes('audio')) { @@ -38,36 +36,34 @@ const ChatListItem = { return this.$t('file_type.file') } }, - messageForStatusContent() { + messageForStatusContent () { const message = this.chat.lastMessage const messageEmojis = message ? message.emojis : [] const isYou = message && message.account_id === this.currentUser.id - const content = message ? this.attachmentInfo || message.content : '' - const messagePreview = isYou - ? `${this.$t('chats.you')} ${content}` - : content + const content = message ? (this.attachmentInfo || message.content) : '' + const messagePreview = isYou ? `${this.$t('chats.you')} ${content}` : content return { summary: '', emojis: messageEmojis, raw_html: messagePreview, text: messagePreview, - attachments: [], + attachments: [] } - }, + } }, methods: { - openChat() { + openChat () { if (this.chat.id) { this.$router.push({ name: 'chat', params: { username: this.currentUser.screen_name, - recipient_id: this.chat.account.id, - }, + recipient_id: this.chat.account.id + } }) } - }, - }, + } + } } export default ChatListItem diff --git a/src/components/chat_message/chat_message.js b/src/components/chat_message/chat_message.js index 0d3876ab6..837f6d214 100644 --- a/src/components/chat_message/chat_message.js +++ b/src/components/chat_message/chat_message.js @@ -1,18 +1,24 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faEllipsisH, faTimes } from '@fortawesome/free-solid-svg-icons' +import { mapState, mapGetters } from 'vuex' import { mapState as mapPiniaState } from 'pinia' -import { useInterfaceStore } from 'src/stores/interface' -import { defineAsyncComponent } from 'vue' -import { mapGetters, mapState } from 'vuex' +import Popover from '../popover/popover.vue' import Attachment from '../attachment/attachment.vue' -import ChatMessageDate from '../chat_message_date/chat_message_date.vue' +import UserAvatar from '../user_avatar/user_avatar.vue' import Gallery from '../gallery/gallery.vue' import LinkPreview from '../link-preview/link-preview.vue' -import Popover from '../popover/popover.vue' import StatusContent from '../status_content/status_content.vue' -import UserAvatar from '../user_avatar/user_avatar.vue' +import ChatMessageDate from '../chat_message_date/chat_message_date.vue' +import { defineAsyncComponent } from 'vue' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faTimes, + faEllipsisH +} from '@fortawesome/free-solid-svg-icons' +import { useInterfaceStore } from 'src/stores/interface' -library.add(faTimes, faEllipsisH) +library.add( + faTimes, + faEllipsisH +) const ChatMessage = { name: 'ChatMessage', @@ -21,7 +27,7 @@ const ChatMessage = { 'edited', 'noHeading', 'chatViewItem', - 'hoveredMessageChain', + 'hoveredMessageChain' ], emits: ['hover'], components: { @@ -32,82 +38,73 @@ const ChatMessage = { Gallery, LinkPreview, ChatMessageDate, - UserPopover: defineAsyncComponent( - () => import('../user_popover/user_popover.vue'), - ), + UserPopover: defineAsyncComponent(() => import('../user_popover/user_popover.vue')) }, computed: { // Returns HH:MM (hours and minutes) in local time. - createdAt() { + createdAt () { const time = this.chatViewItem.data.created_at - return time.toLocaleTimeString('en', { - hour: '2-digit', - minute: '2-digit', - hour12: false, - }) + return time.toLocaleTimeString('en', { hour: '2-digit', minute: '2-digit', hour12: false }) }, - isCurrentUser() { + isCurrentUser () { return this.message.account_id === this.currentUser.id }, - message() { + message () { return this.chatViewItem.data }, - isMessage() { + isMessage () { return this.chatViewItem.type === 'message' }, - messageForStatusContent() { + messageForStatusContent () { return { summary: '', emojis: this.message.emojis, raw_html: this.message.content || '', text: this.message.content || '', - attachments: this.message.attachments, + attachments: this.message.attachments } }, - hasAttachment() { + hasAttachment () { return this.message.attachments.length > 0 }, ...mapPiniaState(useInterfaceStore, { - betterShadow: (store) => store.browserSupport.cssFilter, + betterShadow: store => store.browserSupport.cssFilter }), ...mapState({ - currentUser: (state) => state.users.currentUser, - restrictedNicknames: (state) => state.instance.restrictedNicknames, + currentUser: state => state.users.currentUser, + restrictedNicknames: state => state.instance.restrictedNicknames }), - popoverMarginStyle() { + popoverMarginStyle () { if (this.isCurrentUser) { return {} } else { return { left: 50 } } }, - ...mapGetters(['mergedConfig', 'findUser']), + ...mapGetters(['mergedConfig', 'findUser']) }, - data() { + data () { return { hovered: false, - menuOpened: false, + menuOpened: false } }, methods: { - onHover(bool) { - this.$emit('hover', { - isHovered: bool, - messageChainId: this.chatViewItem.messageChainId, - }) + onHover (bool) { + this.$emit('hover', { isHovered: bool, messageChainId: this.chatViewItem.messageChainId }) }, - async deleteMessage() { + async deleteMessage () { const confirmed = window.confirm(this.$t('chats.delete_confirm')) if (confirmed) { await this.$store.dispatch('deleteChatMessage', { messageId: this.chatViewItem.data.id, - chatId: this.chatViewItem.data.chat_id, + chatId: this.chatViewItem.data.chat_id }) } this.hovered = false this.menuOpened = false - }, - }, + } + } } export default ChatMessage diff --git a/src/components/chat_message/chat_message.style.js b/src/components/chat_message/chat_message.style.js index f7632bc6f..76b565823 100644 --- a/src/components/chat_message/chat_message.style.js +++ b/src/components/chat_message/chat_message.style.js @@ -2,21 +2,26 @@ export default { name: 'ChatMessage', selector: '.chat-message', variants: { - outgoing: '.outgoing', + outgoing: '.outgoing' }, - validInnerComponents: ['Text', 'Icon', 'Border', 'PollGraph'], + validInnerComponents: [ + 'Text', + 'Icon', + 'Border', + 'PollGraph' + ], defaultRules: [ { directives: { background: '--bg, 2', - backgroundNoCssColor: 'yes', - }, + backgroundNoCssColor: 'yes' + } }, { variant: 'outgoing', directives: { - background: '--bg, 5', - }, - }, - ], + background: '--bg, 5' + } + } + ] } diff --git a/src/components/chat_message_date/chat_message_date.vue b/src/components/chat_message_date/chat_message_date.vue index f0cadb6e7..98349b753 100644 --- a/src/components/chat_message_date/chat_message_date.vue +++ b/src/components/chat_message_date/chat_message_date.vue @@ -11,19 +11,16 @@ export default { name: 'Timeago', props: ['date'], computed: { - displayDate() { + displayDate () { const today = new Date() today.setHours(0, 0, 0, 0) if (this.date.getTime() === today.getTime()) { return this.$t('display_date.today') } else { - return this.date.toLocaleDateString( - localeService.internalToBrowserLocale(this.$i18n.locale), - { day: 'numeric', month: 'long' }, - ) + return this.date.toLocaleDateString(localeService.internalToBrowserLocale(this.$i18n.locale), { day: 'numeric', month: 'long' }) } - }, - }, + } + } } diff --git a/src/components/chat_new/chat_new.js b/src/components/chat_new/chat_new.js index d9f73193c..71585995a 100644 --- a/src/components/chat_new/chat_new.js +++ b/src/components/chat_new/chat_new.js @@ -1,33 +1,39 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faChevronLeft, faSearch } from '@fortawesome/free-solid-svg-icons' -import { mapGetters, mapState } from 'vuex' +import { mapState, mapGetters } from 'vuex' import BasicUserCard from '../basic_user_card/basic_user_card.vue' import UserAvatar from '../user_avatar/user_avatar.vue' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faSearch, + faChevronLeft +} from '@fortawesome/free-solid-svg-icons' -library.add(faSearch, faChevronLeft) +library.add( + faSearch, + faChevronLeft +) const chatNew = { components: { BasicUserCard, - UserAvatar, + UserAvatar }, - data() { + data () { return { suggestions: [], userIds: [], loading: false, - query: '', + query: '' } }, - async created() { + async created () { const { chats } = await this.backendInteractor.chats() - chats.forEach((chat) => this.suggestions.push(chat.account)) + chats.forEach(chat => this.suggestions.push(chat.account)) }, computed: { - users() { - return this.userIds.map((userId) => this.findUser(userId)) + users () { + return this.userIds.map(userId => this.findUser(userId)) }, - availableUsers() { + availableUsers () { if (this.query.length !== 0) { return this.users } else { @@ -35,29 +41,29 @@ const chatNew = { } }, ...mapState({ - currentUser: (state) => state.users.currentUser, - backendInteractor: (state) => state.api.backendInteractor, + currentUser: state => state.users.currentUser, + backendInteractor: state => state.api.backendInteractor }), - ...mapGetters(['findUser']), + ...mapGetters(['findUser']) }, methods: { - goBack() { + goBack () { this.$emit('cancel') }, - goToChat(user) { + goToChat (user) { this.$router.push({ name: 'chat', params: { recipient_id: user.id } }) }, - onInput() { + onInput () { this.search(this.query) }, - addUser(user) { + addUser (user) { this.selectedUserIds.push(user.id) this.query = '' }, - removeUser(userId) { - this.selectedUserIds = this.selectedUserIds.filter((id) => id !== userId) + removeUser (userId) { + this.selectedUserIds = this.selectedUserIds.filter(id => id !== userId) }, - search(query) { + search (query) { if (!query) { this.loading = false return @@ -65,14 +71,13 @@ const chatNew = { this.loading = true this.userIds = [] - this.$store - .dispatch('search', { q: query, resolve: true, type: 'accounts' }) - .then((data) => { + this.$store.dispatch('search', { q: query, resolve: true, type: 'accounts' }) + .then(data => { this.loading = false - this.userIds = data.accounts.map((a) => a.id) + this.userIds = data.accounts.map(a => a.id) }) - }, - }, + } + } } export default chatNew diff --git a/src/components/chat_title/chat_title.js b/src/components/chat_title/chat_title.js index 7748f8973..b87211265 100644 --- a/src/components/chat_title/chat_title.js +++ b/src/components/chat_title/chat_title.js @@ -1,23 +1,23 @@ +import UserAvatar from '../user_avatar/user_avatar.vue' import RichContent from 'src/components/rich_content/rich_content.jsx' import { defineAsyncComponent } from 'vue' -import UserAvatar from '../user_avatar/user_avatar.vue' export default { name: 'ChatTitle', components: { UserAvatar, RichContent, - UserPopover: defineAsyncComponent( - () => import('../user_popover/user_popover.vue'), - ), + UserPopover: defineAsyncComponent(() => import('../user_popover/user_popover.vue')) }, - props: ['user', 'withAvatar'], + props: [ + 'user', 'withAvatar' + ], computed: { - title() { + title () { return this.user ? this.user.screen_name_ui : '' }, - htmlTitle() { + htmlTitle () { return this.user ? this.user.name_html : '' - }, - }, + } + } } diff --git a/src/components/checkbox/checkbox.vue b/src/components/checkbox/checkbox.vue index cbe3dd80f..1e0f5ad05 100644 --- a/src/components/checkbox/checkbox.vue +++ b/src/components/checkbox/checkbox.vue @@ -36,25 +36,30 @@ diff --git a/src/components/color_input/color_input.vue b/src/components/color_input/color_input.vue index 76a00416c..58aee575c 100644 --- a/src/components/color_input/color_input.vue +++ b/src/components/color_input/color_input.vue @@ -64,93 +64,95 @@ diff --git a/src/components/component_preview/component_preview.js b/src/components/component_preview/component_preview.js index 1d54f58de..9f830cd72 100644 --- a/src/components/component_preview/component_preview.js +++ b/src/components/component_preview/component_preview.js @@ -2,15 +2,12 @@ import Checkbox from 'src/components/checkbox/checkbox.vue' import ColorInput from 'src/components/color_input/color_input.vue' import genRandomSeed from 'src/services/random_seed/random_seed.service.js' -import { - adoptStyleSheets, - createStyleSheet, -} from 'src/services/style_setter/style_setter.js' +import { createStyleSheet, adoptStyleSheets } from 'src/services/style_setter/style_setter.js' export default { components: { Checkbox, - ColorInput, + ColorInput }, props: [ 'shadow', @@ -20,41 +17,41 @@ export default { 'previewCss', 'disabled', 'invalid', - 'noColorControl', + 'noColorControl' ], emits: ['update:shadow'], - data() { + data () { return { colorOverride: undefined, lightGrid: false, zoom: 100, - randomSeed: genRandomSeed(), + randomSeed: genRandomSeed() } }, - mounted() { + mounted () { this.update() }, computed: { - hideControls() { + hideControls () { return typeof this.shadow === 'string' - }, + } }, watch: { - previewCss() { + previewCss () { this.update() }, - previewStyle() { + previewStyle () { this.update() }, - zoom() { + zoom () { this.update() - }, + } }, methods: { - updateProperty(axis, value) { + updateProperty (axis, value) { this.$emit('update:shadow', { axis, value: Number(value) }) }, - update() { + update () { const sheet = createStyleSheet('style-component-preview', 90) sheet.clear() @@ -63,25 +60,23 @@ export default { if (this.colorOverride) result.push(`--background: ${this.colorOverride}`) const styleRule = [ - '#component-preview-', - this.randomSeed, - ' {\n', + '#component-preview-', this.randomSeed, ' {\n', '.preview-block {\n', `zoom: ${this.zoom / 100};`, this.previewStyle, '\n}', - '\n}', + '\n}' ].join('') sheet.addRule(styleRule) - sheet.addRule( - ['#component-preview-', this.randomSeed, ' {\n', ...result, '\n}'].join( - '', - ), - ) + sheet.addRule([ + '#component-preview-', this.randomSeed, ' {\n', + ...result, + '\n}' + ].join('')) sheet.ready = true adoptStyleSheets() - }, - }, + } + } } diff --git a/src/components/confirm_modal/confirm_modal.js b/src/components/confirm_modal/confirm_modal.js index cd83194be..3e2bc2cb7 100644 --- a/src/components/confirm_modal/confirm_modal.js +++ b/src/components/confirm_modal/confirm_modal.js @@ -9,29 +9,30 @@ import DialogModal from '../dialog_modal/dialog_modal.vue' */ const ConfirmModal = { components: { - DialogModal, + DialogModal }, props: { title: { - type: String, + type: String }, cancelText: { - type: String, + type: String }, confirmText: { - type: String, - }, + type: String + } }, emits: ['cancelled', 'accepted'], - computed: {}, + computed: { + }, methods: { - onCancel() { + onCancel () { this.$emit('cancelled') }, - onAccept() { + onAccept () { this.$emit('accepted') - }, - }, + } + } } export default ConfirmModal diff --git a/src/components/confirm_modal/mute_confirm.js b/src/components/confirm_modal/mute_confirm.js index 2ccb0b3bc..a279dc716 100644 --- a/src/components/confirm_modal/mute_confirm.js +++ b/src/components/confirm_modal/mute_confirm.js @@ -1,66 +1,64 @@ -import Select from 'src/components/select/select.vue' import { mapGetters } from 'vuex' + import ConfirmModal from './confirm_modal.vue' +import Select from 'src/components/select/select.vue' export default { props: ['type', 'user', 'status'], emits: ['hide', 'show', 'muted'], data: () => ({ - showing: false, + showing: false }), components: { ConfirmModal, - Select, + Select }, computed: { - domain() { + domain () { return this.user.fqn.split('@')[1] }, - keypath() { + keypath () { if (this.type === 'domain') { return 'status.mute_domain_confirm' } else if (this.type === 'conversation') { return 'status.mute_conversation_confirm' } }, - conversationIsMuted() { + conversationIsMuted () { return this.status.conversation_muted }, - domainIsMuted() { - return new Set(this.$store.state.users.currentUser.domainMutes).has( - this.domain, - ) + domainIsMuted () { + return new Set(this.$store.state.users.currentUser.domainMutes).has(this.domain) }, - shouldConfirm() { + shouldConfirm () { switch (this.type) { case 'domain': { return this.mergedConfig.modalOnMuteDomain } - default: { - // conversation + default: { // conversation return this.mergedConfig.modalOnMuteConversation } } }, - ...mapGetters(['mergedConfig']), + ...mapGetters(['mergedConfig']) }, methods: { - optionallyPrompt() { + optionallyPrompt () { if (this.shouldConfirm) { this.show() } else { this.doMute() } }, - show() { + show () { this.showing = true this.$emit('show') }, - hide() { + hide () { this.showing = false this.$emit('hide') }, - doMute() { + doMute () { switch (this.type) { case 'domain': { if (!this.domainIsMuted) { @@ -81,6 +79,6 @@ export default { } this.$emit('muted') this.hide() - }, - }, + } + } } diff --git a/src/components/contrast_ratio/contrast_ratio.vue b/src/components/contrast_ratio/contrast_ratio.vue index 6294e6dd1..93799e4c2 100644 --- a/src/components/contrast_ratio/contrast_ratio.vue +++ b/src/components/contrast_ratio/contrast_ratio.vue @@ -57,73 +57,60 @@ diff --git a/src/components/conversation-page/conversation-page.js b/src/components/conversation-page/conversation-page.js index d4705303e..8f996be12 100644 --- a/src/components/conversation-page/conversation-page.js +++ b/src/components/conversation-page/conversation-page.js @@ -2,13 +2,13 @@ import Conversation from '../conversation/conversation.vue' const conversationPage = { components: { - Conversation, + Conversation }, computed: { - statusId() { + statusId () { return this.$route.params.id - }, - }, + } + } } export default conversationPage diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 055f43bb3..491a8543f 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -1,20 +1,25 @@ +import { reduce, filter, findIndex, clone, get } from 'lodash' +import Status from '../status/status.vue' +import ThreadTree from '../thread_tree/thread_tree.vue' +import { WSConnectionStatus } from '../../services/api/api.service.js' +import { mapGetters, mapState } from 'vuex' +import { mapState as mapPiniaState } from 'pinia' +import QuickFilterSettings from '../quick_filter_settings/quick_filter_settings.vue' +import QuickViewSettings from '../quick_view_settings/quick_view_settings.vue' +import { useInterfaceStore } from 'src/stores/interface' + import { library } from '@fortawesome/fontawesome-svg-core' import { faAngleDoubleDown, faAngleDoubleLeft, - faChevronLeft, + faChevronLeft } from '@fortawesome/free-solid-svg-icons' -import { clone, filter, findIndex, get, reduce } from 'lodash' -import { mapState as mapPiniaState } from 'pinia' -import { useInterfaceStore } from 'src/stores/interface' -import { mapGetters, mapState } from 'vuex' -import { WSConnectionStatus } from '../../services/api/api.service.js' -import QuickFilterSettings from '../quick_filter_settings/quick_filter_settings.vue' -import QuickViewSettings from '../quick_view_settings/quick_view_settings.vue' -import Status from '../status/status.vue' -import ThreadTree from '../thread_tree/thread_tree.vue' -library.add(faAngleDoubleDown, faAngleDoubleLeft, faChevronLeft) +library.add( + faAngleDoubleDown, + faAngleDoubleLeft, + faChevronLeft +) const sortById = (a, b) => { const idA = a.type === 'retweet' ? a.retweeted_status.id : a.id @@ -38,25 +43,23 @@ const sortAndFilterConversation = (conversation, statusoid) => { if (statusoid.type === 'retweet') { conversation = filter( conversation, - (status) => - status.type === 'retweet' || - status.id !== statusoid.retweeted_status.id, + (status) => (status.type === 'retweet' || status.id !== statusoid.retweeted_status.id) ) } else { conversation = filter(conversation, (status) => status.type !== 'retweet') } - return conversation.filter((_) => _).sort(sortById) + return conversation.filter(_ => _).sort(sortById) } const conversation = { - data() { + data () { return { highlight: null, expanded: false, threadDisplayStatusObject: {}, // id => 'showing' | 'hidden' statusContentPropertiesObject: {}, inlineDivePosition: null, - loadStatusError: null, + loadStatusError: null } }, props: [ @@ -66,80 +69,76 @@ const conversation = { 'pinnedStatusIdsObject', 'inProfile', 'profileUserId', - 'virtualHidden', + 'virtualHidden' ], - created() { + created () { if (this.isPage) { this.fetchConversation() } }, computed: { - maxDepthToShowByDefault() { + maxDepthToShowByDefault () { // maxDepthInThread = max number of depths that is *visible* // since our depth starts with 0 and "showing" means "showing children" // there is a -2 here const maxDepth = this.$store.getters.mergedConfig.maxDepthInThread - 2 return maxDepth >= 1 ? maxDepth : 1 }, - streamingEnabled() { - return ( - this.mergedConfig.useStreamingApi && - this.mastoUserSocketStatus === WSConnectionStatus.JOINED - ) + streamingEnabled () { + return this.mergedConfig.useStreamingApi && this.mastoUserSocketStatus === WSConnectionStatus.JOINED }, - displayStyle() { + displayStyle () { return this.$store.getters.mergedConfig.conversationDisplay }, - isTreeView() { + isTreeView () { return !this.isLinearView }, - treeViewIsSimple() { + treeViewIsSimple () { return !this.$store.getters.mergedConfig.conversationTreeAdvanced }, - isLinearView() { + isLinearView () { return this.displayStyle === 'linear' }, - shouldFadeAncestors() { + shouldFadeAncestors () { return this.$store.getters.mergedConfig.conversationTreeFadeAncestors }, - otherRepliesButtonPosition() { + otherRepliesButtonPosition () { return this.$store.getters.mergedConfig.conversationOtherRepliesButton }, - showOtherRepliesButtonBelowStatus() { + showOtherRepliesButtonBelowStatus () { return this.otherRepliesButtonPosition === 'below' }, - showOtherRepliesButtonInsideStatus() { + showOtherRepliesButtonInsideStatus () { return this.otherRepliesButtonPosition === 'inside' }, - suspendable() { + suspendable () { if (this.isTreeView) { - return Object.entries(this.statusContentProperties).every( - ([, prop]) => !prop.replying && prop.mediaPlaying.length === 0, - ) + return Object.entries(this.statusContentProperties) + .every(([, prop]) => !prop.replying && prop.mediaPlaying.length === 0) } if (this.$refs.statusComponent && this.$refs.statusComponent[0]) { - return this.$refs.statusComponent.every((s) => s.suspendable) + return this.$refs.statusComponent.every(s => s.suspendable) } else { return true } }, - hideStatus() { + hideStatus () { return this.virtualHidden && this.suspendable }, - status() { + status () { return this.$store.state.statuses.allStatusesObject[this.statusId] }, - originalStatusId() { + originalStatusId () { if (this.status.retweeted_status) { return this.status.retweeted_status.id } else { return this.statusId } }, - conversationId() { + conversationId () { return this.getConversationId(this.statusId) }, - conversation() { + conversation () { if (!this.status) { return [] } @@ -148,9 +147,7 @@ const conversation = { return [this.status] } - const conversation = clone( - this.$store.state.statuses.conversationsObject[this.conversationId], - ) + const conversation = clone(this.$store.state.statuses.conversationsObject[this.conversationId]) const statusIndex = findIndex(conversation, { id: this.originalStatusId }) if (statusIndex !== -1) { conversation[statusIndex] = this.status @@ -158,188 +155,144 @@ const conversation = { return sortAndFilterConversation(conversation, this.status) }, - statusMap() { + statusMap () { return this.conversation.reduce((res, s) => { res[s.id] = s return res }, {}) }, - threadTree() { - const reverseLookupTable = this.conversation.reduce( - (table, status, index) => { - table[status.id] = index - return table - }, - {}, - ) + threadTree () { + const reverseLookupTable = this.conversation.reduce((table, status, index) => { + table[status.id] = index + return table + }, {}) - const threads = this.conversation.reduce( - (a, cur) => { - const id = cur.id - a.forest[id] = this.getReplies(id).map((s) => s.id) + const threads = this.conversation.reduce((a, cur) => { + const id = cur.id + a.forest[id] = this.getReplies(id) + .map(s => s.id) - return a - }, - { - forest: {}, - }, - ) + return a + }, { + forest: {} + }) - const walk = (forest, topLevel, depth = 0, processed = {}) => - topLevel - .map((id) => { - if (processed[id]) { - return [] - } + const walk = (forest, topLevel, depth = 0, processed = {}) => topLevel.map(id => { + if (processed[id]) { + return [] + } - processed[id] = true - return [ - { - status: this.conversation[reverseLookupTable[id]], - id, - depth, - }, - walk(forest, forest[id], depth + 1, processed), - ].reduce((a, b) => a.concat(b), []) - }) - .reduce((a, b) => a.concat(b), []) + processed[id] = true + return [{ + status: this.conversation[reverseLookupTable[id]], + id, + depth + }, walk(forest, forest[id], depth + 1, processed)].reduce((a, b) => a.concat(b), []) + }).reduce((a, b) => a.concat(b), []) - const linearized = walk( - threads.forest, - this.topLevel.map((k) => k.id), - ) + const linearized = walk(threads.forest, this.topLevel.map(k => k.id)) return linearized }, - replyIds() { - return this.conversation - .map((k) => k.id) + replyIds () { + return this.conversation.map(k => k.id) .reduce((res, id) => { - res[id] = (this.replies[id] || []).map((k) => k.id) + res[id] = (this.replies[id] || []).map(k => k.id) return res }, {}) }, - totalReplyCount() { + totalReplyCount () { const sizes = {} const subTreeSizeFor = (id) => { if (sizes[id]) { return sizes[id] } - sizes[id] = - 1 + - this.replyIds[id] - .map((cid) => subTreeSizeFor(cid)) - .reduce((a, b) => a + b, 0) + sizes[id] = 1 + this.replyIds[id].map(cid => subTreeSizeFor(cid)).reduce((a, b) => a + b, 0) return sizes[id] } - this.conversation.map((k) => k.id).map(subTreeSizeFor) + this.conversation.map(k => k.id).map(subTreeSizeFor) return Object.keys(sizes).reduce((res, id) => { res[id] = sizes[id] - 1 // exclude itself return res }, {}) }, - totalReplyDepth() { + totalReplyDepth () { const depths = {} const subTreeDepthFor = (id) => { if (depths[id]) { return depths[id] } - depths[id] = - 1 + - this.replyIds[id] - .map((cid) => subTreeDepthFor(cid)) - .reduce((a, b) => (a > b ? a : b), 0) + depths[id] = 1 + this.replyIds[id].map(cid => subTreeDepthFor(cid)).reduce((a, b) => a > b ? a : b, 0) return depths[id] } - this.conversation.map((k) => k.id).map(subTreeDepthFor) + this.conversation.map(k => k.id).map(subTreeDepthFor) return Object.keys(depths).reduce((res, id) => { res[id] = depths[id] - 1 // exclude itself return res }, {}) }, - depths() { + depths () { return this.threadTree.reduce((a, k) => { a[k.id] = k.depth return a }, {}) }, - topLevel() { - const topLevel = this.conversation.reduce( - (tl, cur) => - tl.filter( - (k) => - this.getReplies(cur.id) - .map((v) => v.id) - .indexOf(k.id) === -1, - ), - this.conversation, - ) + topLevel () { + const topLevel = this.conversation.reduce((tl, cur) => + tl.filter(k => this.getReplies(cur.id).map(v => v.id).indexOf(k.id) === -1), this.conversation) return topLevel }, - otherTopLevelCount() { + otherTopLevelCount () { return this.topLevel.length - 1 }, - showingTopLevel() { + showingTopLevel () { if (this.canDive && this.diveRoot) { return [this.statusMap[this.diveRoot]] } return this.topLevel }, - diveRoot() { + diveRoot () { const statusId = this.inlineDivePosition || this.statusId const isTopLevel = !this.parentOf(statusId) return isTopLevel ? null : statusId }, - diveDepth() { + diveDepth () { return this.canDive && this.diveRoot ? this.depths[this.diveRoot] : 0 }, - diveMode() { + diveMode () { return this.canDive && !!this.diveRoot }, - shouldShowAllConversationButton() { + shouldShowAllConversationButton () { // The "show all conversation" button tells the user that there exist // other toplevel statuses, so do not show it if there is only a single root - return ( - this.isTreeView && - this.isExpanded && - this.diveMode && - this.topLevel.length > 1 - ) + return this.isTreeView && this.isExpanded && this.diveMode && this.topLevel.length > 1 }, - shouldShowAncestors() { - return ( - this.isTreeView && - this.isExpanded && - this.ancestorsOf(this.diveRoot).length - ) + shouldShowAncestors () { + return this.isTreeView && this.isExpanded && this.ancestorsOf(this.diveRoot).length }, - replies() { + replies () { let i = 1 - return reduce( - this.conversation, - (result, { id, in_reply_to_status_id: irid }) => { - if (irid) { - result[irid] = result[irid] || [] - result[irid].push({ - name: `#${i}`, - id, - }) - } - i++ - return result - }, - {}, - ) + return reduce(this.conversation, (result, { id, in_reply_to_status_id: irid }) => { + if (irid) { + result[irid] = result[irid] || [] + result[irid].push({ + name: `#${i}`, + id + }) + } + i++ + return result + }, {}) }, - isExpanded() { + isExpanded () { return !!(this.expanded || this.isPage) }, - hiddenStyle() { + hiddenStyle () { const height = (this.status && this.status.virtualHeight) || '120px' return this.virtualHidden ? { height } : {} }, - threadDisplayStatus() { + threadDisplayStatus () { return this.conversation.reduce((a, k) => { const id = k.id const depth = this.depths[id] @@ -347,7 +300,7 @@ const conversation = { if (this.threadDisplayStatusObject[id]) { return this.threadDisplayStatusObject[id] } - if (depth - this.diveDepth <= this.maxDepthToShowByDefault) { + if ((depth - this.diveDepth) <= this.maxDepthToShowByDefault) { return 'showing' } else { return 'hidden' @@ -358,7 +311,7 @@ const conversation = { return a }, {}) }, - statusContentProperties() { + statusContentProperties () { return this.conversation.reduce((a, k) => { const id = k.id const props = (() => { @@ -367,13 +320,13 @@ const conversation = { expandingSubject: false, showingLongSubject: false, isReplying: false, - mediaPlaying: [], + mediaPlaying: [] } if (this.statusContentPropertiesObject[id]) { return { ...def, - ...this.statusContentPropertiesObject[id], + ...this.statusContentPropertiesObject[id] } } return def @@ -383,59 +336,54 @@ const conversation = { return a }, {}) }, - canDive() { + canDive () { return this.isTreeView && this.isExpanded }, - maybeHighlight() { + maybeHighlight () { return this.isExpanded ? this.highlight : null }, ...mapGetters(['mergedConfig']), ...mapState({ - mastoUserSocketStatus: (state) => state.api.mastoUserSocketStatus, + mastoUserSocketStatus: state => state.api.mastoUserSocketStatus }), ...mapPiniaState(useInterfaceStore, { - mobileLayout: (store) => store.layoutType === 'mobile', - }), + mobileLayout: store => store.layoutType === 'mobile' + }) }, components: { Status, ThreadTree, QuickFilterSettings, - QuickViewSettings, + QuickViewSettings }, watch: { - statusId(newVal, oldVal) { + statusId (newVal, oldVal) { const newConversationId = this.getConversationId(newVal) const oldConversationId = this.getConversationId(oldVal) - if ( - newConversationId && - oldConversationId && - newConversationId === oldConversationId - ) { + if (newConversationId && oldConversationId && newConversationId === oldConversationId) { this.setHighlight(this.originalStatusId) } else { this.fetchConversation() } }, - expanded(value) { + expanded (value) { if (value) { this.fetchConversation() } else { this.resetDisplayState() } }, - virtualHidden() { - this.$store.dispatch('setVirtualHeight', { - statusId: this.statusId, - height: `${this.$el.clientHeight}px`, - }) - }, + virtualHidden () { + this.$store.dispatch( + 'setVirtualHeight', + { statusId: this.statusId, height: `${this.$el.clientHeight}px` } + ) + } }, methods: { - fetchConversation() { + fetchConversation () { if (this.status) { - this.$store.state.api.backendInteractor - .fetchConversation({ id: this.statusId }) + this.$store.state.api.backendInteractor.fetchConversation({ id: this.statusId }) .then(({ ancestors, descendants }) => { this.$store.dispatch('addNewStatuses', { statuses: ancestors }) this.$store.dispatch('addNewStatuses', { statuses: descendants }) @@ -443,8 +391,7 @@ const conversation = { }) } else { this.loadStatusError = null - this.$store.state.api.backendInteractor - .fetchStatus({ id: this.statusId }) + this.$store.state.api.backendInteractor.fetchStatus({ id: this.statusId }) .then((status) => { this.$store.dispatch('addNewStatuses', { statuses: [status] }) this.fetchConversation() @@ -454,16 +401,16 @@ const conversation = { }) } }, - isFocused(id) { - return this.isExpanded && id === this.highlight + isFocused (id) { + return (this.isExpanded) && id === this.highlight }, - getReplies(id) { + getReplies (id) { return this.replies[id] || [] }, - getHighlight() { + getHighlight () { return this.isExpanded ? this.highlight : null }, - setHighlight(id) { + setHighlight (id) { if (!id) return this.highlight = id @@ -474,54 +421,44 @@ const conversation = { this.$store.dispatch('fetchFavsAndRepeats', id) this.$store.dispatch('fetchEmojiReactionsBy', id) }, - toggleExpanded() { + toggleExpanded () { this.expanded = !this.expanded }, - getConversationId(statusId) { + getConversationId (statusId) { const status = this.$store.state.statuses.allStatusesObject[statusId] - return get( - status, - 'retweeted_status.statusnet_conversation_id', - get(status, 'statusnet_conversation_id'), - ) + return get(status, 'retweeted_status.statusnet_conversation_id', get(status, 'statusnet_conversation_id')) }, - setThreadDisplay(id, nextStatus) { + setThreadDisplay (id, nextStatus) { this.threadDisplayStatusObject = { ...this.threadDisplayStatusObject, - [id]: nextStatus, + [id]: nextStatus } }, - toggleThreadDisplay(id) { + toggleThreadDisplay (id) { const curStatus = this.threadDisplayStatus[id] const nextStatus = curStatus === 'showing' ? 'hidden' : 'showing' this.setThreadDisplay(id, nextStatus) }, - setThreadDisplayRecursively(id, nextStatus) { + setThreadDisplayRecursively (id, nextStatus) { this.setThreadDisplay(id, nextStatus) - this.getReplies(id) - .map((k) => k.id) - .map((id) => this.setThreadDisplayRecursively(id, nextStatus)) + this.getReplies(id).map(k => k.id).map(id => this.setThreadDisplayRecursively(id, nextStatus)) }, - showThreadRecursively(id) { + showThreadRecursively (id) { this.setThreadDisplayRecursively(id, 'showing') }, - setStatusContentProperty(id, name, value) { + setStatusContentProperty (id, name, value) { this.statusContentPropertiesObject = { ...this.statusContentPropertiesObject, [id]: { ...this.statusContentPropertiesObject[id], - [name]: value, - }, + [name]: value + } } }, - toggleStatusContentProperty(id, name) { - this.setStatusContentProperty( - id, - name, - !this.statusContentProperties[id][name], - ) + toggleStatusContentProperty (id, name) { + this.setStatusContentProperty(id, name, !this.statusContentProperties[id][name]) }, - leastVisibleAncestor(id) { + leastVisibleAncestor (id) { let cur = id let parent = this.parentOf(cur) while (cur) { @@ -535,20 +472,18 @@ const conversation = { // nothing found, fall back to toplevel return this.topLevel[0] ? this.topLevel[0].id : undefined }, - diveIntoStatus(id) { + diveIntoStatus (id) { this.tryScrollTo(id) }, - diveToTopLevel() { - this.tryScrollTo( - this.topLevelAncestorOrSelfId(this.diveRoot) || this.topLevel[0].id, - ) + diveToTopLevel () { + this.tryScrollTo(this.topLevelAncestorOrSelfId(this.diveRoot) || this.topLevel[0].id) }, // only used when we are not on a page - undive() { + undive () { this.inlineDivePosition = null this.setHighlight(this.statusId) }, - tryScrollTo(id) { + tryScrollTo (id) { if (!id) { return } @@ -577,13 +512,13 @@ const conversation = { this.setHighlight(id) }) }, - goToCurrent() { + goToCurrent () { this.tryScrollTo(this.diveRoot || this.topLevel[0].id) }, - statusById(id) { + statusById (id) { return this.statusMap[id] }, - parentOf(id) { + parentOf (id) { const status = this.statusById(id) if (!status) { return undefined @@ -594,11 +529,11 @@ const conversation = { } return parentId }, - parentOrSelf(id) { + parentOrSelf (id) { return this.parentOf(id) || id }, // Ancestors of some status, from top to bottom - ancestorsOf(id) { + ancestorsOf (id) { const ancestors = [] let cur = this.parentOf(id) while (cur) { @@ -607,7 +542,7 @@ const conversation = { } return ancestors }, - topLevelAncestorOrSelfId(id) { + topLevelAncestorOrSelfId (id) { let cur = id let parent = this.parentOf(id) while (parent) { @@ -616,11 +551,11 @@ const conversation = { } return cur }, - resetDisplayState() { + resetDisplayState () { this.undive() this.threadDisplayStatusObject = {} - }, - }, + } + } } export default conversation diff --git a/src/components/desktop_nav/desktop_nav.js b/src/components/desktop_nav/desktop_nav.js index c816a97b1..98d408a7e 100644 --- a/src/components/desktop_nav/desktop_nav.js +++ b/src/components/desktop_nav/desktop_nav.js @@ -1,20 +1,20 @@ +import SearchBar from 'components/search_bar/search_bar.vue' +import ConfirmModal from '../confirm_modal/confirm_modal.vue' import { library } from '@fortawesome/fontawesome-svg-core' import { - faBell, - faBullhorn, - faCog, - faComments, - faHome, - faInfoCircle, - faSearch, faSignInAlt, faSignOutAlt, - faTachometerAlt, + faHome, + faComments, + faBell, faUserPlus, + faBullhorn, + faSearch, + faTachometerAlt, + faCog, + faInfoCircle } from '@fortawesome/free-solid-svg-icons' -import SearchBar from 'components/search_bar/search_bar.vue' import { useInterfaceStore } from 'src/stores/interface' -import ConfirmModal from '../confirm_modal/confirm_modal.vue' library.add( faSignInAlt, @@ -27,109 +27,91 @@ library.add( faSearch, faTachometerAlt, faCog, - faInfoCircle, + faInfoCircle ) export default { components: { SearchBar, - ConfirmModal, + ConfirmModal }, data: () => ({ searchBarHidden: true, - supportsMask: - window.CSS && - window.CSS.supports && - (window.CSS.supports('mask-size', 'contain') || + supportsMask: window.CSS && window.CSS.supports && ( + window.CSS.supports('mask-size', 'contain') || window.CSS.supports('-webkit-mask-size', 'contain') || window.CSS.supports('-moz-mask-size', 'contain') || window.CSS.supports('-ms-mask-size', 'contain') || - window.CSS.supports('-o-mask-size', 'contain')), - showingConfirmLogout: false, + window.CSS.supports('-o-mask-size', 'contain') + ), + showingConfirmLogout: false }), computed: { - enableMask() { - return this.supportsMask && this.$store.state.instance.logoMask - }, - logoStyle() { + enableMask () { return this.supportsMask && this.$store.state.instance.logoMask }, + logoStyle () { return { - visibility: this.enableMask ? 'hidden' : 'visible', + visibility: this.enableMask ? 'hidden' : 'visible' } }, - logoMaskStyle() { + logoMaskStyle () { return this.enableMask ? { - 'mask-image': `url(${this.$store.state.instance.logo})`, + 'mask-image': `url(${this.$store.state.instance.logo})` } : { - 'background-color': this.enableMask ? '' : 'transparent', + 'background-color': this.enableMask ? '' : 'transparent' } }, - logoBgStyle() { - return Object.assign( - { - margin: `${this.$store.state.instance.logoMargin} 0`, - opacity: this.searchBarHidden ? 1 : 0, - }, - this.enableMask - ? {} - : { - 'background-color': this.enableMask ? '' : 'transparent', - }, - ) + logoBgStyle () { + return Object.assign({ + margin: `${this.$store.state.instance.logoMargin} 0`, + opacity: this.searchBarHidden ? 1 : 0 + }, this.enableMask + ? {} + : { + 'background-color': this.enableMask ? '' : 'transparent' + }) }, - logo() { - return this.$store.state.instance.logo - }, - sitename() { - return this.$store.state.instance.name - }, - hideSitename() { - return this.$store.state.instance.hideSitename - }, - logoLeft() { - return this.$store.state.instance.logoLeft - }, - currentUser() { - return this.$store.state.users.currentUser - }, - privateMode() { - return this.$store.state.instance.private - }, - shouldConfirmLogout() { + logo () { return this.$store.state.instance.logo }, + sitename () { return this.$store.state.instance.name }, + hideSitename () { return this.$store.state.instance.hideSitename }, + logoLeft () { return this.$store.state.instance.logoLeft }, + currentUser () { return this.$store.state.users.currentUser }, + privateMode () { return this.$store.state.instance.private }, + shouldConfirmLogout () { return this.$store.getters.mergedConfig.modalOnLogout - }, + } }, methods: { - scrollToTop() { + scrollToTop () { window.scrollTo(0, 0) }, - showConfirmLogout() { + showConfirmLogout () { this.showingConfirmLogout = true }, - hideConfirmLogout() { + hideConfirmLogout () { this.showingConfirmLogout = false }, - logout() { + logout () { if (!this.shouldConfirmLogout) { this.doLogout() } else { this.showConfirmLogout() } }, - doLogout() { + doLogout () { this.$router.replace('/main/public') this.$store.dispatch('logout') this.hideConfirmLogout() }, - onSearchBarToggled(hidden) { + onSearchBarToggled (hidden) { this.searchBarHidden = hidden }, - openSettingsModal() { + openSettingsModal () { useInterfaceStore().openSettingsModal('user') }, - openAdminModal() { + openAdminModal () { useInterfaceStore().openSettingsModal('admin') - }, - }, + } + } } diff --git a/src/components/dialog_modal/dialog_modal.js b/src/components/dialog_modal/dialog_modal.js index 8070d3429..b39851fe7 100644 --- a/src/components/dialog_modal/dialog_modal.js +++ b/src/components/dialog_modal/dialog_modal.js @@ -2,20 +2,18 @@ const DialogModal = { props: { darkOverlay: { default: true, - type: Boolean, + type: Boolean }, onCancel: { - default: () => { - /* no-op */ - }, - type: Function, - }, + default: () => {}, + type: Function + } }, computed: { - mobileCenter() { + mobileCenter () { return this.$store.getters.mergedConfig.modalMobileCenter - }, - }, + } + } } export default DialogModal diff --git a/src/components/dm_timeline/dm_timeline.js b/src/components/dm_timeline/dm_timeline.js index c977efe30..8b5393a98 100644 --- a/src/components/dm_timeline/dm_timeline.js +++ b/src/components/dm_timeline/dm_timeline.js @@ -2,13 +2,13 @@ import Timeline from '../timeline/timeline.vue' const DMs = { computed: { - timeline() { + timeline () { return this.$store.state.statuses.timelines.dms - }, + } }, components: { - Timeline, - }, + Timeline + } } export default DMs diff --git a/src/components/domain_mute_card/domain_mute_card.js b/src/components/domain_mute_card/domain_mute_card.js index 71da2684c..f234dcb0f 100644 --- a/src/components/domain_mute_card/domain_mute_card.js +++ b/src/components/domain_mute_card/domain_mute_card.js @@ -3,24 +3,24 @@ import ProgressButton from '../progress_button/progress_button.vue' const DomainMuteCard = { props: ['domain'], components: { - ProgressButton, + ProgressButton }, computed: { - user() { + user () { return this.$store.state.users.currentUser }, - muted() { + muted () { return this.user.domainMutes.includes(this.domain) - }, + } }, methods: { - unmuteDomain() { + unmuteDomain () { return this.$store.dispatch('unmuteDomain', this.domain) }, - muteDomain() { + muteDomain () { return this.$store.dispatch('muteDomain', this.domain) - }, - }, + } + } } export default DomainMuteCard diff --git a/src/components/draft/draft.js b/src/components/draft/draft.js index 2a2485b58..55ee11a15 100644 --- a/src/components/draft/draft.js +++ b/src/components/draft/draft.js @@ -1,13 +1,18 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faPollH } from '@fortawesome/free-solid-svg-icons' -import { cloneDeep } from 'lodash' -import ConfirmModal from 'src/components/confirm_modal/confirm_modal.vue' -import EditStatusForm from 'src/components/edit_status_form/edit_status_form.vue' -import Gallery from 'src/components/gallery/gallery.vue' import PostStatusForm from 'src/components/post_status_form/post_status_form.vue' +import EditStatusForm from 'src/components/edit_status_form/edit_status_form.vue' +import ConfirmModal from 'src/components/confirm_modal/confirm_modal.vue' import StatusContent from 'src/components/status_content/status_content.vue' +import Gallery from 'src/components/gallery/gallery.vue' +import { cloneDeep } from 'lodash' -library.add(faPollH) +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faPollH +} from '@fortawesome/free-solid-svg-icons' + +library.add( + faPollH +) const Draft = { components: { @@ -15,23 +20,23 @@ const Draft = { EditStatusForm, ConfirmModal, StatusContent, - Gallery, + Gallery }, props: { draft: { type: Object, - required: true, - }, + required: true + } }, - data() { + data () { return { referenceDraft: cloneDeep(this.draft), editing: false, - showingConfirmDialog: false, + showingConfirmDialog: false } }, computed: { - relAttrs() { + relAttrs () { if (this.draft.type === 'edit') { return { statusId: this.draft.refId } } else if (this.draft.type === 'reply') { @@ -40,24 +45,24 @@ const Draft = { return {} } }, - safeToSave() { - return this.draft.status || this.draft.files?.length || this.draft.hasPoll + safeToSave () { + return this.draft.status || + this.draft.files?.length || + this.draft.hasPoll }, - postStatusFormProps() { + postStatusFormProps () { return { draftId: this.draft.id, - ...this.relAttrs, + ...this.relAttrs } }, - refStatus() { - return this.draft.refId - ? this.$store.state.statuses.allStatusesObject[this.draft.refId] - : undefined + refStatus () { + return this.draft.refId ? this.$store.state.statuses.allStatusesObject[this.draft.refId] : undefined }, - localCollapseSubjectDefault() { + localCollapseSubjectDefault () { return this.$store.getters.mergedConfig.collapseMessageWithSubject }, - nsfwClickthrough() { + nsfwClickthrough () { if (!this.draft.nsfw) { return false } @@ -65,34 +70,35 @@ const Draft = { return false } return true - }, + } }, watch: { - editing(newVal) { + editing (newVal) { if (newVal) return if (this.safeToSave) { this.$store.dispatch('addOrSaveDraft', { draft: this.draft }) } else { this.$store.dispatch('addOrSaveDraft', { draft: this.referenceDraft }) } - }, + } }, methods: { - toggleEditing() { + toggleEditing () { this.editing = !this.editing }, - abandon() { + abandon () { this.showingConfirmDialog = true }, - doAbandon() { - this.$store.dispatch('abandonDraft', { id: this.draft.id }).then(() => { - this.hideConfirmDialog() - }) + doAbandon () { + this.$store.dispatch('abandonDraft', { id: this.draft.id }) + .then(() => { + this.hideConfirmDialog() + }) }, - hideConfirmDialog() { + hideConfirmDialog () { this.showingConfirmDialog = false - }, - }, + } + } } export default Draft diff --git a/src/components/draft_closer/draft_closer.js b/src/components/draft_closer/draft_closer.js index d724ab4ac..e50ea05ab 100644 --- a/src/components/draft_closer/draft_closer.js +++ b/src/components/draft_closer/draft_closer.js @@ -1,29 +1,32 @@ import DialogModal from 'src/components/dialog_modal/dialog_modal.vue' const DraftCloser = { - data() { + data () { return { - showing: false, + showing: false } }, components: { - DialogModal, + DialogModal }, - emits: ['save', 'discard'], + emits: [ + 'save', + 'discard' + ], computed: { - action() { + action () { if (this.$store.getters.mergedConfig.autoSaveDraft) { return 'save' } else { return this.$store.getters.mergedConfig.unsavedPostAction } }, - shouldConfirm() { + shouldConfirm () { return this.action === 'confirm' - }, + } }, methods: { - requestClose() { + requestClose () { if (this.shouldConfirm) { this.showing = true } else if (this.action === 'save') { @@ -32,18 +35,18 @@ const DraftCloser = { this.discard() } }, - save() { + save () { this.$emit('save') this.showing = false }, - discard() { + discard () { this.$emit('discard') this.showing = false }, - cancel() { + cancel () { this.showing = false - }, - }, + } + } } export default DraftCloser diff --git a/src/components/drafts/drafts.js b/src/components/drafts/drafts.js index 8acde3c17..201417f66 100644 --- a/src/components/drafts/drafts.js +++ b/src/components/drafts/drafts.js @@ -4,13 +4,13 @@ import List from 'src/components/list/list.vue' const Drafts = { components: { Draft, - List, + List }, computed: { - drafts() { + drafts () { return this.$store.getters.draftsArray - }, - }, + } + } } export default Drafts diff --git a/src/components/edit_status_form/edit_status_form.js b/src/components/edit_status_form/edit_status_form.js index b8df92794..323763370 100644 --- a/src/components/edit_status_form/edit_status_form.js +++ b/src/components/edit_status_form/edit_status_form.js @@ -1,21 +1,21 @@ -import statusPosterService from '../../services/status_poster/status_poster.service.js' import PostStatusForm from '../post_status_form/post_status_form.vue' +import statusPosterService from '../../services/status_poster/status_poster.service.js' const EditStatusForm = { components: { - PostStatusForm, + PostStatusForm }, props: { params: { type: Object, - required: true, - }, + required: true + } }, methods: { - requestClose() { + requestClose () { this.$refs.postStatusForm.requestClose() }, - doEditStatus({ status, spoilerText, sensitive, media, contentType, poll }) { + doEditStatus ({ status, spoilerText, sensitive, media, contentType, poll }) { const params = { store: this.$store, statusId: this.params.statusId, @@ -24,22 +24,21 @@ const EditStatusForm = { sensitive, poll, media, - contentType, + contentType } - return statusPosterService - .editStatus(params) + return statusPosterService.editStatus(params) .then((data) => { return data }) .catch((err) => { console.error('Error editing status', err) return { - error: err.message, + error: err.message } }) - }, - }, + } + } } export default EditStatusForm diff --git a/src/components/edit_status_modal/edit_status_modal.js b/src/components/edit_status_modal/edit_status_modal.js index 022055e47..4c10c21a0 100644 --- a/src/components/edit_status_modal/edit_status_modal.js +++ b/src/components/edit_status_modal/edit_status_modal.js @@ -1,34 +1,34 @@ -import get from 'lodash/get' -import { useEditStatusStore } from 'src/stores/editStatus' import EditStatusForm from '../edit_status_form/edit_status_form.vue' import Modal from '../modal/modal.vue' +import get from 'lodash/get' +import { useEditStatusStore } from 'src/stores/editStatus' const EditStatusModal = { components: { EditStatusForm, - Modal, + Modal }, - data() { + data () { return { - resettingForm: false, + resettingForm: false } }, computed: { - isLoggedIn() { + isLoggedIn () { return !!this.$store.state.users.currentUser }, - modalActivated() { + modalActivated () { return useEditStatusStore().modalActivated }, - isFormVisible() { + isFormVisible () { return this.isLoggedIn && !this.resettingForm && this.modalActivated }, - params() { + params () { return useEditStatusStore().params || {} - }, + } }, watch: { - params(newVal, oldVal) { + params (newVal, oldVal) { if (get(newVal, 'statusId') !== get(oldVal, 'statusId')) { this.resettingForm = true this.$nextTick(() => { @@ -36,22 +36,20 @@ const EditStatusModal = { }) } }, - isFormVisible(val) { + isFormVisible (val) { if (val) { - this.$nextTick( - () => this.$el && this.$el.querySelector('textarea').focus(), - ) + this.$nextTick(() => this.$el && this.$el.querySelector('textarea').focus()) } - }, + } }, methods: { - closeModal() { + closeModal () { this.$refs.editStatusForm.requestClose() }, - doCloseModal() { + doCloseModal () { useEditStatusStore().closeEditStatusModal() - }, - }, + } + } } export default EditStatusModal diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js index 49470bec9..f6ba6e245 100644 --- a/src/components/emoji_input/emoji_input.js +++ b/src/components/emoji_input/emoji_input.js @@ -1,16 +1,20 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faSmileBeam } from '@fortawesome/free-regular-svg-icons' -import { take } from 'lodash' -import Popover from 'src/components/popover/popover.vue' -import ScreenReaderNotice from 'src/components/screen_reader_notice/screen_reader_notice.vue' -import { ensureFinalFallback } from '../../i18n/languages.js' import Completion from '../../services/completion/completion.js' -import { findOffset } from '../../services/offset_finder/offset_finder.service.js' import genRandomSeed from '../../services/random_seed/random_seed.service.js' import EmojiPicker from '../emoji_picker/emoji_picker.vue' +import Popover from 'src/components/popover/popover.vue' +import ScreenReaderNotice from 'src/components/screen_reader_notice/screen_reader_notice.vue' import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue' +import { take } from 'lodash' +import { findOffset } from '../../services/offset_finder/offset_finder.service.js' +import { ensureFinalFallback } from '../../i18n/languages.js' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faSmileBeam +} from '@fortawesome/free-regular-svg-icons' -library.add(faSmileBeam) +library.add( + faSmileBeam +) /** * EmojiInput - augmented inputs for emoji and autocomplete support in inputs @@ -56,14 +60,14 @@ const EmojiInput = { * For commonly used suggestors (emoji, users, both) use suggestor.js */ required: true, - type: Function, + type: Function }, modelValue: { /** * Used for v-model */ required: true, - type: String, + type: String }, enableEmojiPicker: { /** @@ -71,7 +75,7 @@ const EmojiInput = { */ required: false, type: Boolean, - default: false, + default: false }, hideEmojiButton: { /** @@ -80,7 +84,7 @@ const EmojiInput = { */ required: false, type: Boolean, - default: false, + default: false }, enableStickerPicker: { /** @@ -88,7 +92,7 @@ const EmojiInput = { */ required: false, type: Boolean, - default: false, + default: false }, placement: { /** @@ -97,15 +101,15 @@ const EmojiInput = { */ required: false, type: String, // 'auto', 'top', 'bottom' - default: 'auto', + default: 'auto' }, newlineOnCtrlEnter: { required: false, type: Boolean, - default: false, - }, + default: false + } }, - data() { + data () { return { randomSeed: genRandomSeed(), input: undefined, @@ -118,65 +122,58 @@ const EmojiInput = { disableClickOutside: false, suggestions: [], overlayStyle: {}, - pickerShown: false, + pickerShown: false } }, components: { Popover, EmojiPicker, UnicodeDomainIndicator, - ScreenReaderNotice, + ScreenReaderNotice }, computed: { - padEmoji() { + padEmoji () { return this.$store.getters.mergedConfig.padEmoji }, - defaultCandidateIndex() { + defaultCandidateIndex () { return this.$store.getters.mergedConfig.autocompleteSelect ? 0 : -1 }, - preText() { + preText () { return this.modelValue.slice(0, this.caret) }, - postText() { + postText () { return this.modelValue.slice(this.caret) }, - showSuggestions() { - return ( - this.focused && + showSuggestions () { + return this.focused && this.suggestions && this.suggestions.length > 0 && !this.pickerShown && !this.temporarilyHideSuggestions - ) }, - textAtCaret() { + textAtCaret () { return this.wordAtCaret?.word }, - wordAtCaret() { + wordAtCaret () { if (this.modelValue && this.caret) { - const word = - Completion.wordAtPosition(this.modelValue, this.caret - 1) || {} + const word = Completion.wordAtPosition(this.modelValue, this.caret - 1) || {} return word } }, - languages() { - return ensureFinalFallback( - this.$store.getters.mergedConfig.interfaceLanguage, - ) + languages () { + return ensureFinalFallback(this.$store.getters.mergedConfig.interfaceLanguage) }, - maybeLocalizedEmojiNamesAndKeywords() { - return (emoji) => { + maybeLocalizedEmojiNamesAndKeywords () { + return emoji => { const names = [emoji.displayText] const keywords = [] if (emoji.displayTextI18n) { - names.push( - this.$t(emoji.displayTextI18n.key, emoji.displayTextI18n.args), - ) + names.push(this.$t(emoji.displayTextI18n.key, emoji.displayTextI18n.args)) } if (emoji.annotations) { - this.languages.forEach((lang) => { + this.languages.forEach(lang => { names.push(emoji.annotations[lang]?.name) keywords.push(...(emoji.annotations[lang]?.keywords || [])) @@ -184,13 +181,13 @@ const EmojiInput = { } return { - names: names.filter((k) => k), - keywords: keywords.filter((k) => k), + names: names.filter(k => k), + keywords: keywords.filter(k => k) } } }, - maybeLocalizedEmojiName() { - return (emoji) => { + maybeLocalizedEmojiName () { + return emoji => { if (!emoji.annotations) { return emoji.displayText } @@ -208,18 +205,16 @@ const EmojiInput = { return emoji.displayText } }, - suggestionListId() { + suggestionListId () { return `suggestions-${this.randomSeed}` }, - suggestionItemId() { + suggestionItemId () { return (index) => `suggestion-item-${index}-${this.randomSeed}` - }, + } }, - mounted() { + mounted () { const { root, hiddenOverlayCaret, suggestorPopover } = this.$refs - const input = - root.querySelector('.emoji-input > input') || - root.querySelector('.emoji-input > textarea') + const input = root.querySelector('.emoji-input > input') || root.querySelector('.emoji-input > textarea') if (!input) return this.input = input this.caretEl = hiddenOverlayCaret @@ -248,7 +243,7 @@ const EmojiInput = { input.addEventListener('input', this.onInput) input.addEventListener('scroll', this.onInputScroll) }, - unmounted() { + unmounted () { const { input } = this if (input) { input.removeEventListener('blur', this.onBlur) @@ -278,40 +273,36 @@ const EmojiInput = { this.suggestions = [] return } - const matchedSuggestions = await this.suggest( - newWord, - this.maybeLocalizedEmojiNamesAndKeywords, - ) + const matchedSuggestions = await this.suggest(newWord, this.maybeLocalizedEmojiNamesAndKeywords) // Async: cancel if textAtCaret has changed during wait if (this.textAtCaret !== newWord || matchedSuggestions.length <= 0) { this.suggestions = [] return } - this.suggestions = take(matchedSuggestions, 5).map( - ({ imageUrl, ...rest }) => ({ + this.suggestions = take(matchedSuggestions, 5) + .map(({ imageUrl, ...rest }) => ({ ...rest, - img: imageUrl || '', - }), - ) + img: imageUrl || '' + })) this.highlighted = this.defaultCandidateIndex this.$refs.screenReaderNotice.announce( this.$t( 'tool_tip.autocomplete_available', { number: this.suggestions.length }, - this.suggestions.length, - ), + this.suggestions.length + ) ) - }, + } }, methods: { - onInputScroll(e) { + onInputScroll (e) { this.$refs.hiddenOverlay.scrollTo({ top: this.input.scrollTop, - left: this.input.scrollLeft, + left: this.input.scrollLeft }) this.setCaret(e) }, - triggerShowPicker() { + triggerShowPicker () { this.$nextTick(() => { this.$refs.picker.showPicker() this.scrollIntoView() @@ -324,7 +315,7 @@ const EmojiInput = { this.disableClickOutside = false }, 0) }, - togglePicker() { + togglePicker () { this.input.focus() if (!this.pickerShown) { this.scrollIntoView() @@ -334,16 +325,12 @@ const EmojiInput = { this.$refs.picker.hidePicker() } }, - replace(replacement) { - const newValue = Completion.replaceWord( - this.modelValue, - this.wordAtCaret, - replacement, - ) + replace (replacement) { + const newValue = Completion.replaceWord(this.modelValue, this.wordAtCaret, replacement) this.$emit('update:modelValue', newValue) this.caret = 0 }, - insert({ insertion, keepOpen, surroundingSpace = true }) { + insert ({ insertion, keepOpen, surroundingSpace = true }) { const before = this.modelValue.substring(0, this.caret) || '' const after = this.modelValue.substring(this.caret) || '' @@ -362,24 +349,18 @@ const EmojiInput = { * them, masto seem to be rendering :emoji::emoji: correctly now so why not */ const isSpaceRegex = /\s/ - const spaceBefore = - surroundingSpace && - !isSpaceRegex.exec(before.slice(-1)) && - before.length && - this.padEmoji > 0 - ? ' ' - : '' - const spaceAfter = - surroundingSpace && !isSpaceRegex.exec(after[0]) && this.padEmoji - ? ' ' - : '' + const spaceBefore = (surroundingSpace && !isSpaceRegex.exec(before.slice(-1)) && before.length && this.padEmoji > 0) ? ' ' : '' + const spaceAfter = (surroundingSpace && !isSpaceRegex.exec(after[0]) && this.padEmoji) ? ' ' : '' - const newValue = [before, spaceBefore, insertion, spaceAfter, after].join( - '', - ) + const newValue = [ + before, + spaceBefore, + insertion, + spaceAfter, + after + ].join('') this.$emit('update:modelValue', newValue) - const position = - this.caret + (insertion + spaceAfter + spaceBefore).length + const position = this.caret + (insertion + spaceAfter + spaceBefore).length if (!keepOpen) { this.input.focus() } @@ -391,20 +372,13 @@ const EmojiInput = { this.caret = position }) }, - replaceText(e, suggestion) { + replaceText (e, suggestion) { const len = this.suggestions.length || 0 - if (this.textAtCaret.length === 1) { - return - } + if (this.textAtCaret.length === 1) { return } if (len > 0 || suggestion) { - const chosenSuggestion = - suggestion || this.suggestions[this.highlighted] + const chosenSuggestion = suggestion || this.suggestions[this.highlighted] const replacement = chosenSuggestion.replacement - const newValue = Completion.replaceWord( - this.modelValue, - this.wordAtCaret, - replacement, - ) + const newValue = Completion.replaceWord(this.modelValue, this.wordAtCaret, replacement) this.$emit('update:modelValue', newValue) this.highlighted = 0 const position = this.wordAtCaret.start + replacement.length @@ -419,7 +393,7 @@ const EmojiInput = { e.preventDefault() } }, - cycleBackward(e) { + cycleBackward (e) { const len = this.suggestions.length || 0 this.highlighted -= 1 @@ -432,7 +406,7 @@ const EmojiInput = { e.preventDefault() } }, - cycleForward(e) { + cycleForward (e) { const len = this.suggestions.length || 0 this.highlighted += 1 @@ -444,28 +418,26 @@ const EmojiInput = { e.preventDefault() } }, - scrollIntoView() { + scrollIntoView () { const rootRef = this.$refs.picker.$el /* Scroller is either `window` (replies in TL), sidebar (main post form, * replies in notifs) or mobile post form. Note that getting and setting * scroll is different for `Window` and `Element`s */ - const scrollerRef = - this.$el.closest('.sidebar-scroller') || - this.$el.closest('.post-form-modal-view') || - window - const currentScroll = - scrollerRef === window ? scrollerRef.scrollY : scrollerRef.scrollTop - const scrollerHeight = - scrollerRef === window - ? scrollerRef.innerHeight - : scrollerRef.offsetHeight + const scrollerRef = this.$el.closest('.sidebar-scroller') || + this.$el.closest('.post-form-modal-view') || + window + const currentScroll = scrollerRef === window + ? scrollerRef.scrollY + : scrollerRef.scrollTop + const scrollerHeight = scrollerRef === window + ? scrollerRef.innerHeight + : scrollerRef.offsetHeight const scrollerBottomBorder = currentScroll + scrollerHeight // We check where the bottom border of root element is, this uses findOffset // to find offset relative to scrollable container (scroller) - const rootBottomBorder = - rootRef.offsetHeight + findOffset(rootRef, scrollerRef).top + const rootBottomBorder = rootRef.offsetHeight + findOffset(rootRef, scrollerRef).top const bottomDelta = Math.max(0, rootBottomBorder - scrollerBottomBorder) // could also check top delta but there's no case for it @@ -487,13 +459,13 @@ const EmojiInput = { } }) }, - onPickerShown() { + onPickerShown () { this.pickerShown = true }, - onPickerClosed() { + onPickerClosed () { this.pickerShown = false }, - onBlur(e) { + onBlur (e) { // Clicking on any suggestion removes focus from autocomplete, // preventing click handler ever executing. this.blurTimeout = setTimeout(() => { @@ -501,10 +473,10 @@ const EmojiInput = { this.setCaret(e) }, 200) }, - onClick(e, suggestion) { + onClick (e, suggestion) { this.replaceText(e, suggestion) }, - onFocus(e) { + onFocus (e) { if (this.blurTimeout) { clearTimeout(this.blurTimeout) this.blurTimeout = null @@ -514,7 +486,7 @@ const EmojiInput = { this.setCaret(e) this.temporarilyHideSuggestions = false }, - onKeyUp(e) { + onKeyUp (e) { const { key } = e this.setCaret(e) @@ -526,10 +498,10 @@ const EmojiInput = { this.temporarilyHideSuggestions = false } }, - onPaste(e) { + onPaste (e) { this.setCaret(e) }, - onKeyDown(e) { + onKeyDown (e) { const { ctrlKey, shiftKey, key } = e if (this.newlineOnCtrlEnter && ctrlKey && key === 'Enter') { this.insert({ insertion: '\n', surroundingSpace: false }) @@ -573,30 +545,30 @@ const EmojiInput = { } } }, - onInput(e) { + onInput (e) { this.setCaret(e) this.$emit('update:modelValue', e.target.value) }, - onStickerUploaded(e) { + onStickerUploaded (e) { this.$emit('sticker-uploaded', e) }, - onStickerUploadFailed(e) { + onStickerUploadFailed (e) { this.$emit('sticker-upload-Failed', e) }, - setCaret({ target: { selectionStart } }) { + setCaret ({ target: { selectionStart } }) { this.caret = selectionStart this.$nextTick(() => { this.$refs.suggestorPopover.updateStyles() }) }, - autoCompleteItemLabel(suggestion) { + autoCompleteItemLabel (suggestion) { if (suggestion.user) { return suggestion.displayText + ' ' + suggestion.detailText } else { return this.maybeLocalizedEmojiName(suggestion) } - }, - }, + } + } } export default EmojiInput diff --git a/src/components/emoji_input/suggestor.js b/src/components/emoji_input/suggestor.js index 79d97cff7..f2daf2f46 100644 --- a/src/components/emoji_input/suggestor.js +++ b/src/components/emoji_input/suggestor.js @@ -10,7 +10,7 @@ * doesn't support user linking you can just provide only emoji. */ -export default (data) => { +export default data => { const emojiCurry = suggestEmoji(data.emoji) const usersCurry = data.store && suggestUsers(data.store) return (input, nameKeywordLocalizer) => { @@ -25,35 +25,22 @@ export default (data) => { } } -export const suggestEmoji = (emojis) => (input, nameKeywordLocalizer) => { +export const suggestEmoji = emojis => (input, nameKeywordLocalizer) => { const noPrefix = input.toLowerCase().substr(1) return emojis - .map((emoji) => ({ ...emoji, ...nameKeywordLocalizer(emoji) })) - .filter( - (emoji) => - emoji.names - .concat(emoji.keywords) - .filter((kw) => kw.toLowerCase().match(noPrefix)).length, - ) - .map((k) => { + .map(emoji => ({ ...emoji, ...nameKeywordLocalizer(emoji) })) + .filter((emoji) => (emoji.names.concat(emoji.keywords)).filter(kw => kw.toLowerCase().match(noPrefix)).length) + .map(k => { let score = 0 // An exact match always wins - score += Math.max( - ...k.names.map((name) => (name.toLowerCase() === noPrefix ? 200 : 0)), - 0, - ) + score += Math.max(...k.names.map(name => name.toLowerCase() === noPrefix ? 200 : 0), 0) // Prioritize custom emoji a lot score += k.imageUrl ? 100 : 0 // Prioritize prefix matches somewhat - score += Math.max( - ...k.names.map((kw) => - kw.toLowerCase().startsWith(noPrefix) ? 10 : 0, - ), - 0, - ) + score += Math.max(...k.names.map(kw => kw.toLowerCase().startsWith(noPrefix) ? 10 : 0), 0) // Sort by length score -= k.displayText.length @@ -91,7 +78,7 @@ export const suggestUsers = ({ dispatch, state }) => { }) } - return async (input) => { + return async input => { const noPrefix = input.toLowerCase().substr(1) if (previousQuery === noPrefix) return suggestions @@ -105,42 +92,37 @@ export const suggestUsers = ({ dispatch, state }) => { await debounceUserSearch(noPrefix) } - const newSuggestions = state.users.users - .filter( - (user) => - user.screen_name && - user.name && - (user.screen_name.toLowerCase().startsWith(noPrefix) || - user.name.toLowerCase().startsWith(noPrefix)), - ) - .slice(0, 20) - .sort((a, b) => { - let aScore = 0 - let bScore = 0 + const newSuggestions = state.users.users.filter( + user => + user.screen_name && user.name && ( + user.screen_name.toLowerCase().startsWith(noPrefix) || + user.name.toLowerCase().startsWith(noPrefix)) + ).slice(0, 20).sort((a, b) => { + let aScore = 0 + let bScore = 0 - // Matches on screen name (i.e. user@instance) makes a priority - aScore += a.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0 - bScore += b.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0 + // Matches on screen name (i.e. user@instance) makes a priority + aScore += a.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0 + bScore += b.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0 - // Matches on name takes second priority - aScore += a.name.toLowerCase().startsWith(noPrefix) ? 1 : 0 - bScore += b.name.toLowerCase().startsWith(noPrefix) ? 1 : 0 + // Matches on name takes second priority + aScore += a.name.toLowerCase().startsWith(noPrefix) ? 1 : 0 + bScore += b.name.toLowerCase().startsWith(noPrefix) ? 1 : 0 - const diff = (bScore - aScore) * 10 + const diff = (bScore - aScore) * 10 - // Then sort alphabetically - const nameAlphabetically = a.name > b.name ? 1 : -1 - const screenNameAlphabetically = a.screen_name > b.screen_name ? 1 : -1 + // Then sort alphabetically + const nameAlphabetically = a.name > b.name ? 1 : -1 + const screenNameAlphabetically = a.screen_name > b.screen_name ? 1 : -1 - return diff + nameAlphabetically + screenNameAlphabetically - }) - .map((user) => ({ - user, - displayText: user.screen_name_ui, - detailText: user.name, - imageUrl: user.profile_image_url_original, - replacement: '@' + user.screen_name + ' ', - })) + return diff + nameAlphabetically + screenNameAlphabetically + }).map((user) => ({ + user, + displayText: user.screen_name_ui, + detailText: user.name, + imageUrl: user.profile_image_url_original, + replacement: '@' + user.screen_name + ' ' + })) suggestions = newSuggestions || [] return suggestions diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index 80920a128..8e572d1d2 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -1,24 +1,24 @@ +import { defineAsyncComponent } from 'vue' +import Checkbox from '../checkbox/checkbox.vue' +import Popover from 'src/components/popover/popover.vue' +import StillImage from '../still-image/still-image.vue' +import { ensureFinalFallback } from '../../i18n/languages.js' import { library } from '@fortawesome/fontawesome-svg-core' import { - faBasketballBall, faBoxOpen, - faBus, - faCode, - faFlag, - faIceCream, - faLightbulb, - faPaw, - faSmile, - faSmileBeam, faStickyNote, + faSmileBeam, + faSmile, faUser, + faPaw, + faIceCream, + faBus, + faBasketballBall, + faLightbulb, + faCode, + faFlag } from '@fortawesome/free-solid-svg-icons' -import { chunk, debounce, trim } from 'lodash' -import Popover from 'src/components/popover/popover.vue' -import { defineAsyncComponent } from 'vue' -import { ensureFinalFallback } from '../../i18n/languages.js' -import Checkbox from '../checkbox/checkbox.vue' -import StillImage from '../still-image/still-image.vue' +import { debounce, trim, chunk } from 'lodash' library.add( faBoxOpen, @@ -32,7 +32,7 @@ library.add( faBasketballBall, faLightbulb, faCode, - faFlag, + faFlag ) const UNICODE_EMOJI_GROUP_ICON = { @@ -44,16 +44,16 @@ const UNICODE_EMOJI_GROUP_ICON = { activities: 'basketball-ball', objects: 'lightbulb', symbols: 'code', - flags: 'flag', + flags: 'flag' } const maybeLocalizedKeywords = (emoji, languages, nameLocalizer) => { const res = [emoji.displayText, nameLocalizer(emoji)] if (emoji.annotations) { - languages.forEach((lang) => { + languages.forEach(lang => { const keywords = emoji.annotations[lang]?.keywords || [] const name = emoji.annotations[lang]?.name - res.push(...keywords.concat([name]).filter((k) => k)) + res.push(...(keywords.concat([name]).filter(k => k))) }) } return res @@ -66,8 +66,8 @@ const filterByKeyword = (list, keyword = '', languages, nameLocalizer) => { const orderedEmojiList = [] for (const emoji of list) { const indices = maybeLocalizedKeywords(emoji, languages, nameLocalizer) - .map((k) => k.toLowerCase().indexOf(keywordLowercase)) - .filter((k) => k > -1) + .map(k => k.toLowerCase().indexOf(keywordLowercase)) + .filter(k => k > -1) const indexOfKeyword = indices.length ? Math.min(...indices) : -1 @@ -84,13 +84,11 @@ const filterByKeyword = (list, keyword = '', languages, nameLocalizer) => { const getOffset = (elem) => { const style = elem.style.transform const res = /translateY\((\d+)px\)/.exec(style) - if (!res) { - return 0 - } + if (!res) { return 0 } return res[1] } -const toHeaderId = (id) => { +const toHeaderId = id => { return id.replace(/^row-\d+-/, '') } @@ -99,20 +97,20 @@ const EmojiPicker = { enableStickerPicker: { required: false, type: Boolean, - default: true, + default: true }, hideCustomEmoji: { required: false, type: Boolean, - default: false, - }, + default: false + } }, inject: { popoversZLayer: { - default: '', - }, + default: '' + } }, - data() { + data () { return { keyword: '', activeGroup: 'custom', @@ -127,22 +125,20 @@ const EmojiPicker = { emojiRefs: {}, filteredEmojiGroups: [], emojiSize: 0, - width: 0, + width: 0 } }, components: { - StickerPicker: defineAsyncComponent( - () => import('../sticker_picker/sticker_picker.vue'), - ), + StickerPicker: defineAsyncComponent(() => import('../sticker_picker/sticker_picker.vue')), Checkbox, StillImage, - Popover, + Popover }, methods: { - groupScroll(e) { + groupScroll (e) { e.currentTarget.scrollLeft += e.deltaY + e.deltaX }, - updateEmojiSize() { + updateEmojiSize () { const css = window.getComputedStyle(this.$refs.popover.$el) const fontSize = css.getPropertyValue('font-size') || '1rem' const emojiSize = css.getPropertyValue('--emojiSize') || '2.2rem' @@ -167,68 +163,56 @@ const EmojiPicker = { emojiSizeReal = emojiSizeValue } - const fullEmojiSize = emojiSizeReal + 2 * 0.2 * fontSizeMultiplier * 14 + const fullEmojiSize = emojiSizeReal + (2 * 0.2 * fontSizeMultiplier * 14) this.emojiSize = fullEmojiSize }, - showPicker() { + showPicker () { this.$refs.popover.showPopover() this.$nextTick(() => { this.onShowing() }) }, - hidePicker() { + hidePicker () { this.$refs.popover.hidePopover() }, - setAnchorEl(el) { + setAnchorEl (el) { this.$refs.popover.setAnchorEl(el) }, - setGroupRef(name) { - return (el) => { - this.groupRefs[name] = el - } + setGroupRef (name) { + return el => { this.groupRefs[name] = el } }, - onPopoverShown() { + onPopoverShown () { this.$emit('show') }, - onPopoverClosed() { + onPopoverClosed () { this.$emit('close') }, - onStickerUploaded(e) { + onStickerUploaded (e) { this.$emit('sticker-uploaded', e) }, - onStickerUploadFailed(e) { + onStickerUploadFailed (e) { this.$emit('sticker-upload-failed', e) }, - onEmoji(emoji) { - const value = emoji.imageUrl - ? `:${emoji.displayText}:` - : emoji.replacement + onEmoji (emoji) { + const value = emoji.imageUrl ? `:${emoji.displayText}:` : emoji.replacement if (!this.keepOpen) { this.$refs.popover.hidePopover() } - this.$emit('emoji', { - insertion: value, - insertionUrl: emoji.imageUrl, - keepOpen: this.keepOpen, - }) + this.$emit('emoji', { insertion: value, insertionUrl: emoji.imageUrl, keepOpen: this.keepOpen }) }, - onScroll(startIndex, endIndex, visibleStartIndex, visibleEndIndex) { + onScroll (startIndex, endIndex, visibleStartIndex, visibleEndIndex) { const target = this.$refs['emoji-groups'].$el this.scrolledGroup(target, visibleStartIndex, visibleEndIndex) }, - scrolledGroup(target, start, end) { + scrolledGroup (target, start, end) { const top = target.scrollTop + 5 this.$nextTick(() => { - this.emojiItems.slice(start, end + 1).forEach((group) => { + this.emojiItems.slice(start, end + 1).forEach(group => { const headerId = toHeaderId(group.id) const ref = this.groupRefs['group-' + group.id] - if (!ref) { - return - } + if (!ref) { return } const elem = ref.$el.parentElement - if (!elem) { - return - } + if (!elem) { return } if (elem && getOffset(elem) <= top) { this.activeGroup = headerId } @@ -236,7 +220,7 @@ const EmojiPicker = { this.scrollHeader() }) }, - scrollHeader() { + scrollHeader () { // Scroll the active tab's header into view const headerRef = this.groupRefs['group-header-' + this.activeGroup] const left = headerRef.offsetLeft @@ -244,9 +228,7 @@ const EmojiPicker = { const headerCont = this.$refs.header const currentScroll = headerCont.scrollLeft const currentScrollRight = currentScroll + headerCont.clientWidth - const setScroll = (s) => { - headerCont.scrollLeft = s - } + const setScroll = s => { headerCont.scrollLeft = s } const margin = 7 // .emoji-tabs-item: padding if (left - margin < currentScroll) { @@ -255,12 +237,12 @@ const EmojiPicker = { setScroll(right + margin - headerCont.clientWidth) } }, - highlight(groupId) { + highlight (groupId) { this.setShowStickers(false) - const indexInList = this.emojiItems.findIndex((k) => k.id === groupId) + const indexInList = this.emojiItems.findIndex(k => k.id === groupId) this.$refs['emoji-groups'].scrollToItem(indexInList) }, - updateScrolledClass(target) { + updateScrolledClass (target) { if (target.scrollTop <= 5) { this.groupsScrolledClass = 'scrolled-top' } else if (target.scrollTop >= target.scrollTopMax - 5) { @@ -269,21 +251,16 @@ const EmojiPicker = { this.groupsScrolledClass = 'scrolled-middle' } }, - toggleStickers() { + toggleStickers () { this.showingStickers = !this.showingStickers }, - setShowStickers(value) { + setShowStickers (value) { this.showingStickers = value }, - filterByKeyword(list, keyword) { - return filterByKeyword( - list, - keyword, - this.languages, - this.maybeLocalizedEmojiName, - ) + filterByKeyword (list, keyword) { + return filterByKeyword(list, keyword, this.languages, this.maybeLocalizedEmojiName) }, - onShowing() { + onShowing () { const oldContentLoaded = this.contentLoaded this.updateEmojiSize() this.recalculateItemPerRow() @@ -300,59 +277,59 @@ const EmojiPicker = { }) } }, - getFilteredEmojiGroups() { + getFilteredEmojiGroups () { return this.allEmojiGroups - .map((group) => ({ + .map(group => ({ ...group, - emojis: this.filterByKeyword(group.emojis, trim(this.keyword)), + emojis: this.filterByKeyword(group.emojis, trim(this.keyword)) })) - .filter((group) => group.emojis.length > 0) + .filter(group => group.emojis.length > 0) }, - recalculateItemPerRow() { + recalculateItemPerRow () { this.$nextTick(() => { if (!this.$refs['emoji-groups']) { return } this.width = this.$refs['emoji-groups'].$el.clientWidth }) - }, + } }, watch: { - keyword() { + keyword () { this.onScroll() this.debouncedHandleKeywordChange() }, - allCustomGroups() { + allCustomGroups () { this.filteredEmojiGroups = this.getFilteredEmojiGroups() - }, + } }, computed: { - minItemSize() { + minItemSize () { return this.emojiSize }, // used to watch it - fontSize() { + fontSize () { this.$nextTick(() => { this.updateEmojiSize() }) return this.$store.getters.mergedConfig.fontSize }, - emojiHeight() { + emojiHeight () { return this.emojiSize }, - itemPerRow() { + itemPerRow () { return this.width ? Math.floor(this.width / this.emojiSize) : 6 }, - activeGroupView() { + activeGroupView () { return this.showingStickers ? '' : this.activeGroup }, - stickersAvailable() { + stickersAvailable () { if (this.$store.state.instance.stickers) { return this.$store.state.instance.stickers.length > 0 } return 0 }, - allCustomGroups() { + allCustomGroups () { if (this.hideCustomEmoji || this.hideCustomEmojiInPicker) { return {} } @@ -362,49 +339,46 @@ const EmojiPicker = { } return emojis }, - defaultGroup() { + defaultGroup () { return Object.keys(this.allCustomGroups)[0] }, - unicodeEmojiGroups() { - return this.$store.getters.standardEmojiGroupList.map((group) => ({ + unicodeEmojiGroups () { + return this.$store.getters.standardEmojiGroupList.map(group => ({ id: `standard-${group.id}`, text: this.$t(`emoji.unicode_groups.${group.id}`), icon: UNICODE_EMOJI_GROUP_ICON[group.id], - emojis: group.emojis, + emojis: group.emojis })) }, - allEmojiGroups() { + allEmojiGroups () { return Object.entries(this.allCustomGroups) .map(([, v]) => v) .concat(this.unicodeEmojiGroups) }, - stickerPickerEnabled() { + stickerPickerEnabled () { return (this.$store.state.instance.stickers || []).length !== 0 }, - debouncedHandleKeywordChange() { + debouncedHandleKeywordChange () { return debounce(() => { this.filteredEmojiGroups = this.getFilteredEmojiGroups() }, 500) }, - emojiItems() { - return this.filteredEmojiGroups - .map((group) => - chunk(group.emojis, this.itemPerRow).map((items, index) => ({ + emojiItems () { + return this.filteredEmojiGroups.map(group => + chunk(group.emojis, this.itemPerRow) + .map((items, index) => ({ ...group, id: index === 0 ? group.id : `row-${index}-${group.id}`, emojis: items, - isFirstRow: index === 0, - })), - ) + isFirstRow: index === 0 + }))) .reduce((a, c) => a.concat(c), []) }, - languages() { - return ensureFinalFallback( - this.$store.getters.mergedConfig.interfaceLanguage, - ) + languages () { + return ensureFinalFallback(this.$store.getters.mergedConfig.interfaceLanguage) }, - maybeLocalizedEmojiName() { - return (emoji) => { + maybeLocalizedEmojiName () { + return emoji => { if (!emoji.annotations) { return emoji.displayText } @@ -422,10 +396,10 @@ const EmojiPicker = { return emoji.displayText } }, - isInModal() { + isInModal () { return this.popoversZLayer === 'modals' - }, - }, + } + } } export default EmojiPicker diff --git a/src/components/emoji_reactions/emoji_reactions.js b/src/components/emoji_reactions/emoji_reactions.js index a21f68f83..f5e1b68f6 100644 --- a/src/components/emoji_reactions/emoji_reactions.js +++ b/src/components/emoji_reactions/emoji_reactions.js @@ -1,10 +1,18 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faCheck, faMinus, faPlus } from '@fortawesome/free-solid-svg-icons' -import StillImage from 'src/components/still-image/still-image.vue' import UserAvatar from '../user_avatar/user_avatar.vue' import UserListPopover from '../user_list_popover/user_list_popover.vue' +import StillImage from 'src/components/still-image/still-image.vue' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faPlus, + faMinus, + faCheck +} from '@fortawesome/free-solid-svg-icons' -library.add(faPlus, faMinus, faCheck) +library.add( + faPlus, + faMinus, + faCheck +) const EMOJI_REACTION_COUNT_CUTOFF = 12 @@ -13,62 +21,57 @@ const EmojiReactions = { components: { UserAvatar, UserListPopover, - StillImage, + StillImage }, props: ['status'], data: () => ({ - showAll: false, + showAll: false }), computed: { - tooManyReactions() { + tooManyReactions () { return this.status.emoji_reactions.length > EMOJI_REACTION_COUNT_CUTOFF }, - emojiReactions() { + emojiReactions () { return this.showAll ? this.status.emoji_reactions : this.status.emoji_reactions.slice(0, EMOJI_REACTION_COUNT_CUTOFF) }, - showMoreString() { + showMoreString () { return `+${this.status.emoji_reactions.length - EMOJI_REACTION_COUNT_CUTOFF}` }, - accountsForEmoji() { + accountsForEmoji () { return this.status.emoji_reactions.reduce((acc, reaction) => { acc[reaction.name] = reaction.accounts || [] return acc }, {}) }, - loggedIn() { + loggedIn () { return !!this.$store.state.users.currentUser }, - remoteInteractionLink() { - return this.$store.getters.remoteInteractionLink({ - statusId: this.status.id, - }) - }, + remoteInteractionLink () { + return this.$store.getters.remoteInteractionLink({ statusId: this.status.id }) + } }, methods: { - toggleShowAll() { + toggleShowAll () { this.showAll = !this.showAll }, - reactedWith(emoji) { - return this.status.emoji_reactions.find((r) => r.name === emoji).me + reactedWith (emoji) { + return this.status.emoji_reactions.find(r => r.name === emoji).me }, - async fetchEmojiReactionsByIfMissing() { - const hasNoAccounts = this.status.emoji_reactions.find((r) => !r.accounts) + async fetchEmojiReactionsByIfMissing () { + const hasNoAccounts = this.status.emoji_reactions.find(r => !r.accounts) if (hasNoAccounts) { - return await this.$store.dispatch( - 'fetchEmojiReactionsBy', - this.status.id, - ) + return await this.$store.dispatch('fetchEmojiReactionsBy', this.status.id) } }, - reactWith(emoji) { + reactWith (emoji) { this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji }) }, - unreact(emoji) { + unreact (emoji) { this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji }) }, - async emojiOnClick(emoji) { + async emojiOnClick (emoji) { if (!this.loggedIn) return await this.fetchEmojiReactionsByIfMissing() @@ -78,23 +81,19 @@ const EmojiReactions = { this.reactWith(emoji) } }, - counterTriggerAttrs(reaction) { + counterTriggerAttrs (reaction) { return { class: [ 'emoji-reaction-count-button', { '-picked-reaction': this.reactedWith(reaction.name), - toggled: this.reactedWith(reaction.name), - }, + toggled: this.reactedWith(reaction.name) + } ], - 'aria-label': this.$t( - 'status.reaction_count_label', - { num: reaction.count }, - reaction.count, - ), + 'aria-label': this.$t('status.reaction_count_label', { num: reaction.count }, reaction.count) } - }, - }, + } + } } export default EmojiReactions diff --git a/src/components/exporter/exporter.js b/src/components/exporter/exporter.js index 12213d9e3..fc75372e3 100644 --- a/src/components/exporter/exporter.js +++ b/src/components/exporter/exporter.js @@ -1,47 +1,45 @@ import { library } from '@fortawesome/fontawesome-svg-core' import { faCircleNotch } from '@fortawesome/free-solid-svg-icons' -library.add(faCircleNotch) +library.add( + faCircleNotch +) const Exporter = { props: { getContent: { type: Function, - required: true, + required: true }, filename: { type: String, - default: 'export.csv', + default: 'export.csv' }, exportButtonLabel: { type: String }, - processingMessage: { type: String }, + processingMessage: { type: String } }, - data() { + data () { return { - processing: false, + processing: false } }, methods: { - process() { + process () { this.processing = true - this.getContent().then((content) => { - const fileToDownload = document.createElement('a') - fileToDownload.setAttribute( - 'href', - 'data:text/plain;charset=utf-8,' + encodeURIComponent(content), - ) - fileToDownload.setAttribute('download', this.filename) - fileToDownload.style.display = 'none' - document.body.appendChild(fileToDownload) - fileToDownload.click() - document.body.removeChild(fileToDownload) - // Add delay before hiding processing state since browser takes some time to handle file download - setTimeout(() => { - this.processing = false - }, 2000) - }) - }, - }, + this.getContent() + .then((content) => { + const fileToDownload = document.createElement('a') + fileToDownload.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(content)) + fileToDownload.setAttribute('download', this.filename) + fileToDownload.style.display = 'none' + document.body.appendChild(fileToDownload) + fileToDownload.click() + document.body.removeChild(fileToDownload) + // Add delay before hiding processing state since browser takes some time to handle file download + setTimeout(() => { this.processing = false }, 2000) + }) + } + } } export default Exporter diff --git a/src/components/extra_notifications/extra_notifications.js b/src/components/extra_notifications/extra_notifications.js index f0beeeefd..673b28662 100644 --- a/src/components/extra_notifications/extra_notifications.js +++ b/src/components/extra_notifications/extra_notifications.js @@ -1,70 +1,55 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { - faBullhorn, - faComments, - faUserPlus, -} from '@fortawesome/free-solid-svg-icons' +import { mapGetters } from 'vuex' import { mapState as mapPiniaState } from 'pinia' import { useAnnouncementsStore } from 'src/stores/announcements' -import { useInterfaceStore } from 'src/stores/interface' -import { mapGetters } from 'vuex' -library.add(faUserPlus, faComments, faBullhorn) +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faUserPlus, + faComments, + faBullhorn +} from '@fortawesome/free-solid-svg-icons' + +import { useInterfaceStore } from 'src/stores/interface' + +library.add( + faUserPlus, + faComments, + faBullhorn +) const ExtraNotifications = { computed: { - shouldShowChats() { - return ( - this.mergedConfig.showExtraNotifications && - this.mergedConfig.showChatsInExtraNotifications && - this.unreadChatCount - ) + shouldShowChats () { + return this.mergedConfig.showExtraNotifications && this.mergedConfig.showChatsInExtraNotifications && this.unreadChatCount }, - shouldShowAnnouncements() { - return ( - this.mergedConfig.showExtraNotifications && - this.mergedConfig.showAnnouncementsInExtraNotifications && - this.unreadAnnouncementCount - ) + shouldShowAnnouncements () { + return this.mergedConfig.showExtraNotifications && this.mergedConfig.showAnnouncementsInExtraNotifications && this.unreadAnnouncementCount }, - shouldShowFollowRequests() { - return ( - this.mergedConfig.showExtraNotifications && - this.mergedConfig.showFollowRequestsInExtraNotifications && - this.followRequestCount - ) + shouldShowFollowRequests () { + return this.mergedConfig.showExtraNotifications && this.mergedConfig.showFollowRequestsInExtraNotifications && this.followRequestCount }, - hasAnythingToShow() { - return ( - this.shouldShowChats || - this.shouldShowAnnouncements || - this.shouldShowFollowRequests - ) + hasAnythingToShow () { + return this.shouldShowChats || this.shouldShowAnnouncements || this.shouldShowFollowRequests }, - shouldShowCustomizationTip() { - return ( - this.mergedConfig.showExtraNotificationsTip && this.hasAnythingToShow - ) + shouldShowCustomizationTip () { + return this.mergedConfig.showExtraNotificationsTip && this.hasAnythingToShow }, - currentUser() { + currentUser () { return this.$store.state.users.currentUser }, ...mapGetters(['unreadChatCount', 'followRequestCount', 'mergedConfig']), ...mapPiniaState(useAnnouncementsStore, { - unreadAnnouncementCount: 'unreadAnnouncementCount', - }), + unreadAnnouncementCount: 'unreadAnnouncementCount' + }) }, methods: { - openNotificationSettings() { + openNotificationSettings () { return useInterfaceStore().openSettingsModalTab('notifications') }, - dismissConfigurationTip() { - return this.$store.dispatch('setOption', { - name: 'showExtraNotificationsTip', - value: false, - }) - }, - }, + dismissConfigurationTip () { + return this.$store.dispatch('setOption', { name: 'showExtraNotificationsTip', value: false }) + } + } } export default ExtraNotifications diff --git a/src/components/features_panel/features_panel.js b/src/components/features_panel/features_panel.js index e92cb975e..d177efebe 100644 --- a/src/components/features_panel/features_panel.js +++ b/src/components/features_panel/features_panel.js @@ -2,33 +2,15 @@ import fileSizeFormatService from '../../services/file_size_format/file_size_for const FeaturesPanel = { computed: { - shout: function () { - return this.$store.state.instance.shoutAvailable - }, - pleromaChatMessages: function () { - return this.$store.state.instance.pleromaChatMessagesAvailable - }, - gopher: function () { - return this.$store.state.instance.gopherAvailable - }, - whoToFollow: function () { - return this.$store.state.instance.suggestionsEnabled - }, - mediaProxy: function () { - return this.$store.state.instance.mediaProxyAvailable - }, - minimalScopesMode: function () { - return this.$store.state.instance.minimalScopesMode - }, - textlimit: function () { - return this.$store.state.instance.textlimit - }, - uploadlimit: function () { - return fileSizeFormatService.fileSizeFormat( - this.$store.state.instance.uploadlimit, - ) - }, - }, + shout: function () { return this.$store.state.instance.shoutAvailable }, + pleromaChatMessages: function () { return this.$store.state.instance.pleromaChatMessagesAvailable }, + gopher: function () { return this.$store.state.instance.gopherAvailable }, + whoToFollow: function () { return this.$store.state.instance.suggestionsEnabled }, + mediaProxy: function () { return this.$store.state.instance.mediaProxyAvailable }, + minimalScopesMode: function () { return this.$store.state.instance.minimalScopesMode }, + textlimit: function () { return this.$store.state.instance.textlimit }, + uploadlimit: function () { return fileSizeFormatService.fileSizeFormat(this.$store.state.instance.uploadlimit) } + } } export default FeaturesPanel diff --git a/src/components/flash/flash.js b/src/components/flash/flash.js index 2c1c05ddc..87c1d650c 100644 --- a/src/components/flash/flash.js +++ b/src/components/flash/flash.js @@ -1,53 +1,53 @@ +import RuffleService from '../../services/ruffle_service/ruffle_service.js' import { library } from '@fortawesome/fontawesome-svg-core' import { - faExclamationTriangle, faStop, + faExclamationTriangle } from '@fortawesome/free-solid-svg-icons' -import RuffleService from '../../services/ruffle_service/ruffle_service.js' -library.add(faStop, faExclamationTriangle) +library.add( + faStop, + faExclamationTriangle +) const Flash = { props: ['src'], - data() { + data () { return { player: false, // can be true, "hidden", false. hidden = element exists loaded: false, - ruffleInstance: null, + ruffleInstance: null } }, methods: { - openPlayer() { + openPlayer () { if (this.player) return // prevent double-loading, or re-loading on failure this.player = 'hidden' RuffleService.getRuffle().then((ruffle) => { const player = ruffle.newest().createPlayer() player.config = { - letterbox: 'on', + letterbox: 'on' } const container = this.$refs.container container.appendChild(player) player.style.width = '100%' player.style.height = '100%' - player - .load(this.src) - .then(() => { - this.player = true - }) - .catch((e) => { - console.error('Error loading ruffle', e) - this.player = 'error' - }) + player.load(this.src).then(() => { + this.player = true + }).catch((e) => { + console.error('Error loading ruffle', e) + this.player = 'error' + }) this.ruffleInstance = player this.$emit('playerOpened') }) }, - closePlayer() { + closePlayer () { this.ruffleInstance && this.ruffleInstance.remove() this.player = false this.$emit('playerClosed') - }, - }, + } + } } export default Flash diff --git a/src/components/follow_button/follow_button.js b/src/components/follow_button/follow_button.js index eb545b28d..443aa9bcc 100644 --- a/src/components/follow_button/follow_button.js +++ b/src/components/follow_button/follow_button.js @@ -1,27 +1,24 @@ -import { - requestFollow, - requestUnfollow, -} from '../../services/follow_manipulate/follow_manipulate' import ConfirmModal from '../confirm_modal/confirm_modal.vue' +import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate' export default { props: ['relationship', 'user', 'labelFollowing', 'buttonClass'], components: { - ConfirmModal, + ConfirmModal }, - data() { + data () { return { inProgress: false, - showingConfirmUnfollow: false, + showingConfirmUnfollow: false } }, computed: { - shouldConfirmUnfollow() { + shouldConfirmUnfollow () { return this.$store.getters.mergedConfig.modalOnUnfollow }, - isPressed() { + isPressed () { return this.inProgress || this.relationship.following }, - title() { + title () { if (this.inProgress || this.relationship.following) { return this.$t('user_card.follow_unfollow') } else if (this.relationship.requested) { @@ -30,7 +27,7 @@ export default { return this.$t('user_card.follow') } }, - label() { + label () { if (this.inProgress) { return this.$t('user_card.follow_progress') } else if (this.relationship.following) { @@ -41,47 +38,42 @@ export default { return this.$t('user_card.follow') } }, - disabled() { + disabled () { return this.inProgress || this.user.deactivated - }, + } }, methods: { - showConfirmUnfollow() { + showConfirmUnfollow () { this.showingConfirmUnfollow = true }, - hideConfirmUnfollow() { + hideConfirmUnfollow () { this.showingConfirmUnfollow = false }, - onClick() { - this.relationship.following || this.relationship.requested - ? this.unfollow() - : this.follow() + onClick () { + this.relationship.following || this.relationship.requested ? this.unfollow() : this.follow() }, - follow() { + follow () { this.inProgress = true requestFollow(this.relationship.id, this.$store).then(() => { this.inProgress = false }) }, - unfollow() { + unfollow () { if (this.shouldConfirmUnfollow) { this.showConfirmUnfollow() } else { this.doUnfollow() } }, - doUnfollow() { + doUnfollow () { const store = this.$store this.inProgress = true requestUnfollow(this.relationship.id, store).then(() => { this.inProgress = false - store.commit('removeStatus', { - timeline: 'friends', - userId: this.relationship.id, - }) + store.commit('removeStatus', { timeline: 'friends', userId: this.relationship.id }) }) this.hideConfirmUnfollow() - }, - }, + } + } } diff --git a/src/components/follow_card/follow_card.js b/src/components/follow_card/follow_card.js index e4c84dcdd..b26b27a74 100644 --- a/src/components/follow_card/follow_card.js +++ b/src/components/follow_card/follow_card.js @@ -1,27 +1,30 @@ import BasicUserCard from '../basic_user_card/basic_user_card.vue' -import FollowButton from '../follow_button/follow_button.vue' import RemoteFollow from '../remote_follow/remote_follow.vue' +import FollowButton from '../follow_button/follow_button.vue' import RemoveFollowerButton from '../remove_follower_button/remove_follower_button.vue' const FollowCard = { - props: ['user', 'noFollowsYou'], + props: [ + 'user', + 'noFollowsYou' + ], components: { BasicUserCard, RemoteFollow, FollowButton, - RemoveFollowerButton, + RemoveFollowerButton }, computed: { - isMe() { + isMe () { return this.$store.state.users.currentUser.id === this.user.id }, - loggedIn() { + loggedIn () { return this.$store.state.users.currentUser }, - relationship() { + relationship () { return this.$store.getters.relationship(this.user.id) - }, - }, + } + } } export default FollowCard diff --git a/src/components/follow_request_card/follow_request_card.js b/src/components/follow_request_card/follow_request_card.js index c037ddf42..b0873bb10 100644 --- a/src/components/follow_request_card/follow_request_card.js +++ b/src/components/follow_request_card/follow_request_card.js @@ -1,48 +1,46 @@ -import { notificationsFromStore } from '../../services/notification_utils/notification_utils.js' import BasicUserCard from '../basic_user_card/basic_user_card.vue' import ConfirmModal from '../confirm_modal/confirm_modal.vue' +import { notificationsFromStore } from '../../services/notification_utils/notification_utils.js' const FollowRequestCard = { props: ['user'], components: { BasicUserCard, - ConfirmModal, + ConfirmModal }, - data() { + data () { return { showingApproveConfirmDialog: false, - showingDenyConfirmDialog: false, + showingDenyConfirmDialog: false } }, methods: { - findFollowRequestNotificationId() { + findFollowRequestNotificationId () { const notif = notificationsFromStore(this.$store).find( - (notif) => - notif.from_profile.id === this.user.id && - notif.type === 'follow_request', + (notif) => notif.from_profile.id === this.user.id && notif.type === 'follow_request' ) return notif && notif.id }, - showApproveConfirmDialog() { + showApproveConfirmDialog () { this.showingApproveConfirmDialog = true }, - hideApproveConfirmDialog() { + hideApproveConfirmDialog () { this.showingApproveConfirmDialog = false }, - showDenyConfirmDialog() { + showDenyConfirmDialog () { this.showingDenyConfirmDialog = true }, - hideDenyConfirmDialog() { + hideDenyConfirmDialog () { this.showingDenyConfirmDialog = false }, - approveUser() { + approveUser () { if (this.shouldConfirmApprove) { this.showApproveConfirmDialog() } else { this.doApprove() } }, - doApprove() { + doApprove () { this.$store.state.api.backendInteractor.approveUser({ id: this.user.id }) this.$store.dispatch('removeFollowRequest', this.user) @@ -50,41 +48,40 @@ const FollowRequestCard = { this.$store.dispatch('markSingleNotificationAsSeen', { id: notifId }) this.$store.dispatch('updateNotification', { id: notifId, - updater: (notification) => { + updater: notification => { notification.type = 'follow' - }, + } }) this.hideApproveConfirmDialog() }, - denyUser() { + denyUser () { if (this.shouldConfirmDeny) { this.showDenyConfirmDialog() } else { this.doDeny() } }, - doDeny() { + doDeny () { const notifId = this.findFollowRequestNotificationId() - this.$store.state.api.backendInteractor - .denyUser({ id: this.user.id }) + this.$store.state.api.backendInteractor.denyUser({ id: this.user.id }) .then(() => { this.$store.dispatch('dismissNotificationLocal', { id: notifId }) this.$store.dispatch('removeFollowRequest', this.user) }) this.hideDenyConfirmDialog() - }, + } }, computed: { - mergedConfig() { + mergedConfig () { return this.$store.getters.mergedConfig }, - shouldConfirmApprove() { + shouldConfirmApprove () { return this.mergedConfig.modalOnApproveFollow }, - shouldConfirmDeny() { + shouldConfirmDeny () { return this.mergedConfig.modalOnDenyFollow - }, - }, + } + } } export default FollowRequestCard diff --git a/src/components/follow_requests/follow_requests.js b/src/components/follow_requests/follow_requests.js index 7dbecee53..704a76c66 100644 --- a/src/components/follow_requests/follow_requests.js +++ b/src/components/follow_requests/follow_requests.js @@ -2,13 +2,13 @@ import FollowRequestCard from '../follow_request_card/follow_request_card.vue' const FollowRequests = { components: { - FollowRequestCard, + FollowRequestCard }, computed: { - requests() { + requests () { return this.$store.state.api.followRequests - }, - }, + } + } } export default FollowRequests diff --git a/src/components/font_control/font_control.js b/src/components/font_control/font_control.js index c166088bd..ffc866788 100644 --- a/src/components/font_control/font_control.js +++ b/src/components/font_control/font_control.js @@ -1,28 +1,35 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { - faExclamationTriangle, - faFont, - faKeyboard, -} from '@fortawesome/free-solid-svg-icons' +import Select from '../select/select.vue' import Checkbox from 'src/components/checkbox/checkbox.vue' import Popover from 'src/components/popover/popover.vue' import { useInterfaceStore } from 'src/stores/interface' -import Select from '../select/select.vue' -library.add(faExclamationTriangle, faKeyboard, faFont) +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faExclamationTriangle, + faKeyboard, + faFont +} from '@fortawesome/free-solid-svg-icons' + +library.add( + faExclamationTriangle, + faKeyboard, + faFont +) export default { components: { Select, Checkbox, - Popover, + Popover }, - props: ['name', 'label', 'modelValue', 'fallback', 'options', 'no-inherit'], - mounted() { + props: [ + 'name', 'label', 'modelValue', 'fallback', 'options', 'no-inherit' + ], + mounted () { useInterfaceStore().queryLocalFonts() }, emits: ['update:modelValue'], - data() { + data () { return { manualEntry: false, availableOptions: [ @@ -30,24 +37,24 @@ export default { 'serif', 'sans-serif', 'monospace', - ...(this.options || []), - ].filter((_) => _), + ...(this.options || []) + ].filter(_ => _) } }, methods: { - toggleManualEntry() { + toggleManualEntry () { this.manualEntry = !this.manualEntry - }, + } }, computed: { - present() { + present () { return typeof this.modelValue !== 'undefined' }, - localFontsList() { + localFontsList () { return useInterfaceStore().localFonts }, - localFontsSize() { + localFontsSize () { return useInterfaceStore().localFonts?.length - }, - }, + } + } } diff --git a/src/components/friends_timeline/friends_timeline.js b/src/components/friends_timeline/friends_timeline.js index c0c032a8f..948b23a49 100644 --- a/src/components/friends_timeline/friends_timeline.js +++ b/src/components/friends_timeline/friends_timeline.js @@ -1,14 +1,11 @@ import Timeline from '../timeline/timeline.vue' - const FriendsTimeline = { components: { - Timeline, + Timeline }, computed: { - timeline() { - return this.$store.state.statuses.timelines.friends - }, - }, + timeline () { return this.$store.state.statuses.timelines.friends } + } } export default FriendsTimeline diff --git a/src/components/fun_text.style.js b/src/components/fun_text.style.js index eff88feb7..2d3ac1549 100644 --- a/src/components/fun_text.style.js +++ b/src/components/fun_text.style.js @@ -4,37 +4,37 @@ export default { virtual: true, variants: { greentext: '.greentext', - cyantext: '.cyantext', + cyantext: '.cyantext' }, states: { - faint: '.faint', + faint: '.faint' }, defaultRules: [ { directives: { textColor: '--text', - textAuto: 'preserve', - }, + textAuto: 'preserve' + } }, { state: ['faint'], directives: { - textOpacity: 0.5, - }, + textOpacity: 0.5 + } }, { variant: 'greentext', directives: { textColor: '--cGreen', - textAuto: 'preserve', - }, + textAuto: 'preserve' + } }, { variant: 'cyantext', directives: { textColor: '--cBlue', - textAuto: 'preserve', - }, - }, - ], + textAuto: 'preserve' + } + } + ] } diff --git a/src/components/gallery/gallery.js b/src/components/gallery/gallery.js index 83999ef25..676c830b0 100644 --- a/src/components/gallery/gallery.js +++ b/src/components/gallery/gallery.js @@ -1,6 +1,6 @@ -import { set, sumBy } from 'lodash' import { useMediaViewerStore } from 'src/stores/media_viewer' import Attachment from '../attachment/attachment.vue' +import { sumBy, set } from 'lodash' const Gallery = { props: [ @@ -17,71 +17,52 @@ const Gallery = { 'shiftUpAttachment', 'shiftDnAttachment', 'editAttachment', - 'grid', + 'grid' ], - data() { + data () { return { sizes: {}, - hidingLong: true, + hidingLong: true } }, components: { Attachment }, computed: { - rows() { + rows () { if (!this.attachments) { return [] } - const attachments = - this.limit > 0 - ? this.attachments.slice(0, this.limit) - : this.attachments + const attachments = this.limit > 0 + ? this.attachments.slice(0, this.limit) + : this.attachments if (this.size === 'hide') { - return attachments.map((item) => ({ minimal: true, items: [item] })) + return attachments.map(item => ({ minimal: true, items: [item] })) } const rows = this.grid ? [{ grid: true, items: attachments }] - : attachments - .reduce( - (acc, attachment, i) => { - if (attachment.mimetype.includes('audio')) { - return [ - ...acc, - { audio: true, items: [attachment] }, - { items: [] }, - ] - } - if ( - !( - attachment.mimetype.includes('image') || - attachment.mimetype.includes('video') || - attachment.mimetype.includes('flash') - ) - ) { - return [ - ...acc, - { minimal: true, items: [attachment] }, - { items: [] }, - ] - } - const maxPerRow = 3 - const attachmentsRemaining = this.attachments.length - i + 1 - const currentRow = acc[acc.length - 1].items - currentRow.push(attachment) - if ( - currentRow.length >= maxPerRow && - attachmentsRemaining > maxPerRow - ) { - return [...acc, { items: [] }] - } else { - return acc - } - }, - [{ items: [] }], - ) - .filter((_) => _.items.length > 0) + : attachments.reduce((acc, attachment, i) => { + if (attachment.mimetype.includes('audio')) { + return [...acc, { audio: true, items: [attachment] }, { items: [] }] + } + if (!( + attachment.mimetype.includes('image') || + attachment.mimetype.includes('video') || + attachment.mimetype.includes('flash') + )) { + return [...acc, { minimal: true, items: [attachment] }, { items: [] }] + } + const maxPerRow = 3 + const attachmentsRemaining = this.attachments.length - i + 1 + const currentRow = acc[acc.length - 1].items + currentRow.push(attachment) + if (currentRow.length >= maxPerRow && attachmentsRemaining > maxPerRow) { + return [...acc, { items: [] }] + } else { + return acc + } + }, [{ items: [] }]).filter(_ => _.items.length > 0) return rows }, - attachmentsDimensionalScore() { + attachmentsDimensionalScore () { return this.rows.reduce((acc, row) => { let size = 0 if (row.minimal) { @@ -94,7 +75,7 @@ const Gallery = { return acc + size }, 0) }, - tooManyAttachments() { + tooManyAttachments () { if (this.editable || this.size === 'small') { return false } else if (this.size === 'hide') { @@ -102,38 +83,38 @@ const Gallery = { } else { return this.attachmentsDimensionalScore > 1 } - }, + } }, methods: { - onNaturalSizeLoad({ id, width, height }) { + onNaturalSizeLoad ({ id, width, height }) { set(this.sizes, id, { width, height }) }, - rowStyle(row) { + rowStyle (row) { if (row.audio) { return { 'padding-bottom': '25%' } // fixed reduced height for audio } else if (!row.minimal && !row.grid) { - return { 'padding-bottom': `${100 / (row.items.length + 0.6)}%` } + return { 'padding-bottom': `${(100 / (row.items.length + 0.6))}%` } } }, - itemStyle(id, row) { - const total = sumBy(row, (item) => this.getAspectRatio(item.id)) + itemStyle (id, row) { + const total = sumBy(row, item => this.getAspectRatio(item.id)) return { flex: `${this.getAspectRatio(id) / total} 1 0%` } }, - getAspectRatio(id) { + getAspectRatio (id) { const size = this.sizes[id] return size ? size.width / size.height : 1 }, - toggleHidingLong(event) { + toggleHidingLong (event) { this.hidingLong = event }, - openGallery() { + openGallery () { useMediaViewerStore().setMedia(this.attachments) useMediaViewerStore().setCurrentMedia(this.attachments[0]) }, - onMedia() { + onMedia () { useMediaViewerStore().setMedia(this.attachments) - }, - }, + } + } } export default Gallery diff --git a/src/components/global_notice_list/global_notice_list.js b/src/components/global_notice_list/global_notice_list.js index 7135d5084..cf14d1a07 100644 --- a/src/components/global_notice_list/global_notice_list.js +++ b/src/components/global_notice_list/global_notice_list.js @@ -1,20 +1,24 @@ import { library } from '@fortawesome/fontawesome-svg-core' -import { faTimes } from '@fortawesome/free-solid-svg-icons' +import { + faTimes +} from '@fortawesome/free-solid-svg-icons' import { useInterfaceStore } from 'src/stores/interface' -library.add(faTimes) +library.add( + faTimes +) const GlobalNoticeList = { computed: { - notices() { + notices () { return useInterfaceStore().globalNotices - }, + } }, methods: { - closeNotice(notice) { + closeNotice (notice) { useInterfaceStore().removeGlobalNotice(notice) - }, - }, + } + } } export default GlobalNoticeList diff --git a/src/components/hashtag_link/hashtag_link.js b/src/components/hashtag_link/hashtag_link.js index 09cfaf199..a2433c2ab 100644 --- a/src/components/hashtag_link/hashtag_link.js +++ b/src/components/hashtag_link/hashtag_link.js @@ -5,20 +5,20 @@ const HashtagLink = { props: { url: { required: true, - type: String, + type: String }, content: { required: true, - type: String, + type: String }, tag: { required: false, type: String, - default: '', - }, + default: '' + } }, methods: { - onClick() { + onClick () { const tag = this.tag || extractTagFromUrl(this.url) if (tag) { const link = this.generateTagLink(tag) @@ -27,10 +27,10 @@ const HashtagLink = { window.open(this.url, '_blank') } }, - generateTagLink(tag) { + generateTagLink (tag) { return `/tag/${tag}` - }, - }, + } + } } export default HashtagLink diff --git a/src/components/icon.style.js b/src/components/icon.style.js index b13485c1b..4d30f389b 100644 --- a/src/components/icon.style.js +++ b/src/components/icon.style.js @@ -7,8 +7,8 @@ export default { component: 'Icon', directives: { textColor: '$blend(--stack 0.5 --parent--text)', - textAuto: 'no-auto', - }, - }, - ], + textAuto: 'no-auto' + } + } + ] } diff --git a/src/components/image_cropper/image_cropper.js b/src/components/image_cropper/image_cropper.js index 158fcdefa..afca328e8 100644 --- a/src/components/image_cropper/image_cropper.js +++ b/src/components/image_cropper/image_cropper.js @@ -1,25 +1,29 @@ import 'cropperjs' // This adds all of the cropperjs's components into DOM import { library } from '@fortawesome/fontawesome-svg-core' -import { faCircleNotch } from '@fortawesome/free-solid-svg-icons' +import { + faCircleNotch +} from '@fortawesome/free-solid-svg-icons' -library.add(faCircleNotch) +library.add( + faCircleNotch +) const ImageCropper = { props: { // Mime-types to accept, i.e. which filetypes to accept (.gif, .png, etc.) mimes: { type: String, - default: 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon', + default: 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon' }, // Fixed aspect-ratio for selection box aspectRatio: { - type: Number, - }, + type: Number + } }, - data() { + data () { return { dataUrl: undefined, - filename: undefined, + filename: undefined } }, emits: [ @@ -27,12 +31,12 @@ const ImageCropper = { 'close', // cropper is closed ], methods: { - destroy() { + destroy () { this.$refs.input.value = '' this.dataUrl = undefined this.$emit('close') }, - submit(cropping = true) { + submit (cropping = true) { let cropperPromise if (cropping) { cropperPromise = this.$refs.cropperSelection.$toCanvas() @@ -40,14 +44,14 @@ const ImageCropper = { cropperPromise = Promise.resolve() } - cropperPromise.then((canvas) => { + cropperPromise.then(canvas => { this.$emit('submit', { canvas, file: this.file }) }) }, - pickImage() { + pickImage () { this.$refs.input.click() }, - readFile() { + readFile () { const fileInput = this.$refs.input if (fileInput.files != null && fileInput.files[0] != null) { this.file = fileInput.files[0] @@ -62,10 +66,10 @@ const ImageCropper = { }, inSelection(selection, maxSelection) { return ( - selection.x >= maxSelection.x && - selection.y >= maxSelection.y && - selection.x + selection.width <= maxSelection.x + maxSelection.width && - selection.y + selection.height <= maxSelection.y + maxSelection.height + selection.x >= maxSelection.x + && selection.y >= maxSelection.y + && (selection.x + selection.width) <= (maxSelection.x + maxSelection.width) + && (selection.y + selection.height) <= (maxSelection.y + maxSelection.height) ) }, onCropperSelectionChange(event) { @@ -80,11 +84,11 @@ const ImageCropper = { } if (!this.inSelection(selection, maxSelection)) { - event.preventDefault() + event.preventDefault(); } - }, + } }, - mounted() { + mounted () { // listen for input file changes const fileInput = this.$refs.input fileInput.addEventListener('change', this.readFile) @@ -92,7 +96,7 @@ const ImageCropper = { beforeUnmount: function () { const fileInput = this.$refs.input fileInput.removeEventListener('change', this.readFile) - }, + } } export default ImageCropper diff --git a/src/components/importer/importer.js b/src/components/importer/importer.js index 0403cc944..da86a223c 100644 --- a/src/components/importer/importer.js +++ b/src/components/importer/importer.js @@ -1,49 +1,49 @@ import { library } from '@fortawesome/fontawesome-svg-core' -import { faCircleNotch, faTimes } from '@fortawesome/free-solid-svg-icons' +import { + faCircleNotch, + faTimes +} from '@fortawesome/free-solid-svg-icons' -library.add(faCircleNotch, faTimes) +library.add( + faCircleNotch, + faTimes +) const Importer = { props: { submitHandler: { type: Function, - required: true, + required: true }, submitButtonLabel: { type: String }, successMessage: { type: String }, - errorMessage: { type: String }, + errorMessage: { type: String } }, - data() { + data () { return { file: null, error: false, success: false, - submitting: false, + submitting: false } }, methods: { - change() { + change () { this.file = this.$refs.input.files[0] }, - submit() { + submit () { this.dismiss() this.submitting = true this.submitHandler(this.file) - .then(() => { - this.success = true - }) - .catch(() => { - this.error = true - }) - .finally(() => { - this.submitting = false - }) + .then(() => { this.success = true }) + .catch(() => { this.error = true }) + .finally(() => { this.submitting = false }) }, - dismiss() { + dismiss () { this.success = false this.error = false - }, - }, + } + } } export default Importer diff --git a/src/components/input.style.js b/src/components/input.style.js index 2663392fb..00f51cbf6 100644 --- a/src/components/input.style.js +++ b/src/components/input.style.js @@ -4,96 +4,91 @@ export default { states: { hover: ':is(:hover, :focus-visible):not(.disabled)', focused: ':focus-within', - disabled: '.disabled', + disabled: '.disabled' }, variants: { checkbox: '.-checkbox', - radio: '.-radio', + radio: '.-radio' }, - validInnerComponents: ['Text', 'Icon'], + validInnerComponents: [ + 'Text', + 'Icon' + ], defaultRules: [ { component: 'Root', directives: { - '--defaultInputBevel': - 'shadow | $borderSide(#FFFFFF bottom 0.2), $borderSide(#000000 top 0.2), inset 0 0 2 #000000 / 0.15, 1 0 1 1 --text / 0.15, -1 0 1 1 --text / 0.15', + '--defaultInputBevel': 'shadow | $borderSide(#FFFFFF bottom 0.2), $borderSide(#000000 top 0.2), inset 0 0 2 #000000 / 0.15, 1 0 1 1 --text / 0.15, -1 0 1 1 --text / 0.15', '--defaultInputHoverGlow': 'shadow | 0 0 4 --text / 0.5', - '--defaultInputFocusGlow': 'shadow | 0 0 4 4 --link / 0.5', - }, + '--defaultInputFocusGlow': 'shadow | 0 0 4 4 --link / 0.5' + } }, { variant: 'checkbox', directives: { - roundness: 1, - }, + roundness: 1 + } }, { directives: { '--font': 'generic | inherit', background: '--fg, -5', roundness: 3, - shadow: [ - { - x: 0, - y: 0, - blur: 2, - spread: 0, - color: '#000000', - alpha: 1, - }, - '--defaultInputBevel', - ], - }, + shadow: [{ + x: 0, + y: 0, + blur: 2, + spread: 0, + color: '#000000', + alpha: 1 + }, '--defaultInputBevel'] + } }, { state: ['hover'], directives: { - shadow: ['--defaultInputHoverGlow', '--defaultInputBevel'], - }, + shadow: ['--defaultInputHoverGlow', '--defaultInputBevel'] + } }, { state: ['focused'], directives: { - shadow: ['--defaultInputFocusGlow', '--defaultInputBevel'], - }, + shadow: ['--defaultInputFocusGlow', '--defaultInputBevel'] + } }, { state: ['focused', 'hover'], directives: { - shadow: [ - '--defaultInputFocusGlow', - '--defaultInputHoverGlow', - '--defaultInputBevel', - ], - }, + shadow: ['--defaultInputFocusGlow', '--defaultInputHoverGlow', '--defaultInputBevel'] + } }, { state: ['disabled'], directives: { - background: '--parent', - }, + background: '--parent' + } }, { component: 'Text', parent: { component: 'Input', - state: ['disabled'], + state: ['disabled'] }, directives: { textOpacity: 0.25, - textOpacityMode: 'blend', - }, + textOpacityMode: 'blend' + } }, { component: 'Icon', parent: { component: 'Input', - state: ['disabled'], + state: ['disabled'] }, directives: { textOpacity: 0.25, - textOpacityMode: 'blend', - }, - }, - ], + textOpacityMode: 'blend' + } + } + ] } diff --git a/src/components/instance_specific_panel/instance_specific_panel.js b/src/components/instance_specific_panel/instance_specific_panel.js index eead52f40..09e3d0557 100644 --- a/src/components/instance_specific_panel/instance_specific_panel.js +++ b/src/components/instance_specific_panel/instance_specific_panel.js @@ -1,9 +1,9 @@ const InstanceSpecificPanel = { computed: { - instanceSpecificPanelContent() { + instanceSpecificPanelContent () { return this.$store.state.instance.instanceSpecificPanelContent - }, - }, + } + } } export default InstanceSpecificPanel diff --git a/src/components/interactions/interactions.js b/src/components/interactions/interactions.js index 87e9e1b87..fc441b908 100644 --- a/src/components/interactions/interactions.js +++ b/src/components/interactions/interactions.js @@ -1,5 +1,5 @@ -import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' import Notifications from '../notifications/notifications.vue' +import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' const tabModeDict = { mentions: ['mention'], @@ -8,29 +8,26 @@ const tabModeDict = { follows: ['follow'], reactions: ['pleroma:emoji_reaction'], reports: ['pleroma:report'], - moves: ['move'], + moves: ['move'] } const Interactions = { - data() { + data () { return { - allowFollowingMove: - this.$store.state.users.currentUser.allow_following_move, + allowFollowingMove: this.$store.state.users.currentUser.allow_following_move, filterMode: tabModeDict.mentions, - canSeeReports: this.$store.state.users.currentUser.privileges.includes( - 'reports_manage_reports', - ), + canSeeReports: this.$store.state.users.currentUser.privileges.includes('reports_manage_reports') } }, methods: { - onModeSwitch(key) { + onModeSwitch (key) { this.filterMode = tabModeDict[key] - }, + } }, components: { Notifications, - TabSwitcher, - }, + TabSwitcher + } } export default Interactions diff --git a/src/components/interface_language_switcher/interface_language_switcher.js b/src/components/interface_language_switcher/interface_language_switcher.js index e0c7ed034..721c19887 100644 --- a/src/components/interface_language_switcher/interface_language_switcher.js +++ b/src/components/interface_language_switcher/interface_language_switcher.js @@ -1,62 +1,62 @@ -import ProfileSettingIndicator from 'src/components/settings_modal/helpers/profile_setting_indicator.vue' -import { v4 as uuidv4 } from 'uuid' import localeService from '../../services/locale/locale.service.js' + import Select from '../select/select.vue' +import ProfileSettingIndicator from 'src/components/settings_modal/helpers/profile_setting_indicator.vue' + +import { v4 as uuidv4 } from 'uuid'; export default { components: { Select, - ProfileSettingIndicator, + ProfileSettingIndicator }, props: { // List of languages (or just one language) modelValue: { type: [Array, String], - required: true, + required: true }, // Is this setting stored in user profile (true) or elsewhere (false) // Doesn't affect storage, just shows an icon if true profile: { type: Boolean, - default: false, - }, + default: false + } }, emits: ['update:modelValue'], computed: { - languages() { + languages () { return localeService.languages }, - uniqueId() { - return uuidv4() + uniqueId () { + return uuidv4() }, controlledLanguage: { get: function () { - return Array.isArray(this.modelValue) - ? this.modelValue - : [this.modelValue] + return Array.isArray(this.modelValue) ? this.modelValue : [this.modelValue] }, set: function (val) { this.$emit('update:modelValue', val) - }, - }, + } + } }, methods: { - getLanguageName(code) { + getLanguageName (code) { return localeService.getLanguageName(code) }, - addLanguage() { + addLanguage () { this.controlledLanguage = [...this.controlledLanguage, ''] }, - setLanguageAt(index, val) { + setLanguageAt (index, val) { const lang = [...this.controlledLanguage] lang[index] = val this.controlledLanguage = lang }, - removeLanguageAt(index) { + removeLanguageAt (index) { const lang = [...this.controlledLanguage] lang.splice(index, 1) this.controlledLanguage = lang - }, - }, + } + } } diff --git a/src/components/link-preview/link-preview.js b/src/components/link-preview/link-preview.js index ac91f916d..add7c5631 100644 --- a/src/components/link-preview/link-preview.js +++ b/src/components/link-preview/link-preview.js @@ -2,31 +2,37 @@ import { mapGetters } from 'vuex' const LinkPreview = { name: 'LinkPreview', - props: ['card', 'size', 'nsfw'], - data() { + props: [ + 'card', + 'size', + 'nsfw' + ], + data () { return { - imageLoaded: false, + imageLoaded: false } }, computed: { - useImage() { + useImage () { // Currently BE shoudn't give cards if tagged NSFW, this is a bit paranoid // as it makes sure to hide the image if somehow NSFW tagged preview can // exist. return this.card.image && !this.censored && this.size !== 'hide' }, - censored() { + censored () { return this.nsfw && this.hideNsfwConfig }, - useDescription() { + useDescription () { return this.card.description && /\S/.test(this.card.description) }, - hideNsfwConfig() { + hideNsfwConfig () { return this.mergedConfig.hideNsfw }, - ...mapGetters(['mergedConfig']), + ...mapGetters([ + 'mergedConfig' + ]) }, - created() { + created () { if (this.useImage) { const newImg = new Image() newImg.onload = () => { @@ -34,7 +40,7 @@ const LinkPreview = { } newImg.src = this.card.image } - }, + } } export default LinkPreview diff --git a/src/components/link.style.js b/src/components/link.style.js index 141a1f023..d13cef338 100644 --- a/src/components/link.style.js +++ b/src/components/link.style.js @@ -3,22 +3,22 @@ export default { selector: 'a', virtual: true, states: { - faint: '.faint', + faint: '.faint' }, defaultRules: [ { component: 'Link', directives: { - textColor: '--link', - }, + textColor: '--link' + } }, { component: 'Link', state: ['faint'], directives: { textOpacity: 0.5, - textOpacityMode: 'fake', - }, - }, - ], + textOpacityMode: 'fake' + } + } + ] } diff --git a/src/components/list/list.vue b/src/components/list/list.vue index f34a5f073..5d2c49b3c 100644 --- a/src/components/list/list.vue +++ b/src/components/list/list.vue @@ -29,20 +29,20 @@ export default { props: { items: { type: Array, - default: () => [], + default: () => [] }, getKey: { type: Function, - default: (item) => item.id, + default: item => item.id }, getClass: { type: Function, - default: () => '', + default: () => '' }, nonInteractive: { type: Boolean, - default: false, - }, - }, + default: false + } + } } diff --git a/src/components/lists/lists.js b/src/components/lists/lists.js index 446178245..8dcb48b52 100644 --- a/src/components/lists/lists.js +++ b/src/components/lists/lists.js @@ -2,27 +2,27 @@ import { useListsStore } from 'src/stores/lists' import ListsCard from '../lists_card/lists_card.vue' const Lists = { - data() { + data () { return { - isNew: false, + isNew: false } }, components: { - ListsCard, + ListsCard }, computed: { - lists() { + lists () { return useListsStore().allLists - }, + } }, methods: { - cancelNewList() { + cancelNewList () { this.isNew = false }, - newList() { + newList () { this.isNew = true - }, - }, + } + } } export default Lists diff --git a/src/components/lists_card/lists_card.js b/src/components/lists_card/lists_card.js index 81b811534..b503caec4 100644 --- a/src/components/lists_card/lists_card.js +++ b/src/components/lists_card/lists_card.js @@ -1,10 +1,16 @@ import { library } from '@fortawesome/fontawesome-svg-core' -import { faEllipsisH } from '@fortawesome/free-solid-svg-icons' +import { + faEllipsisH +} from '@fortawesome/free-solid-svg-icons' -library.add(faEllipsisH) +library.add( + faEllipsisH +) const ListsCard = { - props: ['list'], + props: [ + 'list' + ] } export default ListsCard diff --git a/src/components/lists_edit/lists_edit.js b/src/components/lists_edit/lists_edit.js index 42c7721f4..ca36ab886 100644 --- a/src/components/lists_edit/lists_edit.js +++ b/src/components/lists_edit/lists_edit.js @@ -1,16 +1,22 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faChevronLeft, faSearch } from '@fortawesome/free-solid-svg-icons' +import { mapState, mapGetters } from 'vuex' import { mapState as mapPiniaState } from 'pinia' -import PanelLoading from 'src/components/panel_loading/panel_loading.vue' -import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' -import { useInterfaceStore } from 'src/stores/interface' -import { useListsStore } from 'src/stores/lists' -import { mapGetters, mapState } from 'vuex' import BasicUserCard from '../basic_user_card/basic_user_card.vue' import ListsUserSearch from '../lists_user_search/lists_user_search.vue' +import PanelLoading from 'src/components/panel_loading/panel_loading.vue' import UserAvatar from '../user_avatar/user_avatar.vue' +import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faSearch, + faChevronLeft +} from '@fortawesome/free-solid-svg-icons' +import { useInterfaceStore } from 'src/stores/interface' +import { useListsStore } from 'src/stores/lists' -library.add(faSearch, faChevronLeft) +library.add( + faSearch, + faChevronLeft +) const ListsNew = { components: { @@ -18,9 +24,9 @@ const ListsNew = { UserAvatar, ListsUserSearch, TabSwitcher, - PanelLoading, + PanelLoading }, - data() { + data () { return { title: '', titleDraft: '', @@ -29,51 +35,46 @@ const ListsNew = { searchUserIds: [], addedUserIds: new Set([]), // users we added from search, to undo searchLoading: false, - reallyDelete: false, + reallyDelete: false } }, - created() { + created () { if (!this.id) return - useListsStore() - .fetchList({ listId: this.id }) + useListsStore().fetchList({ listId: this.id }) .then(() => { this.title = this.findListTitle(this.id) this.titleDraft = this.title }) - useListsStore() - .fetchListAccounts({ listId: this.id }) + useListsStore().fetchListAccounts({ listId: this.id }) .then(() => { this.membersUserIds = this.findListAccounts(this.id) - this.membersUserIds.forEach((userId) => { + this.membersUserIds.forEach(userId => { this.$store.dispatch('fetchUserIfMissing', userId) }) }) }, computed: { - id() { + id () { return this.$route.params.id }, - membersUsers() { + membersUsers () { return [...this.membersUserIds, ...this.addedUserIds] - .map((userId) => this.findUser(userId)) - .filter((user) => user) + .map(userId => this.findUser(userId)).filter(user => user) }, - searchUsers() { - return this.searchUserIds - .map((userId) => this.findUser(userId)) - .filter((user) => user) + searchUsers () { + return this.searchUserIds.map(userId => this.findUser(userId)).filter(user => user) }, ...mapState({ - currentUser: (state) => state.users.currentUser, + currentUser: state => state.users.currentUser }), ...mapPiniaState(useListsStore, ['findListTitle', 'findListAccounts']), - ...mapGetters(['findUser']), + ...mapGetters(['findUser']) }, methods: { - onInput() { + onInput () { this.search(this.query) }, - toggleRemoveMember(user) { + toggleRemoveMember (user) { if (this.removedUserIds.has(user.id)) { this.id && this.addUser(user) this.removedUserIds.delete(user.id) @@ -82,7 +83,7 @@ const ListsNew = { this.removedUserIds.add(user.id) } }, - toggleAddFromSearch(user) { + toggleAddFromSearch (user) { if (this.addedUserIds.has(user.id)) { this.id && this.removeUser(user.id) this.addedUserIds.delete(user.id) @@ -91,41 +92,39 @@ const ListsNew = { this.addedUserIds.add(user.id) } }, - isRemoved(user) { + isRemoved (user) { return this.removedUserIds.has(user.id) }, - isAdded(user) { + isAdded (user) { return this.addedUserIds.has(user.id) }, - addUser(user) { + addUser (user) { useListsStore().addListAccount({ accountId: user.id, listId: this.id }) }, - removeUser(userId) { + removeUser (userId) { useListsStore().removeListAccount({ accountId: userId, listId: this.id }) }, - onSearchLoading() { + onSearchLoading () { this.searchLoading = true }, - onSearchLoadingDone() { + onSearchLoadingDone () { this.searchLoading = false }, - onSearchResults(results) { + onSearchResults (results) { this.searchLoading = false this.searchUserIds = results }, - updateListTitle() { + updateListTitle () { useListsStore().setList({ listId: this.id, title: this.titleDraft }) - this.title = this.findListTitle(this.id) + .then(() => { + this.title = this.findListTitle(this.id) + }) }, - createList() { - useListsStore() - .createList({ title: this.titleDraft }) + createList () { + useListsStore().createList({ title: this.titleDraft }) .then((list) => { return useListsStore() - .setListAccounts({ - listId: list.id, - accountIds: [...this.addedUserIds], - }) + .setListAccounts({ listId: list.id, accountIds: [...this.addedUserIds] }) .then(() => list.id) }) .then((listId) => { @@ -135,15 +134,15 @@ const ListsNew = { useInterfaceStore().pushGlobalNotice({ messageKey: 'lists.error', messageArgs: [e.message], - level: 'error', + level: 'error' }) }) }, - deleteList() { + deleteList () { useListsStore().deleteList({ listId: this.id }) this.$router.push({ name: 'lists' }) - }, - }, + } + } } export default ListsNew diff --git a/src/components/lists_menu/lists_menu_content.js b/src/components/lists_menu/lists_menu_content.js index 2f0a9c2d2..726fd5fc4 100644 --- a/src/components/lists_menu/lists_menu_content.js +++ b/src/components/lists_menu/lists_menu_content.js @@ -1,24 +1,26 @@ -import { mapState as mapPiniaState } from 'pinia' -import { getListEntries } from 'src/components/navigation/filter.js' -import NavigationEntry from 'src/components/navigation/navigation_entry.vue' -import { useListsStore } from 'src/stores/lists' import { mapState } from 'vuex' +import { mapState as mapPiniaState } from 'pinia' +import NavigationEntry from 'src/components/navigation/navigation_entry.vue' +import { getListEntries } from 'src/components/navigation/filter.js' +import { useListsStore } from 'src/stores/lists' export const ListsMenuContent = { - props: ['showPin'], + props: [ + 'showPin' + ], components: { - NavigationEntry, + NavigationEntry }, computed: { ...mapPiniaState(useListsStore, { - lists: getListEntries, + lists: getListEntries }), ...mapState({ - currentUser: (state) => state.users.currentUser, - privateMode: (state) => state.instance.private, - federating: (state) => state.instance.federating, - }), - }, + currentUser: state => state.users.currentUser, + privateMode: state => state.instance.private, + federating: state => state.instance.federating + }) + } } export default ListsMenuContent diff --git a/src/components/lists_timeline/lists_timeline.js b/src/components/lists_timeline/lists_timeline.js index ae1554eb6..eae82a867 100644 --- a/src/components/lists_timeline/lists_timeline.js +++ b/src/components/lists_timeline/lists_timeline.js @@ -1,19 +1,16 @@ import { useListsStore } from 'src/stores/lists' import Timeline from '../timeline/timeline.vue' - const ListsTimeline = { - data() { + data () { return { - listId: null, + listId: null } }, components: { - Timeline, + Timeline }, computed: { - timeline() { - return this.$store.state.statuses.timelines.list - }, + timeline () { return this.$store.state.statuses.timelines.list } }, watch: { $route: function (route) { @@ -22,25 +19,19 @@ const ListsTimeline = { this.$store.dispatch('stopFetchingTimeline', 'list') this.$store.commit('clearTimeline', { timeline: 'list' }) useListsStore().fetchList({ listId: this.listId }) - this.$store.dispatch('startFetchingTimeline', { - timeline: 'list', - listId: this.listId, - }) + this.$store.dispatch('startFetchingTimeline', { timeline: 'list', listId: this.listId }) } - }, + } }, - created() { + created () { this.listId = this.$route.params.id useListsStore().fetchList({ listId: this.listId }) - this.$store.dispatch('startFetchingTimeline', { - timeline: 'list', - listId: this.listId, - }) + this.$store.dispatch('startFetchingTimeline', { timeline: 'list', listId: this.listId }) }, - unmounted() { + unmounted () { this.$store.dispatch('stopFetchingTimeline', 'list') this.$store.commit('clearTimeline', { timeline: 'list' }) - }, + } } export default ListsTimeline diff --git a/src/components/lists_user_search/lists_user_search.js b/src/components/lists_user_search/lists_user_search.js index 65c55319c..c92ec0eee 100644 --- a/src/components/lists_user_search/lists_user_search.js +++ b/src/components/lists_user_search/lists_user_search.js @@ -1,27 +1,33 @@ import { library } from '@fortawesome/fontawesome-svg-core' -import { faChevronLeft, faSearch } from '@fortawesome/free-solid-svg-icons' +import { + faSearch, + faChevronLeft +} from '@fortawesome/free-solid-svg-icons' import { debounce } from 'lodash' import Checkbox from '../checkbox/checkbox.vue' -library.add(faSearch, faChevronLeft) +library.add( + faSearch, + faChevronLeft +) const ListsUserSearch = { components: { - Checkbox, + Checkbox }, emits: ['loading', 'loadingDone', 'results'], - data() { + data () { return { loading: false, query: '', - followingOnly: true, + followingOnly: true } }, methods: { onInput: debounce(function () { this.search(this.query) }, 2000), - search(query) { + search (query) { if (!query) { this.loading = false return @@ -30,25 +36,16 @@ const ListsUserSearch = { this.loading = true this.$emit('loading') this.userIds = [] - this.$store - .dispatch('search', { - q: query, - resolve: true, - type: 'accounts', - following: this.followingOnly, - }) - .then((data) => { - this.$emit( - 'results', - data.accounts.map((a) => a.id), - ) + this.$store.dispatch('search', { q: query, resolve: true, type: 'accounts', following: this.followingOnly }) + .then(data => { + this.$emit('results', data.accounts.map(a => a.id)) }) .finally(() => { this.loading = false this.$emit('loadingDone') }) - }, - }, + } + } } export default ListsUserSearch diff --git a/src/components/login_form/login_form.js b/src/components/login_form/login_form.js index 346bdd83d..9566aa903 100644 --- a/src/components/login_form/login_form.js +++ b/src/components/login_form/login_form.js @@ -1,59 +1,56 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faTimes } from '@fortawesome/free-solid-svg-icons' -import { mapActions, mapState as mapPiniaState, mapStores } from 'pinia' -import { useAuthFlowStore } from 'src/stores/auth_flow.js' -import { useOAuthStore } from 'src/stores/oauth.js' import { mapState } from 'vuex' +import { mapStores, mapActions, mapState as mapPiniaState } from 'pinia' import oauthApi from '../../services/new_api/oauth.js' +import { useOAuthStore } from 'src/stores/oauth.js' +import { useAuthFlowStore } from 'src/stores/auth_flow.js' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faTimes +} from '@fortawesome/free-solid-svg-icons' -library.add(faTimes) +library.add( + faTimes +) const LoginForm = { data: () => ({ user: {}, - error: false, + error: false }), computed: { - isPasswordAuth() { - return this.requiredPassword - }, - isTokenAuth() { - return this.requiredToken - }, + isPasswordAuth () { return this.requiredPassword }, + isTokenAuth () { return this.requiredToken }, ...mapStores(useOAuthStore), ...mapState({ - registrationOpen: (state) => state.instance.registrationOpen, - instance: (state) => state.instance, - loggingIn: (state) => state.users.loggingIn, + registrationOpen: state => state.instance.registrationOpen, + instance: state => state.instance, + loggingIn: state => state.users.loggingIn, }), - ...mapPiniaState(useAuthFlowStore, [ - 'requiredPassword', - 'requiredToken', - 'requiredMFA', - ]), + ...mapPiniaState(useAuthFlowStore, ['requiredPassword', 'requiredToken', 'requiredMFA']) }, methods: { ...mapActions(useAuthFlowStore, ['requireMFA', 'login']), - submit() { + submit () { this.isTokenAuth ? this.submitToken() : this.submitPassword() }, - submitToken() { + submitToken () { const data = { instance: this.instance.server, - commit: this.$store.commit, + commit: this.$store.commit } // NOTE: we do not really need the app token, but obtaining a token and // calling verify_credentials is the only way to ensure the app still works. - this.oauthStore.ensureAppToken().then(() => { - const app = { - clientId: this.oauthStore.clientId, - clientSecret: this.oauthStore.clientSecret, - } - oauthApi.login({ ...app, ...data }) - }) + this.oauthStore.ensureAppToken() + .then(() => { + const app = { + clientId: this.oauthStore.clientId, + clientSecret: this.oauthStore.clientSecret, + } + oauthApi.login({ ...app, ...data }) + }) }, - submitPassword() { + submitPassword () { this.error = false // NOTE: we do not really need the app token, but obtaining a token and @@ -64,43 +61,38 @@ const LoginForm = { clientSecret: this.oauthStore.clientSecret, } - oauthApi - .getTokenWithCredentials({ + oauthApi.getTokenWithCredentials( + { ...app, instance: this.instance.server, username: this.user.username, - password: this.user.password, - }) - .then((result) => { - if (result.error) { - if (result.error === 'mfa_required') { - this.requireMFA({ settings: result }) - } else if (result.identifier === 'password_reset_required') { - this.$router.push({ - name: 'password-reset', - params: { passwordResetRequested: true }, - }) - } else { - this.error = result.error - this.focusOnPasswordInput() - } - return + password: this.user.password + } + ).then((result) => { + if (result.error) { + if (result.error === 'mfa_required') { + this.requireMFA({ settings: result }) + } else if (result.identifier === 'password_reset_required') { + this.$router.push({ name: 'password-reset', params: { passwordResetRequested: true } }) + } else { + this.error = result.error + this.focusOnPasswordInput() } - this.login(result).then(() => { - this.$router.push({ name: 'friends' }) - }) + return + } + this.login(result).then(() => { + this.$router.push({ name: 'friends' }) }) + }) }) }, - clearError() { - this.error = false - }, - focusOnPasswordInput() { + clearError () { this.error = false }, + focusOnPasswordInput () { const passwordInput = this.$refs.passwordInput passwordInput.focus() passwordInput.setSelectionRange(0, passwordInput.value.length) - }, - }, + } + } } export default LoginForm diff --git a/src/components/media_modal/media_modal.js b/src/components/media_modal/media_modal.js index f1d116757..9a57f8250 100644 --- a/src/components/media_modal/media_modal.js +++ b/src/components/media_modal/media_modal.js @@ -1,21 +1,26 @@ +import StillImage from '../still-image/still-image.vue' +import VideoAttachment from '../video_attachment/video_attachment.vue' +import Modal from '../modal/modal.vue' +import PinchZoom from '../pinch_zoom/pinch_zoom.vue' +import SwipeClick from '../swipe_click/swipe_click.vue' +import GestureService from '../../services/gesture_service/gesture_service' +import Flash from 'src/components/flash/flash.vue' +import fileTypeService from '../../services/file_type/file_type.service.js' import { library } from '@fortawesome/fontawesome-svg-core' import { faChevronLeft, faChevronRight, faCircleNotch, - faTimes, + faTimes } from '@fortawesome/free-solid-svg-icons' -import Flash from 'src/components/flash/flash.vue' import { useMediaViewerStore } from 'src/stores/media_viewer' -import fileTypeService from '../../services/file_type/file_type.service.js' -import GestureService from '../../services/gesture_service/gesture_service' -import Modal from '../modal/modal.vue' -import PinchZoom from '../pinch_zoom/pinch_zoom.vue' -import StillImage from '../still-image/still-image.vue' -import SwipeClick from '../swipe_click/swipe_click.vue' -import VideoAttachment from '../video_attachment/video_attachment.vue' -library.add(faChevronLeft, faChevronRight, faCircleNotch, faTimes) +library.add( + faChevronLeft, + faChevronRight, + faCircleNotch, + faTimes +) const MediaModal = { components: { @@ -24,9 +29,9 @@ const MediaModal = { PinchZoom, SwipeClick, Modal, - Flash, + Flash }, - data() { + data () { return { loading: false, swipeDirection: GestureService.DIRECTION_LEFT, @@ -35,42 +40,42 @@ const MediaModal = { return window.innerWidth * considerableMoveRatio }, pinchZoomMinScale: 1, - pinchZoomScaleResetLimit: 1.2, + pinchZoomScaleResetLimit: 1.2 } }, computed: { - showing() { + showing () { return useMediaViewerStore().activated }, - media() { + media () { return useMediaViewerStore().media }, - description() { + description () { return this.currentMedia.description }, - currentIndex() { + currentIndex () { return useMediaViewerStore().currentIndex }, - currentMedia() { + currentMedia () { return this.media[this.currentIndex] }, - canNavigate() { + canNavigate () { return this.media.length > 1 }, - type() { + type () { return this.currentMedia ? this.getType(this.currentMedia) : null }, - swipeDisableClickThreshold() { + swipeDisableClickThreshold () { // If there is only one media, allow more mouse movements to close the modal // because there is less chance that the user wants to switch to another image - return () => (this.canNavigate ? 1 : 30) - }, + return () => this.canNavigate ? 1 : 30 + } }, methods: { - getType(media) { + getType (media) { return fileTypeService.fileType(media.mimetype) }, - hide() { + hide () { // HACK: Closing immediately via a touch will cause the click // to be processed on the content below the overlay const transitionTime = 100 // ms @@ -78,7 +83,7 @@ const MediaModal = { useMediaViewerStore().closeMediaViewer() }, transitionTime) }, - hideIfNotSwiped(event) { + hideIfNotSwiped (event) { // If we have swiped over SwipeClick, do not trigger hide const comp = this.$refs.swipeClick if (!comp) { @@ -87,12 +92,9 @@ const MediaModal = { comp.$gesture.click(event) } }, - goPrev() { + goPrev () { if (this.canNavigate) { - const prevIndex = - this.currentIndex === 0 - ? this.media.length - 1 - : this.currentIndex - 1 + const prevIndex = this.currentIndex === 0 ? this.media.length - 1 : (this.currentIndex - 1) const newMedia = this.media[prevIndex] if (this.getType(newMedia) === 'image') { this.loading = true @@ -100,12 +102,9 @@ const MediaModal = { useMediaViewerStore().setCurrentMedia(newMedia) } }, - goNext() { + goNext () { if (this.canNavigate) { - const nextIndex = - this.currentIndex === this.media.length - 1 - ? 0 - : this.currentIndex + 1 + const nextIndex = this.currentIndex === this.media.length - 1 ? 0 : (this.currentIndex + 1) const newMedia = this.media[nextIndex] if (this.getType(newMedia) === 'image') { this.loading = true @@ -113,13 +112,13 @@ const MediaModal = { useMediaViewerStore().setCurrentMedia(newMedia) } }, - onImageLoaded() { + onImageLoaded () { this.loading = false }, - handleSwipePreview(offsets) { + handleSwipePreview (offsets) { this.$refs.pinchZoom.setTransform({ scale: 1, x: offsets[0], y: 0 }) }, - handleSwipeEnd(sign) { + handleSwipeEnd (sign) { this.$refs.pinchZoom.setTransform({ scale: 1, x: 0, y: 0 }) if (sign > 0) { this.goNext() @@ -127,36 +126,33 @@ const MediaModal = { this.goPrev() } }, - handleKeyupEvent(e) { - if (this.showing && e.keyCode === 27) { - // escape + handleKeyupEvent (e) { + if (this.showing && e.keyCode === 27) { // escape this.hide() } }, - handleKeydownEvent(e) { + handleKeydownEvent (e) { if (!this.showing) { return } - if (e.keyCode === 39) { - // arrow right + if (e.keyCode === 39) { // arrow right this.goNext() - } else if (e.keyCode === 37) { - // arrow left + } else if (e.keyCode === 37) { // arrow left this.goPrev() } - }, + } }, - mounted() { + mounted () { window.addEventListener('popstate', this.hide) document.addEventListener('keyup', this.handleKeyupEvent) document.addEventListener('keydown', this.handleKeydownEvent) }, - unmounted() { + unmounted () { window.removeEventListener('popstate', this.hide) document.removeEventListener('keyup', this.handleKeyupEvent) document.removeEventListener('keydown', this.handleKeydownEvent) - }, + } } export default MediaModal diff --git a/src/components/media_upload/media_upload.js b/src/components/media_upload/media_upload.js index 92d34b4c9..f2cbfc405 100644 --- a/src/components/media_upload/media_upload.js +++ b/src/components/media_upload/media_upload.js @@ -1,31 +1,34 @@ /* eslint-env browser */ +import statusPosterService from '../../services/status_poster/status_poster.service.js' +import fileSizeFormatService from '../../services/file_size_format/file_size_format.js' import { library } from '@fortawesome/fontawesome-svg-core' -import { faCircleNotch, faUpload } from '@fortawesome/free-solid-svg-icons' -import fileSizeFormatService from '../../services/file_size_format/file_size_format.js' -import statusPosterService from '../../services/status_poster/status_poster.service.js' +import { faUpload, faCircleNotch } from '@fortawesome/free-solid-svg-icons' -library.add(faUpload, faCircleNotch) +library.add( + faUpload, + faCircleNotch +) const mediaUpload = { - data() { + data () { return { uploadCount: 0, - uploadReady: true, + uploadReady: true } }, computed: { - uploading() { + uploading () { return this.uploadCount > 0 - }, + } }, methods: { - onClick() { + onClick () { if (this.uploadReady) { this.$refs.input.click() } }, - async resizeImage(file) { + async resizeImage (file) { // Skip if not an image or if it's a GIF if (!file.type.startsWith('image/') || file.type === 'image/gif') { return file @@ -71,67 +74,46 @@ const mediaUpload = { // Check WebP support by trying to create a WebP canvas const testCanvas = document.createElement('canvas') - const supportsWebP = testCanvas - .toDataURL('image/webp') - .startsWith('data:image/webp') + const supportsWebP = testCanvas.toDataURL('image/webp').startsWith('data:image/webp') // Convert to WebP if supported and alwaysUseJpeg is false, otherwise JPEG - const type = - !this.$store.getters.mergedConfig.alwaysUseJpeg && supportsWebP - ? 'image/webp' - : 'image/jpeg' + const type = (!this.$store.getters.mergedConfig.alwaysUseJpeg && supportsWebP) ? 'image/webp' : 'image/jpeg' const extension = type === 'image/webp' ? '.webp' : '.jpg' // Remove the original extension and add new one const newFileName = file.name.replace(/\.[^/.]+$/, '') + extension - canvas.toBlob( - (blob) => { - resolve( - new File([blob], newFileName, { - type, - lastModified: Date.now(), - }), - ) - }, - type, - 0.85, - ) + canvas.toBlob((blob) => { + resolve(new File([blob], newFileName, { + type, + lastModified: Date.now() + })) + }, type, 0.85) } img.src = URL.createObjectURL(file) }) }, - async isAnimatedPng(file) { + async isAnimatedPng (file) { const buffer = await file.arrayBuffer() const view = new Uint8Array(buffer) // Look for animated PNG chunks (acTL) for (let i = 0; i < view.length - 8; i++) { - if ( - view[i] === 0x61 && // a - view[i + 1] === 0x63 && // c - view[i + 2] === 0x54 && // T - view[i + 3] === 0x4c - ) { - // L + if (view[i] === 0x61 && // a + view[i + 1] === 0x63 && // c + view[i + 2] === 0x54 && // T + view[i + 3] === 0x4C) { // L return true } } return false }, - async uploadFile(file) { + async uploadFile (file) { const self = this const store = this.$store if (file.size > store.state.instance.uploadlimit) { const filesize = fileSizeFormatService.fileSizeFormat(file.size) - const allowedsize = fileSizeFormatService.fileSizeFormat( - store.state.instance.uploadlimit, - ) - self.$emit('upload-failed', 'file_too_big', { - filesize: filesize.num, - filesizeunit: filesize.unit, - allowedsize: allowedsize.num, - allowedsizeunit: allowedsize.unit, - }) + const allowedsize = fileSizeFormatService.fileSizeFormat(store.state.instance.uploadlimit) + self.$emit('upload-failed', 'file_too_big', { filesize: filesize.num, filesizeunit: filesize.unit, allowedsize: allowedsize.num, allowedsizeunit: allowedsize.unit }) return } @@ -143,38 +125,36 @@ const mediaUpload = { self.$emit('uploading') self.uploadCount++ - statusPosterService.uploadMedia({ store, formData }).then( - (fileData) => { + statusPosterService.uploadMedia({ store, formData }) + .then((fileData) => { self.$emit('uploaded', fileData) self.decreaseUploadCount() - }, - (error) => { + }, (error) => { console.error('Error uploading file', error) self.$emit('upload-failed', 'default') self.decreaseUploadCount() - }, - ) + }) }, - decreaseUploadCount() { + decreaseUploadCount () { this.uploadCount-- if (this.uploadCount === 0) { this.$emit('all-uploaded') } }, - clearFile() { + clearFile () { this.uploadReady = false this.$nextTick(() => { this.uploadReady = true }) }, - multiUpload(files) { + multiUpload (files) { for (const file of files) { this.uploadFile(file) } }, - change({ target }) { + change ({ target }) { this.multiUpload(target.files) - }, + } }, props: { dropFiles: Object, @@ -182,16 +162,16 @@ const mediaUpload = { normalButton: Boolean, acceptTypes: { type: String, - default: '*/*', - }, + default: '*/*' + } }, watch: { dropFiles: function (fileInfos) { if (!this.uploading) { this.multiUpload(fileInfos) } - }, - }, + } + } } export default mediaUpload diff --git a/src/components/mention_link/mention_link.js b/src/components/mention_link/mention_link.js index 24820331e..ca5c24618 100644 --- a/src/components/mention_link/mention_link.js +++ b/src/components/mention_link/mention_link.js @@ -1,163 +1,155 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faAt } from '@fortawesome/free-solid-svg-icons' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' -import { defineAsyncComponent } from 'vue' import { mapGetters, mapState } from 'vuex' -import { - highlightClass, - highlightStyle, -} from '../../services/user_highlighter/user_highlighter.js' -import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue' +import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js' import UserAvatar from '../user_avatar/user_avatar.vue' +import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue' +import { defineAsyncComponent } from 'vue' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faAt +} from '@fortawesome/free-solid-svg-icons' -library.add(faAt) +library.add( + faAt +) const MentionLink = { name: 'MentionLink', components: { UserAvatar, UnicodeDomainIndicator, - UserPopover: defineAsyncComponent( - () => import('../user_popover/user_popover.vue'), - ), + UserPopover: defineAsyncComponent(() => import('../user_popover/user_popover.vue')) }, props: { url: { required: true, - type: String, + type: String }, content: { required: true, - type: String, + type: String }, userId: { required: false, - type: String, + type: String }, userScreenName: { required: false, - type: String, - }, + type: String + } }, - data() { + data () { return { - hasSelection: false, + hasSelection: false } }, methods: { - onClick() { + onClick () { if (this.shouldShowTooltip) return const link = generateProfileLink( this.userId || this.user.id, - this.userScreenName || this.user.screen_name, + this.userScreenName || this.user.screen_name ) this.$router.push(link) }, - handleSelection() { + handleSelection () { if (this.$refs.full) { - this.hasSelection = document - .getSelection() - .containsNode(this.$refs.full, true) + this.hasSelection = document.getSelection().containsNode(this.$refs.full, true) } - }, + } }, - mounted() { + mounted () { document.addEventListener('selectionchange', this.handleSelection) }, - unmounted() { + unmounted () { document.removeEventListener('selectionchange', this.handleSelection) }, computed: { - user() { - return ( - this.url && this.$store && this.$store.getters.findUserByUrl(this.url) - ) + user () { + return this.url && this.$store && this.$store.getters.findUserByUrl(this.url) }, - isYou() { + isYou () { // FIXME why user !== currentUser??? return this.user && this.user.id === this.currentUser.id }, - userName() { + userName () { return this.user && this.userNameFullUi.split('@')[0] }, - serverName() { + serverName () { // XXX assumed that domain does not contain @ - return ( - this.user && - (this.userNameFullUi.split('@')[1] || - this.$store.getters.instanceDomain) - ) + return this.user && (this.userNameFullUi.split('@')[1] || this.$store.getters.instanceDomain) }, - userNameFull() { + userNameFull () { return this.user && this.user.screen_name }, - userNameFullUi() { + userNameFullUi () { return this.user && this.user.screen_name_ui }, - highlight() { + highlight () { return this.user && this.mergedConfig.highlight[this.user.screen_name] }, - highlightType() { - return this.highlight && '-' + this.highlight.type + highlightType () { + return this.highlight && ('-' + this.highlight.type) }, - highlightClass() { + highlightClass () { if (this.highlight) return highlightClass(this.user) }, - style() { + style () { if (this.highlight) { + /* eslint-disable no-unused-vars */ const { backgroundColor, backgroundPosition, backgroundImage, ...rest } = highlightStyle(this.highlight) + /* eslint-enable no-unused-vars */ return rest } }, - classnames() { + classnames () { return [ { '-you': this.isYou && this.shouldBoldenYou, '-highlighted': this.highlight, - '-has-selection': this.hasSelection, + '-has-selection': this.hasSelection }, - this.highlightType, + this.highlightType ] }, - isRemote() { + isRemote () { return this.userName !== this.userNameFull }, - shouldShowFullUserName() { + shouldShowFullUserName () { const conf = this.mergedConfig.mentionLinkDisplay if (conf === 'short') { return false } else if (conf === 'full') { return true - } else { - // full_for_remote + } else { // full_for_remote return this.isRemote } }, - shouldShowTooltip() { + shouldShowTooltip () { return this.mergedConfig.mentionLinkShowTooltip }, - shouldShowAvatar() { + shouldShowAvatar () { return this.mergedConfig.mentionLinkShowAvatar }, - shouldShowYous() { + shouldShowYous () { return this.mergedConfig.mentionLinkShowYous }, - shouldBoldenYou() { + shouldBoldenYou () { return this.mergedConfig.mentionLinkBoldenYou }, - shouldFadeDomain() { + shouldFadeDomain () { return this.mergedConfig.mentionLinkFadeDomain }, ...mapGetters(['mergedConfig']), ...mapState({ - currentUser: (state) => state.users.currentUser, - }), - }, + currentUser: state => state.users.currentUser + }) + } } export default MentionLink diff --git a/src/components/mentions/mentions.js b/src/components/mentions/mentions.js index 10167ac77..841d5aa48 100644 --- a/src/components/mentions/mentions.js +++ b/src/components/mentions/mentions.js @@ -2,13 +2,13 @@ import Timeline from '../timeline/timeline.vue' const Mentions = { computed: { - timeline() { + timeline () { return this.$store.state.statuses.timelines.mentions - }, + } }, components: { - Timeline, - }, + Timeline + } } export default Mentions diff --git a/src/components/mentions_line/mentions_line.js b/src/components/mentions_line/mentions_line.js index 8d546a3a7..a4a0c7246 100644 --- a/src/components/mentions_line/mentions_line.js +++ b/src/components/mentions_line/mentions_line.js @@ -8,30 +8,30 @@ const MentionsLine = { props: { mentions: { required: true, - type: Array, - }, + type: Array + } }, data: () => ({ expanded: false }), components: { - MentionLink, + MentionLink }, computed: { - mentionsComputed() { + mentionsComputed () { return this.mentions.slice(0, MENTIONS_LIMIT) }, - extraMentions() { + extraMentions () { return this.mentions.slice(MENTIONS_LIMIT) }, - manyMentions() { + manyMentions () { return this.extraMentions.length > 0 }, - ...mapGetters(['mergedConfig']), + ...mapGetters(['mergedConfig']) }, methods: { - toggleShowMore() { + toggleShowMore () { this.expanded = !this.expanded - }, - }, + } + } } export default MentionsLine diff --git a/src/components/menu_item.style.js b/src/components/menu_item.style.js index a5567b49b..859932062 100644 --- a/src/components/menu_item.style.js +++ b/src/components/menu_item.style.js @@ -1,105 +1,109 @@ export default { name: 'MenuItem', selector: '.menu-item', - validInnerComponents: ['Text', 'Icon', 'Border'], + validInnerComponents: [ + 'Text', + 'Icon', + 'Border' + ], states: { hover: ':is(:hover, :focus-visible, :has(:focus-visible)):not(.disabled)', active: '.-active', - disabled: '.disabled', + disabled: '.disabled' }, defaultRules: [ { directives: { background: '--bg', - opacity: 0, - }, + opacity: 0 + } }, { state: ['hover'], directives: { background: '$mod(--bg 5)', - opacity: 1, - }, + opacity: 1 + } }, { state: ['active'], directives: { background: '$mod(--bg 10)', - opacity: 1, - }, + opacity: 1 + } }, { state: ['active', 'hover'], directives: { background: '$mod(--bg 15)', - opacity: 1, - }, + opacity: 1 + } }, { component: 'Text', parent: { component: 'MenuItem', - state: ['hover'], + state: ['hover'] }, directives: { textColor: '--link', - textAuto: 'no-preserve', - }, + textAuto: 'no-preserve' + } }, { component: 'Text', parent: { component: 'MenuItem', - state: ['active'], + state: ['active'] }, directives: { textColor: '--link', - textAuto: 'no-preserve', - }, + textAuto: 'no-preserve' + } }, { component: 'Icon', parent: { component: 'MenuItem', - state: ['active'], + state: ['active'] }, directives: { textColor: '--link', - textAuto: 'no-preserve', - }, + textAuto: 'no-preserve' + } }, { component: 'Icon', parent: { component: 'MenuItem', - state: ['hover'], + state: ['hover'] }, directives: { textColor: '--link', - textAuto: 'no-preserve', - }, + textAuto: 'no-preserve' + } }, { component: 'Text', parent: { component: 'MenuItem', - state: ['disabled'], + state: ['disabled'] }, directives: { textOpacity: 0.25, - textOpacityMode: 'blend', - }, + textOpacityMode: 'blend' + } }, { component: 'Icon', parent: { component: 'MenuItem', - state: ['disabled'], + state: ['disabled'] }, directives: { textOpacity: 0.25, - textOpacityMode: 'blend', - }, - }, - ], + textOpacityMode: 'blend' + } + } + ] } diff --git a/src/components/mfa_form/recovery_form.js b/src/components/mfa_form/recovery_form.js index 015c310c7..84479b1ec 100644 --- a/src/components/mfa_form/recovery_form.js +++ b/src/components/mfa_form/recovery_form.js @@ -1,40 +1,42 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faTimes } from '@fortawesome/free-solid-svg-icons' -import { mapActions, mapState as mapPiniaState, mapStores } from 'pinia' -import { useAuthFlowStore } from 'src/stores/auth_flow.js' -import { useOAuthStore } from 'src/stores/oauth.js' -import { mapState } from 'vuex' import mfaApi from '../../services/new_api/mfa.js' +import { mapState } from 'vuex' +import { mapStores, mapActions, mapState as mapPiniaState } from 'pinia' +import { useOAuthStore } from 'src/stores/oauth.js' +import { useAuthFlowStore } from 'src/stores/auth_flow.js' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faTimes +} from '@fortawesome/free-solid-svg-icons' -library.add(faTimes) +library.add( + faTimes +) export default { data: () => ({ code: null, - error: false, + error: false }), computed: { ...mapPiniaState(useAuthFlowStore, { - authSettings: (store) => store.settings, + authSettings: store => store.settings }), ...mapStores(useOAuthStore), ...mapState({ instance: 'instance', - }), + }) }, methods: { ...mapActions(useAuthFlowStore, ['requireTOTP', 'abortMFA', 'login']), - clearError() { - this.error = false - }, + clearError () { this.error = false }, - focusOnCodeInput() { + focusOnCodeInput () { const codeInput = this.$refs.codeInput codeInput.focus() codeInput.setSelectionRange(0, codeInput.value.length) }, - submit() { + submit () { const { clientId, clientSecret } = this.oauthStore const data = { @@ -42,7 +44,7 @@ export default { clientSecret, instance: this.instance.server, mfaToken: this.authSettings.mfa_token, - code: this.code, + code: this.code } mfaApi.verifyRecoveryCode(data).then((result) => { @@ -57,6 +59,6 @@ export default { this.$router.push({ name: 'friends' }) }) }) - }, - }, + } + } } diff --git a/src/components/mfa_form/totp_form.js b/src/components/mfa_form/totp_form.js index 006c2ac6e..e369d8a5d 100644 --- a/src/components/mfa_form/totp_form.js +++ b/src/components/mfa_form/totp_form.js @@ -1,40 +1,42 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faTimes } from '@fortawesome/free-solid-svg-icons' -import { mapActions, mapState as mapPiniaState, mapStores } from 'pinia' -import { useAuthFlowStore } from 'src/stores/auth_flow.js' -import { useOAuthStore } from 'src/stores/oauth.js' -import { mapState } from 'vuex' import mfaApi from '../../services/new_api/mfa.js' +import { mapState } from 'vuex' +import { mapStores, mapActions, mapState as mapPiniaState } from 'pinia' +import { useOAuthStore } from 'src/stores/oauth.js' +import { useAuthFlowStore } from 'src/stores/auth_flow.js' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faTimes +} from '@fortawesome/free-solid-svg-icons' -library.add(faTimes) +library.add( + faTimes +) export default { data: () => ({ code: null, - error: false, + error: false }), computed: { ...mapPiniaState(useAuthFlowStore, { - authSettings: (store) => store.settings, + authSettings: store => store.settings }), ...mapStores(useOAuthStore), ...mapState({ instance: 'instance', - }), + }) }, methods: { ...mapActions(useAuthFlowStore, ['requireRecovery', 'abortMFA', 'login']), - clearError() { - this.error = false - }, + clearError () { this.error = false }, - focusOnCodeInput() { + focusOnCodeInput () { const codeInput = this.$refs.codeInput codeInput.focus() codeInput.setSelectionRange(0, codeInput.value.length) }, - submit() { + submit () { const { clientId, clientSecret } = this.oauthStore const data = { @@ -42,7 +44,7 @@ export default { clientSecret, instance: this.instance.server, mfaToken: this.authSettings.mfa_token, - code: this.code, + code: this.code } mfaApi.verifyOTPCode(data).then((result) => { @@ -57,6 +59,6 @@ export default { this.$router.push({ name: 'friends' }) }) }) - }, - }, + } + } } diff --git a/src/components/mobile_drawer.style.js b/src/components/mobile_drawer.style.js index 306bd5c17..0f2cf4e59 100644 --- a/src/components/mobile_drawer.style.js +++ b/src/components/mobile_drawer.style.js @@ -1,13 +1,15 @@ export default { name: 'MobileDrawer', selector: '.mobile-drawer', - validInnerComponents: ['MenuItem'], + validInnerComponents: [ + 'MenuItem' + ], defaultRules: [ { directives: { background: '--bg', - backgroundNoCssColor: 'yes', - }, - }, - ], + backgroundNoCssColor: 'yes' + } + } + ] } diff --git a/src/components/mobile_nav/mobile_nav.js b/src/components/mobile_nav/mobile_nav.js index 382966837..2085d24e3 100644 --- a/src/components/mobile_nav/mobile_nav.js +++ b/src/components/mobile_nav/mobile_nav.js @@ -1,97 +1,99 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { - faArrowUp, - faBars, - faBell, - faCheckDouble, - faMinus, - faTimes, -} from '@fortawesome/free-solid-svg-icons' -import { mapState } from 'pinia' +import SideDrawer from '../side_drawer/side_drawer.vue' +import Notifications from '../notifications/notifications.vue' +import ConfirmModal from '../confirm_modal/confirm_modal.vue' +import GestureService from '../../services/gesture_service/gesture_service' import NavigationPins from 'src/components/navigation/navigation_pins.vue' + +import { + unseenNotificationsFromStore, + countExtraNotifications +} from '../../services/notification_utils/notification_utils' + +import { mapGetters } from 'vuex' +import { mapState } from 'pinia' import { useAnnouncementsStore } from 'src/stores/announcements' import { useServerSideStorageStore } from 'src/stores/serverSideStorage' -import { mapGetters } from 'vuex' -import GestureService from '../../services/gesture_service/gesture_service' +import { library } from '@fortawesome/fontawesome-svg-core' import { - countExtraNotifications, - unseenNotificationsFromStore, -} from '../../services/notification_utils/notification_utils' -import ConfirmModal from '../confirm_modal/confirm_modal.vue' -import Notifications from '../notifications/notifications.vue' -import SideDrawer from '../side_drawer/side_drawer.vue' + faTimes, + faBell, + faBars, + faArrowUp, + faMinus, + faCheckDouble +} from '@fortawesome/free-solid-svg-icons' -library.add(faTimes, faBell, faBars, faArrowUp, faMinus, faCheckDouble) +library.add( + faTimes, + faBell, + faBars, + faArrowUp, + faMinus, + faCheckDouble +) const MobileNav = { components: { SideDrawer, Notifications, NavigationPins, - ConfirmModal, + ConfirmModal }, data: () => ({ notificationsCloseGesture: undefined, notificationsOpen: false, notificationsAtTop: true, - showingConfirmLogout: false, + showingConfirmLogout: false }), - created() { + created () { this.notificationsCloseGesture = GestureService.swipeGesture( GestureService.DIRECTION_RIGHT, () => this.closeMobileNotifications(true), - 50, + 50 ) }, computed: { - currentUser() { + currentUser () { return this.$store.state.users.currentUser }, - unseenNotifications() { + unseenNotifications () { return unseenNotificationsFromStore(this.$store) }, - unseenNotificationsCount() { - return ( - this.unseenNotifications.length + countExtraNotifications(this.$store) - ) + unseenNotificationsCount () { + return this.unseenNotifications.length + countExtraNotifications(this.$store) }, - unseenCount() { + unseenCount () { return this.unseenNotifications.length }, - unseenCountBadgeText() { + unseenCountBadgeText () { return `${this.unseenCount ? this.unseenCount : ''}` }, - hideSitename() { - return this.$store.state.instance.hideSitename - }, - sitename() { - return this.$store.state.instance.name - }, - isChat() { + hideSitename () { return this.$store.state.instance.hideSitename }, + sitename () { return this.$store.state.instance.name }, + isChat () { return this.$route.name === 'chat' }, ...mapState(useAnnouncementsStore, ['unreadAnnouncementCount']), ...mapState(useServerSideStorageStore, { - pinnedItems: (store) => - new Set(store.prefsStorage.collections.pinnedNavItems).has('chats'), + pinnedItems: store => new Set(store.prefsStorage.collections.pinnedNavItems).has('chats') }), - shouldConfirmLogout() { + shouldConfirmLogout () { return this.$store.getters.mergedConfig.modalOnLogout }, - closingDrawerMarksAsSeen() { + closingDrawerMarksAsSeen () { return this.$store.getters.mergedConfig.closingDrawerMarksAsSeen }, - ...mapGetters(['unreadChatCount']), + ...mapGetters(['unreadChatCount']) }, methods: { - toggleMobileSidebar() { + toggleMobileSidebar () { this.$refs.sideDrawer.toggleDrawer() }, - openMobileNotifications() { + openMobileNotifications () { this.notificationsOpen = true }, - closeMobileNotifications(markRead) { + closeMobileNotifications (markRead) { if (this.notificationsOpen) { // make sure to mark notifs seen only when the notifs were open and not // from close-calls. @@ -101,53 +103,53 @@ const MobileNav = { } } }, - notificationsTouchStart(e) { + notificationsTouchStart (e) { GestureService.beginSwipe(e, this.notificationsCloseGesture) }, - notificationsTouchMove(e) { + notificationsTouchMove (e) { GestureService.updateSwipe(e, this.notificationsCloseGesture) }, - scrollToTop() { + scrollToTop () { window.scrollTo(0, 0) }, - scrollMobileNotificationsToTop() { + scrollMobileNotificationsToTop () { this.$refs.mobileNotifications.scrollTo(0, 0) }, - showConfirmLogout() { + showConfirmLogout () { this.showingConfirmLogout = true }, - hideConfirmLogout() { + hideConfirmLogout () { this.showingConfirmLogout = false }, - logout() { + logout () { if (!this.shouldConfirmLogout) { this.doLogout() } else { this.showConfirmLogout() } }, - doLogout() { + doLogout () { this.$router.replace('/main/public') this.$store.dispatch('logout') this.hideConfirmLogout() }, - markNotificationsAsSeen() { + markNotificationsAsSeen () { this.$store.dispatch('markNotificationsAsSeen') }, - onScroll({ target: { scrollTop, clientHeight, scrollHeight } }) { + onScroll ({ target: { scrollTop, clientHeight, scrollHeight } }) { this.notificationsAtTop = scrollTop > 0 if (scrollTop + clientHeight >= scrollHeight) { this.$refs.notifications.fetchOlderNotifications() } - }, + } }, watch: { - $route() { + $route () { // handles closing notificaitons when you press any router-link on the // notifications. this.closeMobileNotifications() - }, - }, + } + } } export default MobileNav diff --git a/src/components/mobile_post_status_button/mobile_post_status_button.js b/src/components/mobile_post_status_button/mobile_post_status_button.js index 3972e0e44..031013559 100644 --- a/src/components/mobile_post_status_button/mobile_post_status_button.js +++ b/src/components/mobile_post_status_button/mobile_post_status_button.js @@ -1,53 +1,57 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faPen } from '@fortawesome/free-solid-svg-icons' import { debounce } from 'lodash' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faPen +} from '@fortawesome/free-solid-svg-icons' import { usePostStatusStore } from 'src/stores/post_status' -library.add(faPen) +library.add( + faPen +) -const HIDDEN_FOR_PAGES = new Set(['chats', 'chat', 'lists-edit']) +const HIDDEN_FOR_PAGES = new Set([ + 'chats', + 'chat', + 'lists-edit' +]) const MobilePostStatusButton = { - data() { + data () { return { hidden: false, scrollingDown: false, inputActive: false, oldScrollPos: 0, - amountScrolled: 0, + amountScrolled: 0 } }, - created() { + created () { if (this.autohideFloatingPostButton) { this.activateFloatingPostButtonAutohide() } window.addEventListener('resize', this.handleOSK) }, - unmounted() { + unmounted () { if (this.autohideFloatingPostButton) { this.deactivateFloatingPostButtonAutohide() } window.removeEventListener('resize', this.handleOSK) }, computed: { - isLoggedIn() { + isLoggedIn () { return !!this.$store.state.users.currentUser }, - isHidden() { - if (HIDDEN_FOR_PAGES.has(this.$route.name)) { - return true - } + isHidden () { + if (HIDDEN_FOR_PAGES.has(this.$route.name)) { return true } - return ( - this.autohideFloatingPostButton && (this.hidden || this.inputActive) - ) + return this.autohideFloatingPostButton && (this.hidden || this.inputActive) }, - isPersistent() { + isPersistent () { return !!this.$store.getters.mergedConfig.alwaysShowNewPostButton }, - autohideFloatingPostButton() { + autohideFloatingPostButton () { return !!this.$store.getters.mergedConfig.autohideFloatingPostButton - }, + } }, watch: { autohideFloatingPostButton: function (isEnabled) { @@ -56,21 +60,21 @@ const MobilePostStatusButton = { } else { this.deactivateFloatingPostButtonAutohide() } - }, + } }, methods: { - activateFloatingPostButtonAutohide() { + activateFloatingPostButtonAutohide () { window.addEventListener('scroll', this.handleScrollStart) window.addEventListener('scroll', this.handleScrollEnd) }, - deactivateFloatingPostButtonAutohide() { + deactivateFloatingPostButtonAutohide () { window.removeEventListener('scroll', this.handleScrollStart) window.removeEventListener('scroll', this.handleScrollEnd) }, - openPostForm() { + openPostForm () { usePostStatusStore().openPostStatusModal() }, - handleOSK() { + handleOSK () { // This is a big hack: we're guessing from changed window sizes if the // on-screen keyboard is active or not. This is only really important // for phones in portrait mode and it's more important to show the button @@ -90,28 +94,20 @@ const MobilePostStatusButton = { this.inputActive = false } }, - handleScrollStart: debounce( - function () { - if (window.scrollY > this.oldScrollPos) { - this.hidden = true - } else { - this.hidden = false - } - this.oldScrollPos = window.scrollY - }, - 100, - { leading: true, trailing: false }, - ), - - handleScrollEnd: debounce( - function () { + handleScrollStart: debounce(function () { + if (window.scrollY > this.oldScrollPos) { + this.hidden = true + } else { this.hidden = false - this.oldScrollPos = window.scrollY - }, - 100, - { leading: false, trailing: true }, - ), - }, + } + this.oldScrollPos = window.scrollY + }, 100, { leading: true, trailing: false }), + + handleScrollEnd: debounce(function () { + this.hidden = false + this.oldScrollPos = window.scrollY + }, 100, { leading: false, trailing: true }) + } } export default MobilePostStatusButton diff --git a/src/components/modal/modal.vue b/src/components/modal/modal.vue index a022f7427..032e7dbeb 100644 --- a/src/components/modal/modal.vue +++ b/src/components/modal/modal.vue @@ -13,27 +13,27 @@ diff --git a/src/components/modal/modals.style.js b/src/components/modal/modals.style.js index 9c8c279f7..1cb4a34a7 100644 --- a/src/components/modal/modals.style.js +++ b/src/components/modal/modals.style.js @@ -3,6 +3,8 @@ export default { selector: ['.modal-view', '#modal', '.shout-panel'], lazy: true, notEditable: true, - validInnerComponents: ['Panel'], - defaultRules: [], + validInnerComponents: [ + 'Panel' + ], + defaultRules: [] } diff --git a/src/components/moderation_tools/moderation_tools.js b/src/components/moderation_tools/moderation_tools.js index 3b8055ba6..bd57a353a 100644 --- a/src/components/moderation_tools/moderation_tools.js +++ b/src/components/moderation_tools/moderation_tools.js @@ -15,8 +15,10 @@ const SANDBOX = 'mrf_tag:sandbox' const QUARANTINE = 'mrf_tag:quarantine' const ModerationTools = { - props: ['user'], - data() { + props: [ + 'user' + ], + data () { return { tags: { FORCE_NSFW, @@ -25,124 +27,92 @@ const ModerationTools = { DISABLE_REMOTE_SUBSCRIPTION, DISABLE_ANY_SUBSCRIPTION, SANDBOX, - QUARANTINE, + QUARANTINE }, showDeleteUserDialog: false, - toggled: false, + toggled: false } }, components: { DialogModal, - Popover, + Popover }, computed: { - tagsSet() { + tagsSet () { return new Set(this.user.tags) }, - canGrantRole() { - return ( - this.user.is_local && - !this.user.deactivated && - this.$store.state.users.currentUser.role === 'admin' - ) + canGrantRole () { + return this.user.is_local && !this.user.deactivated && this.$store.state.users.currentUser.role === 'admin' }, - canChangeActivationState() { + canChangeActivationState () { return this.privileged('users_manage_activation_state') }, - canDeleteAccount() { + canDeleteAccount () { return this.privileged('users_delete') }, - canUseTagPolicy() { - return ( - this.$store.state.instance.tagPolicyAvailable && - this.privileged('users_manage_tags') - ) - }, + canUseTagPolicy () { + return this.$store.state.instance.tagPolicyAvailable && this.privileged('users_manage_tags') + } }, methods: { - hasTag(tagName) { + hasTag (tagName) { return this.tagsSet.has(tagName) }, - privileged(privilege) { + privileged (privilege) { return this.$store.state.users.currentUser.privileges.includes(privilege) }, - toggleTag(tag) { + toggleTag (tag) { const store = this.$store if (this.tagsSet.has(tag)) { - store.state.api.backendInteractor - .untagUser({ user: this.user, tag }) - .then((response) => { - if (!response.ok) { - return - } - store.commit('untagUser', { user: this.user, tag }) - }) + store.state.api.backendInteractor.untagUser({ user: this.user, tag }).then(response => { + if (!response.ok) { return } + store.commit('untagUser', { user: this.user, tag }) + }) } else { - store.state.api.backendInteractor - .tagUser({ user: this.user, tag }) - .then((response) => { - if (!response.ok) { - return - } - store.commit('tagUser', { user: this.user, tag }) - }) + store.state.api.backendInteractor.tagUser({ user: this.user, tag }).then(response => { + if (!response.ok) { return } + store.commit('tagUser', { user: this.user, tag }) + }) } }, - toggleRight(right) { + toggleRight (right) { const store = this.$store if (this.user.rights[right]) { - store.state.api.backendInteractor - .deleteRight({ user: this.user, right }) - .then((response) => { - if (!response.ok) { - return - } - store.commit('updateRight', { - user: this.user, - right, - value: false, - }) - }) + store.state.api.backendInteractor.deleteRight({ user: this.user, right }).then(response => { + if (!response.ok) { return } + store.commit('updateRight', { user: this.user, right, value: false }) + }) } else { - store.state.api.backendInteractor - .addRight({ user: this.user, right }) - .then((response) => { - if (!response.ok) { - return - } - store.commit('updateRight', { user: this.user, right, value: true }) - }) + store.state.api.backendInteractor.addRight({ user: this.user, right }).then(response => { + if (!response.ok) { return } + store.commit('updateRight', { user: this.user, right, value: true }) + }) } }, - toggleActivationStatus() { + toggleActivationStatus () { this.$store.dispatch('toggleActivationStatus', { user: this.user }) }, - deleteUserDialog(show) { + deleteUserDialog (show) { this.showDeleteUserDialog = show }, - deleteUser() { + deleteUser () { const store = this.$store const user = this.user const { id, name } = user - store.state.api.backendInteractor.deleteUser({ user }).then(() => { - this.$store.dispatch( - 'markStatusesAsDeleted', - (status) => user.id === status.user.id, - ) - const isProfile = - this.$route.name === 'external-user-profile' || - this.$route.name === 'user-profile' - const isTargetUser = - this.$route.params.name === name || this.$route.params.id === id - if (isProfile && isTargetUser) { - window.history.back() - } - }) + store.state.api.backendInteractor.deleteUser({ user }) + .then(() => { + this.$store.dispatch('markStatusesAsDeleted', status => user.id === status.user.id) + const isProfile = this.$route.name === 'external-user-profile' || this.$route.name === 'user-profile' + const isTargetUser = this.$route.params.name === name || this.$route.params.id === id + if (isProfile && isTargetUser) { + window.history.back() + } + }) }, - setToggled(value) { + setToggled (value) { this.toggled = value - }, - }, + } + } } export default ModerationTools diff --git a/src/components/mrf_transparency_panel/mrf_transparency_panel.js b/src/components/mrf_transparency_panel/mrf_transparency_panel.js index 2bd82f486..13cfb52ee 100644 --- a/src/components/mrf_transparency_panel/mrf_transparency_panel.js +++ b/src/components/mrf_transparency_panel/mrf_transparency_panel.js @@ -1,5 +1,5 @@ -import { get } from 'lodash' import { mapState } from 'vuex' +import { get } from 'lodash' /** * This is for backwards compatibility. We originally didn't recieve @@ -8,7 +8,7 @@ import { mapState } from 'vuex' * to add an extra "info" key. */ const toInstanceReasonObject = (instances, info, key) => { - return instances.map((instance) => { + return instances.map(instance => { if (info[key] && info[key][instance] && info[key][instance].reason) { return { instance, reason: info[key][instance].reason } } @@ -19,82 +19,56 @@ const toInstanceReasonObject = (instances, info, key) => { const MRFTransparencyPanel = { computed: { ...mapState({ - federationPolicy: (state) => get(state, 'instance.federationPolicy'), - mrfPolicies: (state) => - get(state, 'instance.federationPolicy.mrf_policies', []), - quarantineInstances: (state) => - toInstanceReasonObject( - get(state, 'instance.federationPolicy.quarantined_instances', []), - get( - state, - 'instance.federationPolicy.quarantined_instances_info', - [], - ), - 'quarantined_instances', - ), - acceptInstances: (state) => - toInstanceReasonObject( - get(state, 'instance.federationPolicy.mrf_simple.accept', []), - get(state, 'instance.federationPolicy.mrf_simple_info', []), - 'accept', - ), - rejectInstances: (state) => - toInstanceReasonObject( - get(state, 'instance.federationPolicy.mrf_simple.reject', []), - get(state, 'instance.federationPolicy.mrf_simple_info', []), - 'reject', - ), - ftlRemovalInstances: (state) => - toInstanceReasonObject( - get( - state, - 'instance.federationPolicy.mrf_simple.federated_timeline_removal', - [], - ), - get(state, 'instance.federationPolicy.mrf_simple_info', []), - 'federated_timeline_removal', - ), - mediaNsfwInstances: (state) => - toInstanceReasonObject( - get(state, 'instance.federationPolicy.mrf_simple.media_nsfw', []), - get(state, 'instance.federationPolicy.mrf_simple_info', []), - 'media_nsfw', - ), - mediaRemovalInstances: (state) => - toInstanceReasonObject( - get(state, 'instance.federationPolicy.mrf_simple.media_removal', []), - get(state, 'instance.federationPolicy.mrf_simple_info', []), - 'media_removal', - ), - keywordsFtlRemoval: (state) => - get( - state, - 'instance.federationPolicy.mrf_keyword.federated_timeline_removal', - [], - ), - keywordsReject: (state) => - get(state, 'instance.federationPolicy.mrf_keyword.reject', []), - keywordsReplace: (state) => - get(state, 'instance.federationPolicy.mrf_keyword.replace', []), + federationPolicy: state => get(state, 'instance.federationPolicy'), + mrfPolicies: state => get(state, 'instance.federationPolicy.mrf_policies', []), + quarantineInstances: state => toInstanceReasonObject( + get(state, 'instance.federationPolicy.quarantined_instances', []), + get(state, 'instance.federationPolicy.quarantined_instances_info', []), + 'quarantined_instances' + ), + acceptInstances: state => toInstanceReasonObject( + get(state, 'instance.federationPolicy.mrf_simple.accept', []), + get(state, 'instance.federationPolicy.mrf_simple_info', []), + 'accept' + ), + rejectInstances: state => toInstanceReasonObject( + get(state, 'instance.federationPolicy.mrf_simple.reject', []), + get(state, 'instance.federationPolicy.mrf_simple_info', []), + 'reject' + ), + ftlRemovalInstances: state => toInstanceReasonObject( + get(state, 'instance.federationPolicy.mrf_simple.federated_timeline_removal', []), + get(state, 'instance.federationPolicy.mrf_simple_info', []), + 'federated_timeline_removal' + ), + mediaNsfwInstances: state => toInstanceReasonObject( + get(state, 'instance.federationPolicy.mrf_simple.media_nsfw', []), + get(state, 'instance.federationPolicy.mrf_simple_info', []), + 'media_nsfw' + ), + mediaRemovalInstances: state => toInstanceReasonObject( + get(state, 'instance.federationPolicy.mrf_simple.media_removal', []), + get(state, 'instance.federationPolicy.mrf_simple_info', []), + 'media_removal' + ), + keywordsFtlRemoval: state => get(state, 'instance.federationPolicy.mrf_keyword.federated_timeline_removal', []), + keywordsReject: state => get(state, 'instance.federationPolicy.mrf_keyword.reject', []), + keywordsReplace: state => get(state, 'instance.federationPolicy.mrf_keyword.replace', []) }), - hasInstanceSpecificPolicies() { - return ( - this.quarantineInstances.length || + hasInstanceSpecificPolicies () { + return this.quarantineInstances.length || this.acceptInstances.length || this.rejectInstances.length || this.ftlRemovalInstances.length || this.mediaNsfwInstances.length || this.mediaRemovalInstances.length - ) }, - hasKeywordPolicies() { - return ( - this.keywordsFtlRemoval.length || + hasKeywordPolicies () { + return this.keywordsFtlRemoval.length || this.keywordsReject.length || this.keywordsReplace.length - ) - }, - }, + } + } } export default MRFTransparencyPanel diff --git a/src/components/mute_card/mute_card.js b/src/components/mute_card/mute_card.js index aaad96863..895586888 100644 --- a/src/components/mute_card/mute_card.js +++ b/src/components/mute_card/mute_card.js @@ -1,41 +1,39 @@ -import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue' import BasicUserCard from '../basic_user_card/basic_user_card.vue' +import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue' const MuteCard = { props: ['userId'], computed: { - user() { + user () { return this.$store.getters.findUser(this.userId) }, - relationship() { + relationship () { return this.$store.getters.relationship(this.userId) }, - muted() { + muted () { return this.relationship.muting }, - muteExpiryAvailable() { + muteExpiryAvailable () { return this.user.mute_expires_at !== undefined }, - muteExpiry() { + muteExpiry () { return this.user.mute_expires_at == null ? this.$t('user_card.mute_expires_forever') - : this.$t('user_card.mute_expires_at', [ - new Date(this.user.mute_expires_at).toLocaleString(), - ]) - }, + : this.$t('user_card.mute_expires_at', [new Date(this.user.mute_expires_at).toLocaleString()]) + } }, components: { BasicUserCard, - UserTimedFilterModal, + UserTimedFilterModal }, methods: { - unmuteUser() { + unmuteUser () { this.$store.dispatch('unmuteUser', this.userId) }, - muteUser() { + muteUser () { this.$refs.timedMuteDialog.optionallyPrompt() - }, - }, + } + } } export default MuteCard diff --git a/src/components/nav_panel/nav_panel.js b/src/components/nav_panel/nav_panel.js index 77bfa0ff5..a155abe0c 100644 --- a/src/components/nav_panel/nav_panel.js +++ b/src/components/nav_panel/nav_panel.js @@ -1,31 +1,33 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { - faBell, - faBookmark, - faBullhorn, - faChevronDown, - faChevronUp, - faCity, - faComments, - faEnvelope, - faFilePen, - faGlobe, - faInfoCircle, - faList, - faStream, - faUsers, -} from '@fortawesome/free-solid-svg-icons' -import { mapState as mapPiniaState } from 'pinia' import BookmarkFoldersMenuContent from 'src/components/bookmark_folders_menu/bookmark_folders_menu_content.vue' -import Checkbox from 'src/components/checkbox/checkbox.vue' import ListsMenuContent from 'src/components/lists_menu/lists_menu_content.vue' +import { mapState, mapGetters } from 'vuex' +import { mapState as mapPiniaState } from 'pinia' +import { TIMELINES, ROOT_ITEMS } from 'src/components/navigation/navigation.js' import { filterNavigation } from 'src/components/navigation/filter.js' -import { ROOT_ITEMS, TIMELINES } from 'src/components/navigation/navigation.js' import NavigationEntry from 'src/components/navigation/navigation_entry.vue' import NavigationPins from 'src/components/navigation/navigation_pins.vue' +import Checkbox from 'src/components/checkbox/checkbox.vue' + import { useAnnouncementsStore } from 'src/stores/announcements' import { useServerSideStorageStore } from 'src/stores/serverSideStorage' -import { mapGetters, mapState } from 'vuex' + +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faUsers, + faGlobe, + faCity, + faBookmark, + faEnvelope, + faChevronDown, + faChevronUp, + faComments, + faBell, + faInfoCircle, + faStream, + faList, + faBullhorn, + faFilePen +} from '@fortawesome/free-solid-svg-icons' library.add( faUsers, @@ -41,92 +43,80 @@ library.add( faStream, faList, faBullhorn, - faFilePen, + faFilePen ) const NavPanel = { props: ['forceExpand', 'forceEditMode'], + created () { + }, components: { BookmarkFoldersMenuContent, ListsMenuContent, NavigationEntry, NavigationPins, - Checkbox, + Checkbox }, - data() { + data () { return { editMode: false, showTimelines: false, showLists: false, showBookmarkFolders: false, - timelinesList: Object.entries(TIMELINES).map(([k, v]) => ({ - ...v, - name: k, - })), - rootList: Object.entries(ROOT_ITEMS).map(([k, v]) => ({ ...v, name: k })), + timelinesList: Object.entries(TIMELINES).map(([k, v]) => ({ ...v, name: k })), + rootList: Object.entries(ROOT_ITEMS).map(([k, v]) => ({ ...v, name: k })) } }, methods: { - toggleTimelines() { + toggleTimelines () { this.showTimelines = !this.showTimelines }, - toggleLists() { + toggleLists () { this.showLists = !this.showLists }, - toggleBookmarkFolders() { + toggleBookmarkFolders () { this.showBookmarkFolders = !this.showBookmarkFolders }, - toggleEditMode() { + toggleEditMode () { this.editMode = !this.editMode }, - toggleCollapse() { - useServerSideStorageStore().setPreference({ - path: 'simple.collapseNav', - value: !this.collapsed, - }) + toggleCollapse () { + useServerSideStorageStore().setPreference({ path: 'simple.collapseNav', value: !this.collapsed }) useServerSideStorageStore().pushServerSideStorage() }, - isPinned(item) { + isPinned (item) { return this.pinnedItems.has(item) }, - togglePin(item) { + togglePin (item) { if (this.isPinned(item)) { - useServerSideStorageStore().removeCollectionPreference({ - path: 'collections.pinnedNavItems', - value: item, - }) + useServerSideStorageStore().removeCollectionPreference({ path: 'collections.pinnedNavItems', value: item }) } else { - useServerSideStorageStore().addCollectionPreference({ - path: 'collections.pinnedNavItems', - value: item, - }) + useServerSideStorageStore().addCollectionPreference({ path: 'collections.pinnedNavItems', value: item }) } useServerSideStorageStore().pushServerSideStorage() - }, + } }, computed: { ...mapPiniaState(useAnnouncementsStore, { unreadAnnouncementCount: 'unreadAnnouncementCount', - supportsAnnouncements: (store) => store.supportsAnnouncements, + supportsAnnouncements: store => store.supportsAnnouncements }), ...mapPiniaState(useServerSideStorageStore, { - collapsed: (store) => store.prefsStorage.simple.collapseNav, - pinnedItems: (store) => - new Set(store.prefsStorage.collections.pinnedNavItems), + collapsed: store => store.prefsStorage.simple.collapseNav, + pinnedItems: store => new Set(store.prefsStorage.collections.pinnedNavItems) }), ...mapState({ - currentUser: (state) => state.users.currentUser, - followRequestCount: (state) => state.api.followRequests.length, - privateMode: (state) => state.instance.private, - federating: (state) => state.instance.federating, - pleromaChatMessagesAvailable: (state) => - state.instance.pleromaChatMessagesAvailable, - bookmarkFolders: (state) => - state.instance.pleromaBookmarkFoldersAvailable, - bubbleTimeline: (state) => state.instance.localBubbleInstances.length > 0, + currentUser: state => state.users.currentUser, + followRequestCount: state => state.api.followRequests.length, + privateMode: state => state.instance.private, + federating: state => state.instance.federating, + pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable, + bookmarkFolders: state => state.instance.pleromaBookmarkFoldersAvailable, + bubbleTimeline: state => state.instance.localBubbleInstances.length > 0 }), - timelinesItems() { + timelinesItems () { return filterNavigation( - Object.entries({ ...TIMELINES }) + Object + .entries({ ...TIMELINES }) // do not show in timeliens list since it's in a better place now .filter(([key]) => key !== 'bookmarks') .map(([k, v]) => ({ ...v, name: k })), @@ -137,13 +127,15 @@ const NavPanel = { isPrivate: this.privateMode, currentUser: this.currentUser, supportsBubbleTimeline: this.bubbleTimeline, - supportsBookmarkFolders: this.bookmarkFolders, - }, + supportsBookmarkFolders: this.bookmarkFolders + } ) }, - rootItems() { + rootItems () { return filterNavigation( - Object.entries({ ...ROOT_ITEMS }).map(([k, v]) => ({ ...v, name: k })), + Object + .entries({ ...ROOT_ITEMS }) + .map(([k, v]) => ({ ...v, name: k })), { hasChats: this.pleromaChatMessagesAvailable, hasAnnouncements: this.supportsAnnouncements, @@ -151,12 +143,12 @@ const NavPanel = { isPrivate: this.privateMode, currentUser: this.currentUser, supportsBubbleTimeline: this.bubbleTimeline, - supportsBookmarkFolders: this.bookmarkFolders, - }, + supportsBookmarkFolders: this.bookmarkFolders + } ) }, - ...mapGetters(['unreadChatCount']), - }, + ...mapGetters(['unreadChatCount']) + } } export default NavPanel diff --git a/src/components/navigation/filter.js b/src/components/navigation/filter.js index 0255db6aa..54abb67b4 100644 --- a/src/components/navigation/filter.js +++ b/src/components/navigation/filter.js @@ -1,50 +1,39 @@ -export const filterNavigation = ( - list = [], - { - hasChats, - hasAnnouncements, - isFederating, - isPrivate, - currentUser, - supportsBookmarkFolders, - supportsBubbleTimeline, - }, -) => { +export const filterNavigation = (list = [], { + hasChats, + hasAnnouncements, + isFederating, + isPrivate, + currentUser, + supportsBookmarkFolders, + supportsBubbleTimeline +}) => { return list.filter(({ criteria, anon, anonRoute }) => { const set = new Set(criteria || []) if (!isFederating && set.has('federating')) return false if (!currentUser && isPrivate && set.has('!private')) return false if (!currentUser && !(anon || anonRoute)) return false - if ((!currentUser || !currentUser.locked) && set.has('lockedUser')) - return false + if ((!currentUser || !currentUser.locked) && set.has('lockedUser')) return false if (!hasChats && set.has('chats')) return false if (!hasAnnouncements && set.has('announcements')) return false - if (!supportsBubbleTimeline && set.has('supportsBubbleTimeline')) - return false - if (!supportsBookmarkFolders && set.has('supportsBookmarkFolders')) - return false - if (supportsBookmarkFolders && set.has('!supportsBookmarkFolders')) - return false + if (!supportsBubbleTimeline && set.has('supportsBubbleTimeline')) return false + if (!supportsBookmarkFolders && set.has('supportsBookmarkFolders')) return false + if (supportsBookmarkFolders && set.has('!supportsBookmarkFolders')) return false return true }) } -export const getListEntries = (store) => - store.allLists.map((list) => ({ - name: 'list-' + list.id, - routeObject: { name: 'lists-timeline', params: { id: list.id } }, - labelRaw: list.title, - iconLetter: list.title[0], - })) +export const getListEntries = store => store.allLists.map(list => ({ + name: 'list-' + list.id, + routeObject: { name: 'lists-timeline', params: { id: list.id } }, + labelRaw: list.title, + iconLetter: list.title[0] +})) -export const getBookmarkFolderEntries = (store) => - store.allFolders - ? store.allFolders.map((folder) => ({ - name: 'bookmark-folder-' + folder.id, - routeObject: { name: 'bookmark-folder', params: { id: folder.id } }, - labelRaw: folder.name, - iconEmoji: folder.emoji, - iconEmojiUrl: folder.emoji_url, - iconLetter: folder.name[0], - })) - : [] +export const getBookmarkFolderEntries = store => store.allFolders ? store.allFolders.map(folder => ({ + name: 'bookmark-folder-' + folder.id, + routeObject: { name: 'bookmark-folder', params: { id: folder.id } }, + labelRaw: folder.name, + iconEmoji: folder.emoji, + iconEmojiUrl: folder.emoji_url, + iconLetter: folder.name[0] +})) : [] diff --git a/src/components/navigation/navigation.js b/src/components/navigation/navigation.js index 66fb0d347..d1c2b6763 100644 --- a/src/components/navigation/navigation.js +++ b/src/components/navigation/navigation.js @@ -4,39 +4,42 @@ export const USERNAME_ROUTES = new Set([ 'interactions', 'notifications', 'chat', - 'chats', + 'chats' ]) // routes that take :name property -export const NAME_ROUTES = new Set(['user-profile', 'legacy-user-profile']) +export const NAME_ROUTES = new Set([ + 'user-profile', + 'legacy-user-profile' +]) export const TIMELINES = { home: { route: 'friends', icon: 'home', label: 'nav.home_timeline', - criteria: ['!private'], + criteria: ['!private'] }, public: { route: 'public-timeline', anon: true, icon: 'users', label: 'nav.public_tl', - criteria: ['!private'], + criteria: ['!private'] }, bubble: { route: 'bubble', anon: true, icon: 'city', label: 'nav.bubble', - criteria: ['!private', 'federating', 'supportsBubbleTimeline'], + criteria: ['!private', 'federating', 'supportsBubbleTimeline'] }, twkn: { route: 'public-external-timeline', anon: true, icon: 'globe', label: 'nav.twkn', - criteria: ['!private', 'federating'], + criteria: ['!private', 'federating'] }, // bookmarks are still technically a timeline so we should show it in the dropdown bookmarks: { @@ -47,13 +50,13 @@ export const TIMELINES = { favorites: { routeObject: { name: 'user-profile', query: { tab: 'favorites' } }, icon: 'star', - label: 'user_card.favorites', + label: 'user_card.favorites' }, dms: { route: 'dms', icon: 'envelope', - label: 'nav.dms', - }, + label: 'nav.dms' + } } export const ROOT_ITEMS = { @@ -64,12 +67,12 @@ export const ROOT_ITEMS = { // shows bookmarks entry in a better suited location // hides it when bookmark folders are supported since // we show custom component instead of it - criteria: ['!supportsBookmarkFolders'], + criteria: ['!supportsBookmarkFolders'] }, interactions: { route: 'interactions', icon: 'bell', - label: 'nav.interactions', + label: 'nav.interactions' }, chats: { route: 'chats', @@ -77,7 +80,7 @@ export const ROOT_ITEMS = { label: 'nav.chats', badgeStyle: 'notification', badgeGetter: 'unreadChatCount', - criteria: ['chats'], + criteria: ['chats'] }, friendRequests: { route: 'friend-requests', @@ -85,13 +88,13 @@ export const ROOT_ITEMS = { label: 'nav.friend_requests', badgeStyle: 'notification', criteria: ['lockedUser'], - badgeGetter: 'followRequestCount', + badgeGetter: 'followRequestCount' }, about: { route: 'about', anon: true, icon: 'info-circle', - label: 'nav.about', + label: 'nav.about' }, announcements: { route: 'announcements', @@ -100,18 +103,18 @@ export const ROOT_ITEMS = { store: 'announcements', badgeStyle: 'notification', badgeGetter: 'unreadAnnouncementCount', - criteria: ['announcements'], + criteria: ['announcements'] }, drafts: { route: 'drafts', icon: 'file-pen', label: 'nav.drafts', badgeStyle: 'neutral', - badgeGetter: 'draftCount', - }, + badgeGetter: 'draftCount' + } } -export function routeTo(item, currentUser) { +export function routeTo (item, currentUser) { if (!item.route && !item.routeObject) return null let route @@ -119,7 +122,7 @@ export function routeTo(item, currentUser) { if (item.routeObject) { route = item.routeObject } else { - route = { name: item.anon || currentUser ? item.route : item.anonRoute } + route = { name: (item.anon || currentUser) ? item.route : item.anonRoute } } if (USERNAME_ROUTES.has(route.name)) { diff --git a/src/components/navigation/navigation_entry.js b/src/components/navigation/navigation_entry.js index ae0bbd305..11db1c9e3 100644 --- a/src/components/navigation/navigation_entry.js +++ b/src/components/navigation/navigation_entry.js @@ -1,54 +1,48 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faThumbtack } from '@fortawesome/free-solid-svg-icons' -import { mapState as mapPiniaState, mapStores } from 'pinia' +import { mapState } from 'vuex' import { routeTo } from 'src/components/navigation/navigation.js' import OptionalRouterLink from 'src/components/optional_router_link/optional_router_link.vue' +import { library } from '@fortawesome/fontawesome-svg-core' +import { faThumbtack } from '@fortawesome/free-solid-svg-icons' +import { mapStores, mapState as mapPiniaState } from 'pinia' + import { useAnnouncementsStore } from 'src/stores/announcements' import { useServerSideStorageStore } from 'src/stores/serverSideStorage' -import { mapState } from 'vuex' library.add(faThumbtack) const NavigationEntry = { props: ['item', 'showPin'], components: { - OptionalRouterLink, + OptionalRouterLink }, methods: { - isPinned(value) { + isPinned (value) { return this.pinnedItems.has(value) }, - togglePin(value) { + togglePin (value) { if (this.isPinned(value)) { - useServerSideStorageStore().removeCollectionPreference({ - path: 'collections.pinnedNavItems', - value, - }) + useServerSideStorageStore().removeCollectionPreference({ path: 'collections.pinnedNavItems', value }) } else { - useServerSideStorageStore().addCollectionPreference({ - path: 'collections.pinnedNavItems', - value, - }) + useServerSideStorageStore().addCollectionPreference({ path: 'collections.pinnedNavItems', value }) } useServerSideStorageStore().pushServerSideStorage() - }, + } }, computed: { - routeTo() { + routeTo () { return routeTo(this.item, this.currentUser) }, - getters() { + getters () { return this.$store.getters }, ...mapStores(useAnnouncementsStore), ...mapState({ - currentUser: (state) => state.users.currentUser, + currentUser: state => state.users.currentUser }), ...mapPiniaState(useServerSideStorageStore, { - pinnedItems: (store) => - new Set(store.prefsStorage.collections.pinnedNavItems), + pinnedItems: store => new Set(store.prefsStorage.collections.pinnedNavItems) }), - }, + } } export default NavigationEntry diff --git a/src/components/navigation/navigation_pins.js b/src/components/navigation/navigation_pins.js index 5bc349d01..f9a900fc6 100644 --- a/src/components/navigation/navigation_pins.js +++ b/src/components/navigation/navigation_pins.js @@ -1,33 +1,27 @@ +import { mapState } from 'vuex' +import { mapState as mapPiniaState } from 'pinia' +import { TIMELINES, ROOT_ITEMS, routeTo } from 'src/components/navigation/navigation.js' +import { getBookmarkFolderEntries, getListEntries, filterNavigation } from 'src/components/navigation/filter.js' + +import StillImage from 'src/components/still-image/still-image.vue' + import { library } from '@fortawesome/fontawesome-svg-core' import { - faBell, - faBookmark, - faCity, - faComments, - faEnvelope, - faGlobe, - faInfoCircle, - faList, - faStream, faUsers, + faGlobe, + faCity, + faBookmark, + faEnvelope, + faComments, + faBell, + faInfoCircle, + faStream, + faList } from '@fortawesome/free-solid-svg-icons' -import { mapState as mapPiniaState } from 'pinia' -import { - filterNavigation, - getBookmarkFolderEntries, - getListEntries, -} from 'src/components/navigation/filter.js' -import { - ROOT_ITEMS, - routeTo, - TIMELINES, -} from 'src/components/navigation/navigation.js' -import StillImage from 'src/components/still-image/still-image.vue' +import { useListsStore } from 'src/stores/lists' import { useAnnouncementsStore } from 'src/stores/announcements' import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders' -import { useListsStore } from 'src/stores/lists' import { useServerSideStorageStore } from 'src/stores/serverSideStorage' -import { mapState } from 'vuex' library.add( faUsers, @@ -39,74 +33,72 @@ library.add( faBell, faInfoCircle, faStream, - faList, + faList ) const NavPanel = { props: ['limit'], methods: { - getRouteTo(item) { + getRouteTo (item) { return routeTo(item, this.currentUser) - }, + } }, components: { - StillImage, + StillImage }, computed: { - getters() { + getters () { return this.$store.getters }, ...mapPiniaState(useListsStore, { - lists: getListEntries, + lists: getListEntries }), ...mapPiniaState(useAnnouncementsStore, { - supportsAnnouncements: (store) => store.supportsAnnouncements, + supportsAnnouncements: store => store.supportsAnnouncements }), ...mapPiniaState(useBookmarkFoldersStore, { bookmarks: getBookmarkFolderEntries, }), ...mapPiniaState(useServerSideStorageStore, { - pinnedItems: (store) => - new Set(store.prefsStorage.collections.pinnedNavItems), + pinnedItems: store => new Set(store.prefsStorage.collections.pinnedNavItems) }), ...mapState({ - currentUser: (state) => state.users.currentUser, - followRequestCount: (state) => state.api.followRequests.length, - privateMode: (state) => state.instance.private, - federating: (state) => state.instance.federating, - pleromaChatMessagesAvailable: (state) => - state.instance.pleromaChatMessagesAvailable, - bubbleTimeline: (state) => state.instance.localBubbleInstances.length > 0, + currentUser: state => state.users.currentUser, + followRequestCount: state => state.api.followRequests.length, + privateMode: state => state.instance.private, + federating: state => state.instance.federating, + pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable, + bubbleTimeline: state => state.instance.localBubbleInstances.length > 0 }), - pinnedList() { + pinnedList () { if (!this.currentUser) { - return filterNavigation( - [ - { ...TIMELINES.public, name: 'public' }, - { ...TIMELINES.twkn, name: 'twkn' }, - { ...ROOT_ITEMS.about, name: 'about' }, - ], - { - hasChats: this.pleromaChatMessagesAvailable, - hasAnnouncements: this.supportsAnnouncements, - isFederating: this.federating, - isPrivate: this.privateMode, - currentUser: this.currentUser, - supportsBubbleTimeline: this.bubbleTimeline, - supportsBookmarkFolders: this.bookmarks, - }, - ) + return filterNavigation([ + { ...TIMELINES.public, name: 'public' }, + { ...TIMELINES.twkn, name: 'twkn' }, + { ...ROOT_ITEMS.about, name: 'about' } + ], + { + hasChats: this.pleromaChatMessagesAvailable, + hasAnnouncements: this.supportsAnnouncements, + isFederating: this.federating, + isPrivate: this.privateMode, + currentUser: this.currentUser, + supportsBubbleTimeline: this.bubbleTimeline, + supportsBookmarkFolders: this.bookmarks + }) } return filterNavigation( [ - ...Object.entries({ ...TIMELINES }) + ...Object + .entries({ ...TIMELINES }) .filter(([k]) => this.pinnedItems.has(k)) .map(([k, v]) => ({ ...v, name: k })), ...this.lists.filter((k) => this.pinnedItems.has(k.name)), ...this.bookmarks.filter((k) => this.pinnedItems.has(k.name)), - ...Object.entries({ ...ROOT_ITEMS }) + ...Object + .entries({ ...ROOT_ITEMS }) .filter(([k]) => this.pinnedItems.has(k)) - .map(([k, v]) => ({ ...v, name: k })), + .map(([k, v]) => ({ ...v, name: k })) ], { hasChats: this.pleromaChatMessagesAvailable, @@ -115,11 +107,11 @@ const NavPanel = { supportsBookmarkFolders: this.bookmarks, isFederating: this.federating, isPrivate: this.privateMode, - currentUser: this.currentUser, - }, + currentUser: this.currentUser + } ).slice(0, this.limit) - }, - }, + } + } } export default NavPanel diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index 20285168d..3edf21de7 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -1,33 +1,30 @@ +import StatusContent from '../status_content/status_content.vue' +import { mapState } from 'vuex' +import Status from '../status/status.vue' +import UserAvatar from '../user_avatar/user_avatar.vue' +import UserCard from '../user_card/user_card.vue' +import Timeago from '../timeago/timeago.vue' +import Report from '../report/report.vue' +import UserLink from '../user_link/user_link.vue' +import RichContent from 'src/components/rich_content/rich_content.jsx' +import UserPopover from '../user_popover/user_popover.vue' +import ConfirmModal from '../confirm_modal/confirm_modal.vue' +import { isStatusNotification } from '../../services/notification_utils/notification_utils.js' +import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js' +import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import { library } from '@fortawesome/fontawesome-svg-core' import { faCheck, - faCompressAlt, - faExpandAlt, - faEyeSlash, - faRetweet, - faStar, - faSuitcaseRolling, faTimes, - faUser, + faStar, + faRetweet, faUserPlus, + faEyeSlash, + faUser, + faSuitcaseRolling, + faExpandAlt, + faCompressAlt } from '@fortawesome/free-solid-svg-icons' -import RichContent from 'src/components/rich_content/rich_content.jsx' -import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' -import { mapState } from 'vuex' -import { isStatusNotification } from '../../services/notification_utils/notification_utils.js' -import { - highlightClass, - highlightStyle, -} from '../../services/user_highlighter/user_highlighter.js' -import ConfirmModal from '../confirm_modal/confirm_modal.vue' -import Report from '../report/report.vue' -import Status from '../status/status.vue' -import StatusContent from '../status_content/status_content.vue' -import Timeago from '../timeago/timeago.vue' -import UserAvatar from '../user_avatar/user_avatar.vue' -import UserCard from '../user_card/user_card.vue' -import UserLink from '../user_link/user_link.vue' -import UserPopover from '../user_popover/user_popover.vue' library.add( faCheck, @@ -39,17 +36,17 @@ library.add( faEyeSlash, faSuitcaseRolling, faExpandAlt, - faCompressAlt, + faCompressAlt ) const Notification = { - data() { + data () { return { selecting: false, statusExpanded: false, unmuted: false, showingApproveConfirmDialog: false, - showingDenyConfirmDialog: false, + showingDenyConfirmDialog: false } }, props: ['notification'], @@ -64,158 +61,141 @@ const Notification = { RichContent, UserPopover, UserLink, - ConfirmModal, + ConfirmModal }, - mounted() { + mounted () { document.addEventListener('selectionchange', this.onContentSelect) }, - unmounted() { + unmounted () { document.removeEventListener('selectionchange', this.onContentSelect) }, methods: { - toggleStatusExpanded() { + toggleStatusExpanded () { if (!this.expandable) return this.statusExpanded = !this.statusExpanded }, - onContentSelect() { + onContentSelect () { const { isCollapsed, anchorNode, offsetNode } = document.getSelection() if (isCollapsed) { this.selecting = false return } - const within = - this.$refs.root.contains(anchorNode) || - this.$refs.root.contains(offsetNode) + const within = this.$refs.root.contains(anchorNode) || this.$refs.root.contains(offsetNode) if (within) { this.selecting = true } else { this.selecting = false } }, - onContentClick(e) { - if ( - !this.selecting && - !e.target.closest('a') && - !e.target.closest('button') - ) { + onContentClick (e) { + if (!this.selecting && !e.target.closest('a') && !e.target.closest('button')) { this.toggleStatusExpanded() } }, - generateUserProfileLink(user) { - return generateProfileLink( - user.id, - user.screen_name, - this.$store.state.instance.restrictedNicknames, - ) + generateUserProfileLink (user) { + return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames) }, - getUser(notification) { + getUser (notification) { return this.$store.state.users.usersObject[notification.from_profile.id] }, - interacted() { + interacted () { this.$emit('interacted') }, - toggleMute() { + toggleMute () { this.unmuted = !this.unmuted }, - showApproveConfirmDialog() { + showApproveConfirmDialog () { this.showingApproveConfirmDialog = true }, - hideApproveConfirmDialog() { + hideApproveConfirmDialog () { this.showingApproveConfirmDialog = false }, - showDenyConfirmDialog() { + showDenyConfirmDialog () { this.showingDenyConfirmDialog = true }, - hideDenyConfirmDialog() { + hideDenyConfirmDialog () { this.showingDenyConfirmDialog = false }, - approveUser() { + approveUser () { if (this.shouldConfirmApprove) { this.showApproveConfirmDialog() } else { this.doApprove() } }, - doApprove() { + doApprove () { this.$emit('interacted') this.$store.state.api.backendInteractor.approveUser({ id: this.user.id }) this.$store.dispatch('removeFollowRequest', this.user) - this.$store.dispatch('markSingleNotificationAsSeen', { - id: this.notification.id, - }) + this.$store.dispatch('markSingleNotificationAsSeen', { id: this.notification.id }) this.$store.dispatch('updateNotification', { id: this.notification.id, - updater: (notification) => { + updater: notification => { notification.type = 'follow' - }, + } }) this.hideApproveConfirmDialog() }, - denyUser() { + denyUser () { if (this.shouldConfirmDeny) { this.showDenyConfirmDialog() } else { this.doDeny() } }, - doDeny() { + doDeny () { this.$emit('interacted') - this.$store.state.api.backendInteractor - .denyUser({ id: this.user.id }) + this.$store.state.api.backendInteractor.denyUser({ id: this.user.id }) .then(() => { - this.$store.dispatch('dismissNotificationLocal', { - id: this.notification.id, - }) + this.$store.dispatch('dismissNotificationLocal', { id: this.notification.id }) this.$store.dispatch('removeFollowRequest', this.user) }) this.hideDenyConfirmDialog() - }, + } }, computed: { - userClass() { + userClass () { return highlightClass(this.notification.from_profile) }, - userStyle() { + userStyle () { const highlight = this.$store.getters.mergedConfig.highlight const user = this.notification.from_profile return highlightStyle(highlight[user.screen_name]) }, - expandable() { - return new Set(['like', 'pleroma:emoji_reaction', 'repeat', 'poll']).has( - this.notification.type, - ) + expandable () { + return (new Set(['like', 'pleroma:emoji_reaction', 'repeat'])).has(this.notification.type) }, - user() { + user () { return this.$store.getters.findUser(this.notification.from_profile.id) }, - userProfileLink() { + userProfileLink () { return this.generateUserProfileLink(this.user) }, - targetUser() { + targetUser () { return this.$store.getters.findUser(this.notification.target.id) }, - targetUserProfileLink() { + targetUserProfileLink () { return this.generateUserProfileLink(this.targetUser) }, - needMute() { + needMute () { return this.$store.getters.relationship(this.user.id).muting }, - isStatusNotification() { + isStatusNotification () { return isStatusNotification(this.notification.type) }, - mergedConfig() { + mergedConfig () { return this.$store.getters.mergedConfig }, - shouldConfirmApprove() { + shouldConfirmApprove () { return this.mergedConfig.modalOnApproveFollow }, - shouldConfirmDeny() { + shouldConfirmDeny () { return this.mergedConfig.modalOnDenyFollow }, ...mapState({ - currentUser: (state) => state.users.currentUser, - }), - }, + currentUser: state => state.users.currentUser + }) + } } export default Notification diff --git a/src/components/notification/notification.style.js b/src/components/notification/notification.style.js index 49e28cf2e..05c1f6f23 100644 --- a/src/components/notification/notification.style.js +++ b/src/components/notification/notification.style.js @@ -7,7 +7,7 @@ export default { 'Icon', 'Border', 'Avatar', - 'PollGraph', + 'PollGraph' ], - defaultRules: [], + defaultRules: [] } diff --git a/src/components/notifications/notification_filters.vue b/src/components/notifications/notification_filters.vue index 674acdec5..0b740ea0a 100644 --- a/src/components/notifications/notification_filters.vue +++ b/src/components/notifications/notification_filters.vue @@ -106,29 +106,31 @@ diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index 236d7ddf5..ced97d57f 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -1,28 +1,28 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { - faArrowUp, - faCircleNotch, - faMinus, -} from '@fortawesome/free-solid-svg-icons' -import { mapState } from 'pinia' -import { useAnnouncementsStore } from 'src/stores/announcements' -import { useInterfaceStore } from 'src/stores/interface' import { computed } from 'vue' import { mapGetters } from 'vuex' -import FaviconService from '../../services/favicon_service/favicon_service.js' -import { - ACTIONABLE_NOTIFICATION_TYPES, - countExtraNotifications, - filteredNotificationsFromStore, - notificationsFromStore, - unseenNotificationsFromStore, -} from '../../services/notification_utils/notification_utils.js' -import notificationsFetcher from '../../services/notifications_fetcher/notifications_fetcher.service.js' -import ExtraNotifications from '../extra_notifications/extra_notifications.vue' +import { mapState } from 'pinia' import Notification from '../notification/notification.vue' +import ExtraNotifications from '../extra_notifications/extra_notifications.vue' import NotificationFilters from './notification_filters.vue' +import notificationsFetcher from '../../services/notifications_fetcher/notifications_fetcher.service.js' +import { + notificationsFromStore, + filteredNotificationsFromStore, + unseenNotificationsFromStore, + countExtraNotifications, + ACTIONABLE_NOTIFICATION_TYPES +} from '../../services/notification_utils/notification_utils.js' +import FaviconService from '../../services/favicon_service/favicon_service.js' +import { library } from '@fortawesome/fontawesome-svg-core' +import { faCircleNotch, faArrowUp, faMinus } from '@fortawesome/free-solid-svg-icons' +import { useInterfaceStore } from 'src/stores/interface' +import { useAnnouncementsStore } from 'src/stores/announcements' -library.add(faCircleNotch, faArrowUp, faMinus) +library.add( + faCircleNotch, + faArrowUp, + faMinus +) const DEFAULT_SEEN_TO_DISPLAY_COUNT = 30 @@ -30,7 +30,7 @@ const Notifications = { components: { Notification, NotificationFilters, - ExtraNotifications, + ExtraNotifications }, props: { // Disables panel styles, unread mark, potentially other notification-related actions @@ -41,110 +41,93 @@ const Notifications = { // Do not show extra notifications noExtra: { type: Boolean, - default: false, + default: false }, // Disable teleporting (i.e. for /users/user/notifications) - disableTeleport: Boolean, + disableTeleport: Boolean }, - data() { + data () { return { showScrollTop: false, bottomedOut: false, // How many seen notifications to display in the list. The more there are, // the heavier the page becomes. This count is increased when loading // older notifications, and cut back to default whenever hitting "Read!". - seenToDisplayCount: DEFAULT_SEEN_TO_DISPLAY_COUNT, + seenToDisplayCount: DEFAULT_SEEN_TO_DISPLAY_COUNT } }, - provide() { + provide () { return { - popoversZLayer: computed(() => this.popoversZLayer), + popoversZLayer: computed(() => this.popoversZLayer) } }, computed: { - mainClass() { + mainClass () { return this.minimalMode ? '' : 'panel panel-default' }, - notifications() { + notifications () { return notificationsFromStore(this.$store) }, - error() { + error () { return this.$store.state.notifications.error }, - unseenNotifications() { + unseenNotifications () { return unseenNotificationsFromStore(this.$store) }, - filteredNotifications() { + filteredNotifications () { if (this.unseenAtTop) { return [ - ...filteredNotificationsFromStore(this.$store).filter((n) => - this.shouldShowUnseen(n), - ), - ...filteredNotificationsFromStore(this.$store).filter( - (n) => !this.shouldShowUnseen(n), - ), + ...filteredNotificationsFromStore(this.$store).filter(n => this.shouldShowUnseen(n)), + ...filteredNotificationsFromStore(this.$store).filter(n => !this.shouldShowUnseen(n)) ] } else { return filteredNotificationsFromStore(this.$store, this.filterMode) } }, - unseenCountBadgeText() { + unseenCountBadgeText () { return `${this.unseenCount ? this.unseenCount : ''}${this.extraNotificationsCount ? '*' : ''}` }, - unseenCount() { + unseenCount () { return this.unseenNotifications.length }, - ignoreInactionableSeen() { - return this.$store.getters.mergedConfig.ignoreInactionableSeen - }, - extraNotificationsCount() { + ignoreInactionableSeen () { return this.$store.getters.mergedConfig.ignoreInactionableSeen }, + extraNotificationsCount () { return countExtraNotifications(this.$store) }, - unseenCountTitle() { - return ( - this.unseenNotifications.length + - this.unreadChatCount + - this.unreadAnnouncementCount - ) + unseenCountTitle () { + return this.unseenNotifications.length + (this.unreadChatCount) + this.unreadAnnouncementCount }, - loading() { + loading () { return this.$store.state.notifications.loading }, - noHeading() { + noHeading () { const { layoutType } = useInterfaceStore() return this.minimalMode || layoutType === 'mobile' }, - teleportTarget() { + teleportTarget () { const { layoutType } = useInterfaceStore() const map = { wide: '#notifs-column', - mobile: '#mobile-notifications', + mobile: '#mobile-notifications' } return map[layoutType] || '#notifs-sidebar' }, - popoversZLayer() { + popoversZLayer () { const { layoutType } = useInterfaceStore() return layoutType === 'mobile' ? 'navbar' : null }, - notificationsToDisplay() { - return this.filteredNotifications.slice( - 0, - this.unseenCount + this.seenToDisplayCount, - ) + notificationsToDisplay () { + return this.filteredNotifications.slice(0, this.unseenCount + this.seenToDisplayCount) }, - noSticky() { - return this.$store.getters.mergedConfig.disableStickyHeaders - }, - unseenAtTop() { - return this.$store.getters.mergedConfig.unseenAtTop - }, - showExtraNotifications() { + noSticky () { return this.$store.getters.mergedConfig.disableStickyHeaders }, + unseenAtTop () { return this.$store.getters.mergedConfig.unseenAtTop }, + showExtraNotifications () { return !this.noExtra }, ...mapState(useAnnouncementsStore, ['unreadAnnouncementCount']), - ...mapGetters(['unreadChatCount']), + ...mapGetters(['unreadChatCount']) }, - mounted() { + mounted () { this.scrollerRef = this.$refs.root.closest('.column.-scrollable') if (!this.scrollerRef) { this.scrollerRef = this.$refs.root.closest('.mobile-notifications') @@ -154,12 +137,12 @@ const Notifications = { } this.scrollerRef.addEventListener('scroll', this.updateScrollPosition) }, - unmounted() { + unmounted () { if (!this.scrollerRef) return this.scrollerRef.removeEventListener('scroll', this.updateScrollPosition) }, watch: { - unseenCountTitle(count) { + unseenCountTitle (count) { if (count > 0) { FaviconService.drawFaviconBadge() useInterfaceStore().setPageTitle(`(${count})`) @@ -168,13 +151,10 @@ const Notifications = { useInterfaceStore().setPageTitle('') } }, - teleportTarget() { + teleportTarget () { // handle scroller change this.$nextTick(() => { - this.scrollerRef.removeEventListener( - 'scroll', - this.updateScrollPosition, - ) + this.scrollerRef.removeEventListener('scroll', this.updateScrollPosition) this.scrollerRef = this.$refs.root.closest('.column.-scrollable') if (!this.scrollerRef) { this.scrollerRef = this.$refs.root.closest('.mobile-notifications') @@ -182,18 +162,17 @@ const Notifications = { this.scrollerRef.addEventListener('scroll', this.updateScrollPosition) this.updateScrollPosition() }) - }, + } }, methods: { - scrollToTop() { + scrollToTop () { const scrollable = this.scrollerRef scrollable.scrollTo({ top: this.$refs.root.offsetTop }) }, - updateScrollPosition() { - this.showScrollTop = - this.$refs.root.offsetTop < this.scrollerRef.scrollTop + updateScrollPosition () { + this.showScrollTop = this.$refs.root.offsetTop < this.scrollerRef.scrollTop }, - shouldShowUnseen(notification) { + shouldShowUnseen (notification) { if (notification.seen) return false const actionable = ACTIONABLE_NOTIFICATION_TYPES.has(notification.type) @@ -203,29 +182,26 @@ const Notifications = { * everything else (likes/repeats/reacts) cannot be acted and therefore we just clear * the "seen" status upon any clicks on them */ - notificationClicked(notification) { + notificationClicked (notification) { const { id } = notification this.$store.dispatch('notificationClicked', { id }) }, - notificationInteracted(notification) { + notificationInteracted (notification) { const { id } = notification this.$store.dispatch('markSingleNotificationAsSeen', { id }) }, - markAsSeen() { + markAsSeen () { this.$store.dispatch('markNotificationsAsSeen') this.seenToDisplayCount = DEFAULT_SEEN_TO_DISPLAY_COUNT }, - fetchOlderNotifications() { + fetchOlderNotifications () { if (this.loading) { return } const seenCount = this.filteredNotifications.length - this.unseenCount if (this.seenToDisplayCount < seenCount) { - this.seenToDisplayCount = Math.min( - this.seenToDisplayCount + 20, - seenCount, - ) + this.seenToDisplayCount = Math.min(this.seenToDisplayCount + 20, seenCount) return } else if (this.seenToDisplayCount > seenCount) { this.seenToDisplayCount = seenCount @@ -234,21 +210,19 @@ const Notifications = { const store = this.$store const credentials = store.state.users.currentUser.credentials store.commit('setNotificationsLoading', { value: true }) - notificationsFetcher - .fetchAndUpdate({ - store, - credentials, - older: true, - }) - .then((notifs) => { - store.commit('setNotificationsLoading', { value: false }) - if (notifs.length === 0) { - this.bottomedOut = true - } - this.seenToDisplayCount += notifs.length - }) - }, - }, + notificationsFetcher.fetchAndUpdate({ + store, + credentials, + older: true + }).then(notifs => { + store.commit('setNotificationsLoading', { value: false }) + if (notifs.length === 0) { + this.bottomedOut = true + } + this.seenToDisplayCount += notifs.length + }) + } + } } export default Notifications diff --git a/src/components/oauth_callback/oauth_callback.js b/src/components/oauth_callback/oauth_callback.js index 82c3db047..02e4c9ffc 100644 --- a/src/components/oauth_callback/oauth_callback.js +++ b/src/components/oauth_callback/oauth_callback.js @@ -1,27 +1,25 @@ -import { useOAuthStore } from 'src/stores/oauth.js' import oauth from '../../services/new_api/oauth.js' +import { useOAuthStore } from 'src/stores/oauth.js' const oac = { props: ['code'], - mounted() { + mounted () { if (this.code) { const oauthStore = useOAuthStore() const { clientId, clientSecret } = oauthStore - oauth - .getToken({ - clientId, - clientSecret, - instance: this.$store.state.instance.server, - code: this.code, - }) - .then((result) => { - oauthStore.setToken(result.access_token) - this.$store.dispatch('loginUser', result.access_token) - this.$router.push({ name: 'friends' }) - }) + oauth.getToken({ + clientId, + clientSecret, + instance: this.$store.state.instance.server, + code: this.code + }).then((result) => { + oauthStore.setToken(result.access_token) + this.$store.dispatch('loginUser', result.access_token) + this.$router.push({ name: 'friends' }) + }) } - }, + } } export default oac diff --git a/src/components/opacity_input/opacity_input.vue b/src/components/opacity_input/opacity_input.vue index b8012741f..19de233d7 100644 --- a/src/components/opacity_input/opacity_input.vue +++ b/src/components/opacity_input/opacity_input.vue @@ -36,14 +36,16 @@ import Checkbox from '../checkbox/checkbox.vue' export default { components: { - Checkbox, + Checkbox }, - props: ['name', 'label', 'modelValue', 'fallback', 'disabled'], + props: [ + 'name', 'label', 'modelValue', 'fallback', 'disabled' + ], emits: ['update:modelValue'], computed: { - present() { + present () { return typeof this.modelValue !== 'undefined' - }, - }, + } + } } diff --git a/src/components/optional_router_link/optional_router_link.vue b/src/components/optional_router_link/optional_router_link.vue index b0d553801..d56ad268a 100644 --- a/src/components/optional_router_link/optional_router_link.vue +++ b/src/components/optional_router_link/optional_router_link.vue @@ -18,6 +18,6 @@ diff --git a/src/components/palette_editor/palette_editor.vue b/src/components/palette_editor/palette_editor.vue index eeb523786..3040696d0 100644 --- a/src/components/palette_editor/palette_editor.vue +++ b/src/components/palette_editor/palette_editor.vue @@ -45,17 +45,26 @@ diff --git a/src/components/panel.style.js b/src/components/panel.style.js index ff8c2bf3b..2c8956ae1 100644 --- a/src/components/panel.style.js +++ b/src/components/panel.style.js @@ -9,9 +9,15 @@ export default { 'PanelHeader', 'Post', 'Notification', - 'MenuItem', + 'MenuItem' + ], + validInnerComponentsLite: [ + 'Text', + 'Link', + 'Icon', + 'Border', + 'PanelHeader' ], - validInnerComponentsLite: ['Text', 'Link', 'Icon', 'Border', 'PanelHeader'], defaultRules: [ { directives: { @@ -19,25 +25,23 @@ export default { background: '--bg', roundness: 3, blur: '5px', - shadow: [ - { - x: 0, - y: 0, - blur: 3, - spread: 0, - color: '#000000', - alpha: 0.5, - }, - { - x: 0, - y: 4, - blur: 6, - spread: 3, - color: '#000000', - alpha: 0.3, - }, - ], - }, - }, - ], + shadow: [{ + x: 0, + y: 0, + blur: 3, + spread: 0, + color: '#000000', + alpha: 0.5 + }, + { + x: 0, + y: 4, + blur: 6, + spread: 3, + color: '#000000', + alpha: 0.3 + }] + } + } + ] } diff --git a/src/components/panel_header.style.js b/src/components/panel_header.style.js index 67673e1bf..4e5f97760 100644 --- a/src/components/panel_header.style.js +++ b/src/components/panel_header.style.js @@ -7,7 +7,7 @@ export default { 'Icon', 'Button', 'ButtonUnstyled', - 'Alert', + 'Alert' ], defaultRules: [ { @@ -15,26 +15,24 @@ export default { directives: { backgroundNoCssColor: 'yes', background: '--fg', - shadow: [ - { - x: 0, - y: 1, - blur: 3, - spread: 0, - color: '#000000', - alpha: 0.4, - }, - { - x: 0, - y: 1, - blur: 0, - spread: 0, - color: '#ffffff', - alpha: 0.2, - inset: true, - }, - ], - }, - }, - ], + shadow: [{ + x: 0, + y: 1, + blur: 3, + spread: 0, + color: '#000000', + alpha: 0.4 + }, + { + x: 0, + y: 1, + blur: 0, + spread: 0, + color: '#ffffff', + alpha: 0.2, + inset: true + }] + } + } + ] } diff --git a/src/components/panel_loading/panel_loading.vue b/src/components/panel_loading/panel_loading.vue index df29e5df0..7a8321220 100644 --- a/src/components/panel_loading/panel_loading.vue +++ b/src/components/panel_loading/panel_loading.vue @@ -15,7 +15,9 @@ import { library } from '@fortawesome/fontawesome-svg-core' import { faCircleNotch } from '@fortawesome/free-solid-svg-icons' -library.add(faCircleNotch) +library.add( + faCircleNotch +) export default {} diff --git a/src/components/password_reset/password_reset.js b/src/components/password_reset/password_reset.js index c7e78da2d..3d94f5e72 100644 --- a/src/components/password_reset/password_reset.js +++ b/src/components/password_reset/password_reset.js @@ -1,30 +1,34 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faTimes } from '@fortawesome/free-solid-svg-icons' import { mapState } from 'vuex' import passwordResetApi from '../../services/new_api/password_reset.js' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faTimes +} from '@fortawesome/free-solid-svg-icons' -library.add(faTimes) +library.add( + faTimes +) const passwordReset = { data: () => ({ user: { - email: '', + email: '' }, isPending: false, success: false, throttled: false, - error: null, + error: null }), computed: { ...mapState({ signedIn: (state) => !!state.users.currentUser, - instance: (state) => state.instance, + instance: state => state.instance }), - mailerEnabled() { + mailerEnabled () { return this.instance.mailerEnabled - }, + } }, - created() { + created () { if (this.signedIn) { this.$router.push({ name: 'root' }) } @@ -32,38 +36,36 @@ const passwordReset = { props: { passwordResetRequested: { default: false, - type: Boolean, - }, + type: Boolean + } }, methods: { - dismissError() { + dismissError () { this.error = null }, - submit() { + submit () { this.isPending = true const email = this.user.email const instance = this.instance.server - passwordResetApi({ instance, email }) - .then(({ status }) => { - this.isPending = false - this.user.email = '' + passwordResetApi({ instance, email }).then(({ status }) => { + this.isPending = false + this.user.email = '' - if (status === 204) { - this.success = true - this.error = null - } else if (status === 429) { - this.throttled = true - this.error = this.$t('password_reset.too_many_requests') - } - }) - .catch(() => { - this.isPending = false - this.user.email = '' - this.error = this.$t('general.generic_error') - }) - }, - }, + if (status === 204) { + this.success = true + this.error = null + } else if (status === 429) { + this.throttled = true + this.error = this.$t('password_reset.too_many_requests') + } + }).catch(() => { + this.isPending = false + this.user.email = '' + this.error = this.$t('general.generic_error') + }) + } + } } export default passwordReset diff --git a/src/components/pinch_zoom/pinch_zoom.js b/src/components/pinch_zoom/pinch_zoom.js index 448f90e4b..82670ddfa 100644 --- a/src/components/pinch_zoom/pinch_zoom.js +++ b/src/components/pinch_zoom/pinch_zoom.js @@ -2,12 +2,12 @@ import PinchZoom from '@kazvmoe-infra/pinch-zoom-element' export default { methods: { - setTransform({ scale, x, y }) { + setTransform ({ scale, x, y }) { this.$el.setTransform({ scale, x, y }) - }, + } }, - created() { + created () { // Make lint happy - ;(() => PinchZoom)() - }, + (() => PinchZoom)() + } } diff --git a/src/components/poll/poll.js b/src/components/poll/poll.js index 2894a60e1..a1b7808f2 100644 --- a/src/components/poll/poll.js +++ b/src/components/poll/poll.js @@ -1,8 +1,8 @@ -import Checkbox from 'components/checkbox/checkbox.vue' -import RichContent from 'components/rich_content/rich_content.jsx' import Timeago from 'components/timeago/timeago.vue' -import { usePollsStore } from 'src/stores/polls' import genRandomSeed from '../../services/random_seed/random_seed.service.js' +import RichContent from 'components/rich_content/rich_content.jsx' +import Checkbox from 'components/checkbox/checkbox.vue' +import { usePollsStore } from 'src/stores/polls' export default { name: 'Poll', @@ -10,85 +10,83 @@ export default { components: { Timeago, RichContent, - Checkbox, + Checkbox }, - data() { + data () { return { loading: false, choices: [], - randomSeed: genRandomSeed(), + randomSeed: genRandomSeed() } }, - created() { + created () { if (!usePollsStore().pollsObject[this.pollId]) { usePollsStore().mergeOrAddPoll(this.basePoll) } usePollsStore().trackPoll(this.pollId) }, - unmounted() { + unmounted () { usePollsStore().untrackPoll(this.pollId) }, computed: { - pollId() { + pollId () { return this.basePoll.id }, - poll() { + poll () { const storePoll = usePollsStore().pollsObject[this.pollId] return storePoll || {} }, - options() { + options () { return (this.poll && this.poll.options) || [] }, - expiresAt() { + expiresAt () { return (this.poll && this.poll.expires_at) || null }, - expired() { + expired () { return (this.poll && this.poll.expired) || false }, - expirationLabel() { + expirationLabel () { if (this.$store.getters.mergedConfig.useAbsoluteTimeFormat) { return this.expired ? 'polls.expired_at' : 'polls.expires_at' } else { return this.expired ? 'polls.expired' : 'polls.expires_in' } }, - loggedIn() { + loggedIn () { return this.$store.state.users.currentUser }, - showResults() { + showResults () { return this.poll.voted || this.expired || !this.loggedIn }, - totalVotesCount() { + totalVotesCount () { return this.poll.votes_count }, - containerClass() { + containerClass () { return { - loading: this.loading, + loading: this.loading } }, - choiceIndices() { + choiceIndices () { // Convert array of booleans into an array of indices of the // items that were 'true', so [true, false, false, true] becomes // [0, 3]. return this.choices .map((entry, index) => entry && index) - .filter((value) => typeof value === 'number') + .filter(value => typeof value === 'number') }, - isDisabled() { + isDisabled () { const noChoice = this.choiceIndices.length === 0 return this.loading || noChoice - }, + } }, methods: { - percentageForOption(count) { - return this.totalVotesCount === 0 - ? 0 - : Math.round((count / this.totalVotesCount) * 100) + percentageForOption (count) { + return this.totalVotesCount === 0 ? 0 : Math.round(count / this.totalVotesCount * 100) }, - resultTitle(option) { + resultTitle (option) { return `${option.votes_count}/${this.totalVotesCount} ${this.$t('polls.votes')}` }, - activateOption(index, value) { + activateOption (index, value) { let result if (this.poll.multiple) { result = this.choices || this.options.map(() => false) @@ -98,21 +96,17 @@ export default { result[index] = value this.choices = result }, - optionId(index) { + optionId (index) { return `poll${this.poll.id}-${index}` }, - vote() { + vote () { if (this.choiceIndices.length === 0) return this.loading = true - usePollsStore() - .votePoll({ - id: this.statusId, - pollId: this.poll.id, - choices: this.choiceIndices, - }) - .then(() => { - this.loading = false - }) - }, - }, + usePollsStore().votePoll( + { id: this.statusId, pollId: this.poll.id, choices: this.choiceIndices } + ).then(() => { + this.loading = false + }) + } + } } diff --git a/src/components/poll/poll_form.js b/src/components/poll/poll_form.js index 1e2d0f22d..7660db0c2 100644 --- a/src/components/poll/poll_form.js +++ b/src/components/poll/poll_form.js @@ -1,33 +1,35 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faPlus, faTimes } from '@fortawesome/free-solid-svg-icons' import * as DateUtils from 'src/services/date_utils/date_utils.js' import { pollFallback } from 'src/services/poll/poll.service.js' +import { library } from '@fortawesome/fontawesome-svg-core' import Select from '../select/select.vue' +import { + faTimes, + faPlus +} from '@fortawesome/free-solid-svg-icons' -library.add(faTimes, faPlus) +library.add( + faTimes, + faPlus +) export default { components: { - Select, + Select }, name: 'PollForm', props: { visible: {}, params: { type: Object, - required: true, - }, + required: true + } }, computed: { pollType: { - get() { - return pollFallback(this.params, 'pollType') - }, - set(newVal) { - this.params.pollType = newVal - }, + get () { return pollFallback(this.params, 'pollType') }, + set (newVal) { this.params.pollType = newVal } }, - options() { + options () { const hasOptions = !!this.params.options if (!hasOptions) { this.params.options = pollFallback(this.params, 'options') @@ -35,62 +37,54 @@ export default { return this.params.options }, expiryAmount: { - get() { - return pollFallback(this.params, 'expiryAmount') - }, - set(newVal) { - this.params.expiryAmount = newVal - }, + get () { return pollFallback(this.params, 'expiryAmount') }, + set (newVal) { this.params.expiryAmount = newVal } }, expiryUnit: { - get() { - return pollFallback(this.params, 'expiryUnit') - }, - set(newVal) { - this.params.expiryUnit = newVal - }, + get () { return pollFallback(this.params, 'expiryUnit') }, + set (newVal) { this.params.expiryUnit = newVal } }, - pollLimits() { + pollLimits () { return this.$store.state.instance.pollLimits }, - maxOptions() { + maxOptions () { return this.pollLimits.max_options }, - maxLength() { + maxLength () { return this.pollLimits.max_option_chars }, - expiryUnits() { + expiryUnits () { const allUnits = ['minutes', 'hours', 'days'] const expiry = this.convertExpiryFromUnit return allUnits.filter( - (unit) => this.pollLimits.max_expiration >= expiry(unit, 1), + unit => this.pollLimits.max_expiration >= expiry(unit, 1) ) }, - minExpirationInCurrentUnit() { + minExpirationInCurrentUnit () { return Math.ceil( this.convertExpiryToUnit( this.expiryUnit, - this.pollLimits.min_expiration, - ), + this.pollLimits.min_expiration + ) ) }, - maxExpirationInCurrentUnit() { + maxExpirationInCurrentUnit () { return Math.floor( this.convertExpiryToUnit( this.expiryUnit, - this.pollLimits.max_expiration, - ), + this.pollLimits.max_expiration + ) ) - }, + } }, methods: { - clear() { + clear () { this.pollType = 'single' this.options = ['', ''] this.expiryAmount = 10 this.expiryUnit = 'minutes' }, - nextOption(index) { + nextOption (index) { const element = this.$el.querySelector(`#poll-${index + 1}`) if (element) { element.focus() @@ -104,34 +98,30 @@ export default { } } }, - addOption() { + addOption () { if (this.options.length < this.maxOptions) { this.options.push('') return true } return false }, - deleteOption(index) { + deleteOption (index) { if (this.options.length > 2) { this.options.splice(index, 1) } }, - convertExpiryToUnit(unit, amount) { + convertExpiryToUnit (unit, amount) { // Note: we want seconds and not milliseconds return DateUtils.secondsToUnit(unit, amount) }, - convertExpiryFromUnit(unit, amount) { + convertExpiryFromUnit (unit, amount) { return DateUtils.unitToSeconds(unit, amount) }, - expiryAmountChange() { - this.expiryAmount = Math.max( - this.minExpirationInCurrentUnit, - this.expiryAmount, - ) - this.expiryAmount = Math.min( - this.maxExpirationInCurrentUnit, - this.expiryAmount, - ) - }, - }, + expiryAmountChange () { + this.expiryAmount = + Math.max(this.minExpirationInCurrentUnit, this.expiryAmount) + this.expiryAmount = + Math.min(this.maxExpirationInCurrentUnit, this.expiryAmount) + } + } } diff --git a/src/components/poll/poll_graph.style.js b/src/components/poll/poll_graph.style.js index 69e2fd3ad..247a266a2 100644 --- a/src/components/poll/poll_graph.style.js +++ b/src/components/poll/poll_graph.style.js @@ -5,8 +5,8 @@ export default { { directives: { background: '--accent', - opacity: 0.5, - }, - }, - ], + opacity: 0.5 + } + } + ] } diff --git a/src/components/popover.style.js b/src/components/popover.style.js index 22c3e43d2..455b5f5e0 100644 --- a/src/components/popover.style.js +++ b/src/components/popover.style.js @@ -3,25 +3,25 @@ export default { selector: '.popover', lazy: true, variants: { - modal: '.modal', + modal: '.modal' }, - validInnerComponents: ['MenuItem'], + validInnerComponents: [ + 'MenuItem' + ], defaultRules: [ { directives: { background: '--bg', blur: '10px', - shadow: [ - { - x: 2, - y: 2, - blur: 3, - spread: 0, - color: '#000000', - alpha: 0.5, - }, - ], - }, - }, - ], + shadow: [{ + x: 2, + y: 2, + blur: 3, + spread: 0, + color: '#000000', + alpha: 0.5 + }] + } + } + ] } diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js index 3b83bd58f..e8e857918 100644 --- a/src/components/popover/popover.js +++ b/src/components/popover/popover.js @@ -57,16 +57,15 @@ const Popover = { triggerAttrs: { type: Object, - default: {}, - }, + default: {} + } }, - inject: { - // override popover z layer + inject: { // override popover z layer popoversZLayer: { - default: '', - }, + default: '' + } }, - data() { + data () { return { // lockReEntry is a flag that is set when mouse cursor is leaving the popover's content // so that if mouse goes back into popover it won't be re-shown again to prevent annoyance @@ -84,16 +83,14 @@ const Popover = { graceTimeout: null, parentPopover: null, disableClickOutside: false, - childrenShown: new Set(), + childrenShown: new Set() } }, computed: { - allTriggerAttrs() { + allTriggerAttrs () { if (process.env.NODE_ENV === 'development') { if ('aria-hidden' in this.triggerAttrs) { - throw new Error( - 'Do not use aria-hidden in triggerAttrs. Instead set hideTrigger to true', - ) + throw new Error('Do not use aria-hidden in triggerAttrs. Instead set hideTrigger to true') } } @@ -107,20 +104,18 @@ const Popover = { } return attrs - }, + } }, methods: { - setAnchorEl(el) { + setAnchorEl (el) { this.anchorEl = el this.updateStyles() }, - containerBoundingClientRect() { - const container = this.boundToSelector - ? this.$el.closest(this.boundToSelector) - : this.$el.offsetParent + containerBoundingClientRect () { + const container = this.boundToSelector ? this.$el.closest(this.boundToSelector) : this.$el.offsetParent return container.getBoundingClientRect() }, - updateStyles() { + updateStyles () { if (this.hidden) { this.styles = {} return @@ -128,10 +123,7 @@ const Popover = { // Popover will be anchored around this element, trigger ref is the container, so // its children are what are inside the slot. Expect only one v-slot:trigger. - const anchorEl = - this.anchorEl || - (this.$refs.trigger && this.$refs.trigger.children[0]) || - this.$el + const anchorEl = this.anchorEl || (this.$refs.trigger && this.$refs.trigger.children[0]) || this.$el // SVGs don't have offsetWidth/Height, use fallback const anchorHeight = anchorEl.offsetHeight || anchorEl.clientHeight const anchorWidth = anchorEl.offsetWidth || anchorEl.clientWidth @@ -146,7 +138,7 @@ const Popover = { // Screen position of the origin point for popover = center of the anchor const origin = { x: anchorScreenBox.left + anchorWidth * 0.5, - y: anchorScreenBox.top + anchorHeight * 0.5, + y: anchorScreenBox.top + anchorHeight * 0.5 } const content = this.$refs.content const overlayCenter = this.overlayCenters @@ -154,8 +146,7 @@ const Popover = { : null // Minor optimization, don't call a slow reflow call if we don't have to - const parentScreenBox = - this.boundTo && + const parentScreenBox = this.boundTo && (this.boundTo.x === 'container' || this.boundTo.y === 'container') && this.containerBoundingClientRect() @@ -163,27 +154,25 @@ const Popover = { // What are the screen bounds for the popover? Viewport vs container // when using viewport, using default margin values to dodge the navbar - const xBounds = - this.boundTo && this.boundTo.x === 'container' - ? { - min: parentScreenBox.left + (margin.left || 0), - max: parentScreenBox.right - (margin.right || 0), - } - : { - min: 0 + (margin.left || 10), - max: window.innerWidth - (margin.right || 10), - } + const xBounds = this.boundTo && this.boundTo.x === 'container' + ? { + min: parentScreenBox.left + (margin.left || 0), + max: parentScreenBox.right - (margin.right || 0) + } + : { + min: 0 + (margin.left || 10), + max: window.innerWidth - (margin.right || 10) + } - const yBounds = - this.boundTo && this.boundTo.y === 'container' - ? { - min: parentScreenBox.top + (margin.top || 0), - max: parentScreenBox.bottom - (margin.bottom || 0), - } - : { - min: 0 + (margin.top || 50), - max: window.innerHeight - (margin.bottom || 5), - } + const yBounds = this.boundTo && this.boundTo.y === 'container' + ? { + min: parentScreenBox.top + (margin.top || 0), + max: parentScreenBox.bottom - (margin.bottom || 0) + } + : { + min: 0 + (margin.top || 50), + max: window.innerHeight - (margin.bottom || 5) + } let horizOffset = 0 let vertOffset = 0 @@ -238,12 +227,8 @@ const Popover = { // Handle special cases, first force to displaying on top if there's no space on bottom, // regardless of what placement value was. Then check if there's no space on top, and // force to bottom, again regardless of what placement value was. - const topBoundary = - origin.y - anchorHeight * 0.5 + (this.removePadding ? topPadding : 0) - const bottomBoundary = - origin.y + - anchorHeight * 0.5 - - (this.removePadding ? bottomPadding : 0) + const topBoundary = origin.y - anchorHeight * 0.5 + (this.removePadding ? topPadding : 0) + const bottomBoundary = origin.y + anchorHeight * 0.5 - (this.removePadding ? bottomPadding : 0) if (bottomBoundary + content.offsetHeight > yBounds.max) usingTop = true if (topBoundary - content.offsetHeight < yBounds.min) usingTop = false @@ -261,10 +246,8 @@ const Popover = { // Handle special cases, first force to displaying on left if there's no space on right, // regardless of what placement value was. Then check if there's no space on right, and // force to left, again regardless of what placement value was. - const leftBoundary = - origin.x - anchorWidth * 0.5 + (this.removePadding ? leftPadding : 0) - const rightBoundary = - origin.x + anchorWidth * 0.5 - (this.removePadding ? rightPadding : 0) + const leftBoundary = origin.x - anchorWidth * 0.5 + (this.removePadding ? leftPadding : 0) + const rightBoundary = origin.x + anchorWidth * 0.5 - (this.removePadding ? rightPadding : 0) if (rightBoundary + content.offsetWidth > xBounds.max) usingLeft = true if (leftBoundary - content.offsetWidth < xBounds.min) usingLeft = false @@ -279,18 +262,17 @@ const Popover = { this.styles = { left: `${Math.round(translateX)}px`, - top: `${Math.round(translateY)}px`, + top: `${Math.round(translateY)}px` } if (this.popoversZLayer) { - this.styles['--ZI_popover_override'] = - `var(--ZI_${this.popoversZLayer}_popovers)` + this.styles['--ZI_popover_override'] = `var(--ZI_${this.popoversZLayer}_popovers)` } if (parentScreenBox) { this.styles.maxWidth = `${Math.round(parentScreenBox.width)}px` } }, - showPopover() { + showPopover () { if (this.disabled) return this.disableClickOutside = true setTimeout(() => { @@ -309,7 +291,7 @@ const Popover = { this.updateStyles() }) }, - hidePopover() { + hidePopover () { if (this.disabled) return if (!this.hidden) this.$emit('close') this.hidden = true @@ -320,12 +302,12 @@ const Popover = { this.scrollable?.removeEventListener('scroll', this.onScroll) this.scrollable?.removeEventListener('resize', this.onResize) }, - resizePopover() { + resizePopover () { setTimeout(() => { this.updateStyles() }, 1) }, - onMouseenter() { + onMouseenter () { if (this.trigger === 'hover') { this.lockReEntry = false clearTimeout(this.graceTimeout) @@ -333,12 +315,12 @@ const Popover = { this.showPopover() } }, - onMouseleave() { + onMouseleave () { if (this.trigger === 'hover' && this.childrenShown.size === 0) { this.graceTimeout = setTimeout(() => this.hidePopover(), 1) } }, - onMouseenterContent() { + onMouseenterContent () { if (this.trigger === 'hover' && !this.lockReEntry) { this.lockReEntry = true clearTimeout(this.graceTimeout) @@ -346,12 +328,12 @@ const Popover = { this.showPopover() } }, - onMouseleaveContent() { + onMouseleaveContent () { if (this.trigger === 'hover' && this.childrenShown.size === 0) { this.graceTimeout = setTimeout(() => this.hidePopover(), 1) } }, - onClick() { + onClick () { if (this.trigger === 'click') { if (this.hidden) { this.showPopover() @@ -360,7 +342,7 @@ const Popover = { } } }, - onClickOutside(e) { + onClickOutside (e) { if (this.disableClickOutside) return if (this.hidden) return if (this.$refs.content && this.$refs.content.contains(e.target)) return @@ -369,42 +351,35 @@ const Popover = { this.hidePopover() if (this.parentPopover) this.parentPopover.onClickOutside(e) }, - onScroll() { + onScroll () { this.updateStyles() }, - onResize() { + onResize () { const content = this.$refs.content if (!content) return - if ( - this.oldSize.width !== content.offsetWidth || - this.oldSize.height !== content.offsetHeight - ) { + if (this.oldSize.width !== content.offsetWidth || this.oldSize.height !== content.offsetHeight) { this.updateStyles() - this.oldSize = { - width: content.offsetWidth, - height: content.offsetHeight, - } + this.oldSize = { width: content.offsetWidth, height: content.offsetHeight } } }, - onChildPopoverState(childRef, state) { + onChildPopoverState (childRef, state) { if (state) { this.childrenShown.add(childRef) } else { this.childrenShown.delete(childRef) } - }, + } }, - updated() { + updated () { // Monitor changes to content size, update styles only when content sizes have changed, // that should be the only time we need to move the popover box if we don't care about scroll // or resize this.onResize() }, - mounted() { + mounted () { this.teleport = true - let scrollable = - this.$refs.trigger.closest('.column.-scrollable') || - this.$refs.trigger.closest('.mobile-notifications') + let scrollable = this.$refs.trigger.closest('.column.-scrollable') || + this.$refs.trigger.closest('.mobile-notifications') if (!scrollable) scrollable = window this.scrollable = scrollable let parent = this.$parent @@ -413,9 +388,9 @@ const Popover = { } this.parentPopover = parent }, - beforeUnmount() { + beforeUnmount () { this.hidePopover() - }, + } } export default Popover diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index 530620397..238be88df 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -1,38 +1,40 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { - faBan, - faChevronDown, - faChevronLeft, - faChevronRight, - faCircleNotch, - faPollH, - faSmileBeam, - faTimes, - faUpload, -} from '@fortawesome/free-solid-svg-icons' -import { debounce, map, reject, uniqBy } from 'lodash' -import { mapActions, mapState } from 'pinia' -import DraftCloser from 'src/components/draft_closer/draft_closer.vue' +import statusPoster from '../../services/status_poster/status_poster.service.js' +import genRandomSeed from '../../services/random_seed/random_seed.service.js' +import MediaUpload from '../media_upload/media_upload.vue' +import ScopeSelector from '../scope_selector/scope_selector.vue' +import EmojiInput from '../emoji_input/emoji_input.vue' +import PollForm from '../poll/poll_form.vue' +import Attachment from '../attachment/attachment.vue' import Gallery from 'src/components/gallery/gallery.vue' +import StatusContent from '../status_content/status_content.vue' import Popover from 'src/components/popover/popover.vue' -import { pollFormToMasto } from 'src/services/poll/poll.service.js' -import { useInterfaceStore } from 'src/stores/interface.js' -import { useMediaViewerStore } from 'src/stores/media_viewer.js' -import { mapGetters } from 'vuex' -import { propsToNative } from '../../services/attributes_helper/attributes_helper.service.js' import fileTypeService from '../../services/file_type/file_type.service.js' import { findOffset } from '../../services/offset_finder/offset_finder.service.js' -import genRandomSeed from '../../services/random_seed/random_seed.service.js' -import statusPoster from '../../services/status_poster/status_poster.service.js' -import Attachment from '../attachment/attachment.vue' -import Checkbox from '../checkbox/checkbox.vue' -import EmojiInput from '../emoji_input/emoji_input.vue' +import { propsToNative } from '../../services/attributes_helper/attributes_helper.service.js' +import { pollFormToMasto } from 'src/services/poll/poll.service.js' +import { reject, map, uniqBy, debounce } from 'lodash' import suggestor from '../emoji_input/suggestor.js' -import MediaUpload from '../media_upload/media_upload.vue' -import PollForm from '../poll/poll_form.vue' -import ScopeSelector from '../scope_selector/scope_selector.vue' +import { mapGetters } from 'vuex' +import { mapState, mapActions } from 'pinia' +import Checkbox from '../checkbox/checkbox.vue' import Select from '../select/select.vue' -import StatusContent from '../status_content/status_content.vue' +import DraftCloser from 'src/components/draft_closer/draft_closer.vue' + +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faSmileBeam, + faPollH, + faUpload, + faBan, + faTimes, + faCircleNotch, + faChevronDown, + faChevronLeft, + faChevronRight +} from '@fortawesome/free-solid-svg-icons' + +import { useInterfaceStore } from 'src/stores/interface.js' +import { useMediaViewerStore } from 'src/stores/media_viewer.js' library.add( faSmileBeam, @@ -43,7 +45,7 @@ library.add( faCircleNotch, faChevronDown, faChevronLeft, - faChevronRight, + faChevronRight ) const buildMentionsString = ({ user, attentions = [] }, currentUser) => { @@ -115,7 +117,7 @@ const PostStatusForm = { 'emojiPickerPlacement', 'optimisticPosting', 'profileMention', - 'draftId', + 'draftId' ], emits: [ 'posted', @@ -124,7 +126,7 @@ const PostStatusForm = { 'mediaplay', 'mediapause', 'can-close', - 'update', + 'update' ], components: { MediaUpload, @@ -137,9 +139,9 @@ const PostStatusForm = { StatusContent, Gallery, DraftCloser, - Popover, + Popover }, - mounted() { + mounted () { this.updateIdempotencyKey() this.resize(this.$refs.textarea) @@ -152,41 +154,28 @@ const PostStatusForm = { this.$refs.textarea.focus() } }, - data() { + data () { const preset = this.$route.query.message let statusText = preset || '' const { scopeCopy } = this.$store.getters.mergedConfig - const [statusType, refId] = typeAndRefId({ - replyTo: this.replyTo, - profileMention: this.profileMention && this.repliedUser?.id, - statusId: this.statusId, - }) + const [statusType, refId] = typeAndRefId({ replyTo: this.replyTo, profileMention: this.profileMention && this.repliedUser?.id, statusId: this.statusId }) // If we are starting a new post, do not associate it with old drafts - let statusParams = - !this.disableDraft && (this.draftId || statusType !== 'new') - ? this.getDraft(statusType, refId) - : null + let statusParams = !this.disableDraft && (this.draftId || statusType !== 'new') ? this.getDraft(statusType, refId) : null if (!statusParams) { if (statusType === 'reply' || statusType === 'mention') { const currentUser = this.$store.state.users.currentUser - statusText = buildMentionsString( - { user: this.repliedUser, attentions: this.attentions }, - currentUser, - ) + statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser) } - const scope = - (this.copyMessageScope && scopeCopy) || - this.copyMessageScope === 'direct' - ? this.copyMessageScope - : this.$store.state.users.currentUser.default_scope + const scope = ((this.copyMessageScope && scopeCopy) || this.copyMessageScope === 'direct') + ? this.copyMessageScope + : this.$store.state.users.currentUser.default_scope - const { postContentType: contentType, sensitiveByDefault } = - this.$store.getters.mergedConfig + const { postContentType: contentType, sensitiveByDefault } = this.$store.getters.mergedConfig statusParams = { type: statusType, @@ -200,7 +189,7 @@ const PostStatusForm = { mediaDescriptions: {}, visibility: scope, contentType, - quoting: false, + quoting: false } if (statusType === 'edit') { @@ -216,7 +205,7 @@ const PostStatusForm = { hasPoll: false, mediaDescriptions: this.statusMediaDescriptions || {}, visibility: this.statusScope || scope, - contentType: statusContentType, + contentType: statusContentType } } } @@ -237,109 +226,101 @@ const PostStatusForm = { emojiInputShown: false, idempotencyKey: '', saveInhibited: true, - saveable: false, + saveable: false } }, computed: { - users() { + users () { return this.$store.state.users.users }, - userDefaultScope() { + userDefaultScope () { return this.$store.state.users.currentUser.default_scope }, - showAllScopes() { + showAllScopes () { return !this.mergedConfig.minimalScopesMode }, - hideExtraActions() { + hideExtraActions () { return this.disableDraft || this.hideDraft }, - emojiUserSuggestor() { + emojiUserSuggestor () { return suggestor({ emoji: [ ...this.$store.getters.standardEmojiList, - ...this.$store.state.instance.customEmoji, + ...this.$store.state.instance.customEmoji ], - store: this.$store, + store: this.$store }) }, - emojiSuggestor() { + emojiSuggestor () { return suggestor({ emoji: [ ...this.$store.getters.standardEmojiList, - ...this.$store.state.instance.customEmoji, - ], + ...this.$store.state.instance.customEmoji + ] }) }, - emoji() { + emoji () { return this.$store.getters.standardEmojiList || [] }, - customEmoji() { + customEmoji () { return this.$store.state.instance.customEmoji || [] }, - statusLength() { + statusLength () { return this.newStatus.status.length }, - spoilerTextLength() { + spoilerTextLength () { return this.newStatus.spoilerText.length }, - statusLengthLimit() { + statusLengthLimit () { return this.$store.state.instance.textlimit }, - hasStatusLengthLimit() { + hasStatusLengthLimit () { return this.statusLengthLimit > 0 }, - charactersLeft() { - return ( - this.statusLengthLimit - (this.statusLength + this.spoilerTextLength) - ) + charactersLeft () { + return this.statusLengthLimit - (this.statusLength + this.spoilerTextLength) }, - isOverLengthLimit() { - return this.hasStatusLengthLimit && this.charactersLeft < 0 + isOverLengthLimit () { + return this.hasStatusLengthLimit && (this.charactersLeft < 0) }, - minimalScopesMode() { + minimalScopesMode () { return this.$store.state.instance.minimalScopesMode }, - alwaysShowSubject() { + alwaysShowSubject () { return this.mergedConfig.alwaysShowSubjectInput }, - postFormats() { + postFormats () { return this.$store.state.instance.postFormats || [] }, - safeDMEnabled() { + safeDMEnabled () { return this.$store.state.instance.safeDM }, - pollsAvailable() { - return ( - this.$store.state.instance.pollsAvailable && + pollsAvailable () { + return this.$store.state.instance.pollsAvailable && this.$store.state.instance.pollLimits.max_options >= 2 && this.disablePolls !== true - ) }, - hideScopeNotice() { - return ( - this.disableNotice || this.$store.getters.mergedConfig.hideScopeNotice - ) + hideScopeNotice () { + return this.disableNotice || this.$store.getters.mergedConfig.hideScopeNotice }, - pollContentError() { - return ( - this.pollFormVisible && this.newStatus.poll && this.newStatus.poll.error - ) + pollContentError () { + return this.pollFormVisible && + this.newStatus.poll && + this.newStatus.poll.error }, - showPreview() { + showPreview () { return !this.disablePreview && (!!this.preview || this.previewLoading) }, - emptyStatus() { - return ( - this.newStatus.status.trim() === '' && this.newStatus.files.length === 0 - ) + emptyStatus () { + return this.newStatus.status.trim() === '' && this.newStatus.files.length === 0 }, - uploadFileLimitReached() { + uploadFileLimitReached () { return this.newStatus.files.length >= this.fileLimit }, - isEdit() { + isEdit () { return typeof this.statusId !== 'undefined' && this.statusId.trim() !== '' }, - quotable() { + quotable () { if (!this.$store.state.instance.quotingAvailable) { return false } @@ -348,17 +329,14 @@ const PostStatusForm = { return false } - const repliedStatus = - this.$store.state.statuses.allStatusesObject[this.replyTo] + const repliedStatus = this.$store.state.statuses.allStatusesObject[this.replyTo] if (!repliedStatus) { return false } - if ( - repliedStatus.visibility === 'public' || - repliedStatus.visibility === 'unlisted' || - repliedStatus.visibility === 'local' - ) { + if (repliedStatus.visibility === 'public' || + repliedStatus.visibility === 'unlisted' || + repliedStatus.visibility === 'local') { return true } else if (repliedStatus.visibility === 'private') { return repliedStatus.user.id === this.$store.state.users.currentUser.id @@ -366,16 +344,16 @@ const PostStatusForm = { return false }, - debouncedMaybeAutoSaveDraft() { + debouncedMaybeAutoSaveDraft () { return debounce(this.maybeAutoSaveDraft, 3000) }, - pollFormVisible() { + pollFormVisible () { return this.newStatus.hasPoll }, - shouldAutoSaveDraft() { + shouldAutoSaveDraft () { return this.$store.getters.mergedConfig.autoSaveDraft }, - autoSaveState() { + autoSaveState () { if (this.saveable) { return this.$t('post_status.auto_save_saving') } else if (this.newStatus.id) { @@ -384,39 +362,35 @@ const PostStatusForm = { return this.$t('post_status.auto_save_nothing_new') } }, - safeToSaveDraft() { + safeToSaveDraft () { return ( - (this.newStatus.status || - this.newStatus.spoilerText || - this.newStatus.files?.length || - this.newStatus.hasPoll) && - this.saveable - ) + this.newStatus.status || + this.newStatus.spoilerText || + this.newStatus.files?.length || + this.newStatus.hasPoll + ) && this.saveable }, - hasEmptyDraft() { - return ( - this.newStatus.id && - !( - this.newStatus.status || + hasEmptyDraft () { + return this.newStatus.id && !( + this.newStatus.status || this.newStatus.spoilerText || this.newStatus.files?.length || this.newStatus.hasPoll - ) ) }, ...mapGetters(['mergedConfig']), ...mapState(useInterfaceStore, { - mobileLayout: (store) => store.mobileLayout, - }), + mobileLayout: store => store.mobileLayout + }) }, watch: { newStatus: { deep: true, - handler() { + handler () { this.statusChanged() - }, + } }, - saveable(val) { + saveable (val) { // https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event#usage_notes // MDN says we'd better add the beforeunload event listener only when needed, and remove it when it's no longer needed if (val) { @@ -424,22 +398,22 @@ const PostStatusForm = { } else { this.removeBeforeUnloadListener() } - }, + } }, - beforeUnmount() { + beforeUnmount () { this.maybeAutoSaveDraft() this.removeBeforeUnloadListener() }, methods: { ...mapActions(useMediaViewerStore, ['increment']), - statusChanged() { + statusChanged () { this.autoPreview() this.updateIdempotencyKey() this.debouncedMaybeAutoSaveDraft() this.saveable = true this.saveInhibited = false }, - clearStatus() { + clearStatus () { const newStatus = this.newStatus this.saveInhibited = true this.newStatus = { @@ -451,7 +425,7 @@ const PostStatusForm = { poll: {}, hasPoll: false, mediaDescriptions: {}, - quoting: false, + quoting: false } this.$refs.mediaUpload && this.$refs.mediaUpload.clearFile() this.clearPollForm() @@ -467,36 +441,23 @@ const PostStatusForm = { if (this.preview) this.previewStatus() this.saveable = false }, - async postStatus(event, newStatus) { - if (this.posting && !this.optimisticPosting) { - return - } - if (this.disableSubmit) { - return - } - if (this.emojiInputShown) { - return - } + async postStatus (event, newStatus) { + if (this.posting && !this.optimisticPosting) { return } + if (this.disableSubmit) { return } + if (this.emojiInputShown) { return } if (this.submitOnEnter) { event.stopPropagation() event.preventDefault() } - if ( - this.optimisticPosting && - (this.emptyStatus || this.isOverLengthLimit) - ) { - return - } + if (this.optimisticPosting && (this.emptyStatus || this.isOverLengthLimit)) { return } if (this.emptyStatus) { this.error = this.$t('post_status.empty_status_error') return } - const poll = this.newStatus.hasPoll - ? pollFormToMasto(this.newStatus.poll) - : {} + const poll = this.newStatus.hasPoll ? pollFormToMasto(this.newStatus.poll) : {} if (this.pollContentError) { this.error = this.pollContentError return @@ -512,9 +473,7 @@ const PostStatusForm = { return } - const replyOrQuoteAttr = newStatus.quoting - ? 'quoteId' - : 'inReplyToStatusId' + const replyOrQuoteAttr = newStatus.quoting ? 'quoteId' : 'inReplyToStatusId' const postingOptions = { status: newStatus.status, @@ -526,12 +485,10 @@ const PostStatusForm = { [replyOrQuoteAttr]: this.replyTo, contentType: newStatus.contentType, poll, - idempotencyKey: this.idempotencyKey, + idempotencyKey: this.idempotencyKey } - const postHandler = this.postHandler - ? this.postHandler - : statusPoster.postStatus + const postHandler = this.postHandler ? this.postHandler : statusPoster.postStatus postHandler(postingOptions).then((data) => { if (!data.error) { @@ -544,7 +501,7 @@ const PostStatusForm = { this.posting = false }) }, - previewStatus() { + previewStatus () { if (this.emptyStatus && this.newStatus.spoilerText.trim() === '') { this.preview = { error: this.$t('post_status.preview_empty') } this.previewLoading = false @@ -552,100 +509,89 @@ const PostStatusForm = { } const newStatus = this.newStatus this.previewLoading = true - const replyOrQuoteAttr = newStatus.quoting - ? 'quoteId' - : 'inReplyToStatusId' - statusPoster - .postStatus({ - status: newStatus.status, - spoilerText: newStatus.spoilerText || null, - visibility: newStatus.visibility, - sensitive: newStatus.nsfw, - media: [], - store: this.$store, - [replyOrQuoteAttr]: this.replyTo, - contentType: newStatus.contentType, - poll: {}, - preview: true, - }) - .then((data) => { - // Don't apply preview if not loading, because it means - // user has closed the preview manually. - if (!this.previewLoading) return - if (!data.error) { - this.preview = data - } else { - this.preview = { error: data.error } - } - }) - .catch((error) => { - this.preview = { error } - }) - .finally(() => { - this.previewLoading = false - }) + const replyOrQuoteAttr = newStatus.quoting ? 'quoteId' : 'inReplyToStatusId' + statusPoster.postStatus({ + status: newStatus.status, + spoilerText: newStatus.spoilerText || null, + visibility: newStatus.visibility, + sensitive: newStatus.nsfw, + media: [], + store: this.$store, + [replyOrQuoteAttr]: this.replyTo, + contentType: newStatus.contentType, + poll: {}, + preview: true + }).then((data) => { + // Don't apply preview if not loading, because it means + // user has closed the preview manually. + if (!this.previewLoading) return + if (!data.error) { + this.preview = data + } else { + this.preview = { error: data.error } + } + }).catch((error) => { + this.preview = { error } + }).finally(() => { + this.previewLoading = false + }) }, - debouncePreviewStatus: debounce(function () { - this.previewStatus() - }, 500), - autoPreview() { + debouncePreviewStatus: debounce(function () { this.previewStatus() }, 500), + autoPreview () { if (!this.preview) return this.previewLoading = true this.debouncePreviewStatus() }, - closePreview() { + closePreview () { this.preview = null this.previewLoading = false }, - togglePreview() { + togglePreview () { if (this.showPreview) { this.closePreview() } else { this.previewStatus() } }, - addMediaFile(fileInfo) { + addMediaFile (fileInfo) { this.newStatus.files.push(fileInfo) this.$emit('resize', { delayed: true }) }, - removeMediaFile(fileInfo) { + removeMediaFile (fileInfo) { const index = this.newStatus.files.indexOf(fileInfo) this.newStatus.files.splice(index, 1) this.$emit('resize') }, - editAttachment(fileInfo, newText) { + editAttachment (fileInfo, newText) { this.newStatus.mediaDescriptions[fileInfo.id] = newText }, - shiftUpMediaFile(fileInfo) { + shiftUpMediaFile (fileInfo) { const { files } = this.newStatus const index = this.newStatus.files.indexOf(fileInfo) files.splice(index, 1) files.splice(index - 1, 0, fileInfo) }, - shiftDnMediaFile(fileInfo) { + shiftDnMediaFile (fileInfo) { const { files } = this.newStatus const index = this.newStatus.files.indexOf(fileInfo) files.splice(index, 1) files.splice(index + 1, 0, fileInfo) }, - uploadFailed(errString, templateArgs) { + uploadFailed (errString, templateArgs) { templateArgs = templateArgs || {} - this.error = - this.$t('upload.error.base') + - ' ' + - this.$t('upload.error.' + errString, templateArgs) + this.error = this.$t('upload.error.base') + ' ' + this.$t('upload.error.' + errString, templateArgs) }, - startedUploadingFiles() { + startedUploadingFiles () { this.uploadingFiles = true }, - finishedUploadingFiles() { + finishedUploadingFiles () { this.$emit('resize') this.uploadingFiles = false }, - type(fileInfo) { + type (fileInfo) { return fileTypeService.fileType(fileInfo.mimetype) }, - paste(e) { + paste (e) { this.autoPreview() this.resize(e) if (e.clipboardData.files.length > 0) { @@ -657,7 +603,7 @@ const PostStatusForm = { this.dropFiles = [e.clipboardData.files[0]] } }, - fileDrop(e) { + fileDrop (e) { if (e.dataTransfer && e.dataTransfer.types.includes('Files')) { e.preventDefault() // allow dropping text like before this.dropFiles = e.dataTransfer.files @@ -665,7 +611,7 @@ const PostStatusForm = { this.showDropIcon = 'hide' } }, - fileDragStop() { + fileDragStop () { // The false-setting is done with delay because just using leave-events // directly caused unwanted flickering, this is not perfect either but // much less noticable. @@ -673,23 +619,21 @@ const PostStatusForm = { this.showDropIcon = 'fade' this.dropStopTimeout = setTimeout(() => (this.showDropIcon = 'hide'), 500) }, - fileDrag(e) { + fileDrag (e) { e.dataTransfer.dropEffect = this.uploadFileLimitReached ? 'none' : 'copy' if (e.dataTransfer && e.dataTransfer.types.includes('Files')) { clearTimeout(this.dropStopTimeout) this.showDropIcon = 'show' } }, - onEmojiInputInput() { + onEmojiInputInput () { this.$nextTick(() => { this.resize(this.$refs.textarea) }) }, - resize(e) { + resize (e) { const target = e.target || e - if (!(target instanceof window.Element)) { - return - } + if (!(target instanceof window.Element)) { return } // Reset to default height for empty form, nothing else to do here. if (target.value === '') { @@ -704,14 +648,12 @@ const PostStatusForm = { * replies in notifs) or mobile post form. Note that getting and setting * scroll is different for `Window` and `Element`s */ - const bottomBottomPaddingStr = - window.getComputedStyle(bottomRef)['padding-bottom'] + const bottomBottomPaddingStr = window.getComputedStyle(bottomRef)['padding-bottom'] const bottomBottomPadding = pxStringToNumber(bottomBottomPaddingStr) - const scrollerRef = - this.$el.closest('.column.-scrollable') || - this.$el.closest('.post-form-modal-view') || - window + const scrollerRef = this.$el.closest('.column.-scrollable') || + this.$el.closest('.post-form-modal-view') || + window // Getting info about padding we have to account for, removing 'px' part const topPaddingStr = window.getComputedStyle(target)['padding-top'] @@ -740,20 +682,18 @@ const PostStatusForm = { */ // this part has to be BEFORE the content size update - const currentScroll = - scrollerRef === window ? scrollerRef.scrollY : scrollerRef.scrollTop - const scrollerHeight = - scrollerRef === window - ? scrollerRef.innerHeight - : scrollerRef.offsetHeight + const currentScroll = scrollerRef === window + ? scrollerRef.scrollY + : scrollerRef.scrollTop + const scrollerHeight = scrollerRef === window + ? scrollerRef.innerHeight + : scrollerRef.offsetHeight const scrollerBottomBorder = currentScroll + scrollerHeight // BEGIN content size update target.style.height = 'auto' const heightWithoutPadding = Math.floor(target.scrollHeight - vertPadding) - let newHeight = this.maxHeight - ? Math.min(heightWithoutPadding, this.maxHeight) - : heightWithoutPadding + let newHeight = this.maxHeight ? Math.min(heightWithoutPadding, this.maxHeight) : heightWithoutPadding // This is a bit of a hack to combat target.scrollHeight being different on every other input // on some browsers for whatever reason. Don't change the height if difference is 1px or less. if (Math.abs(newHeight - oldHeight) <= 1) { @@ -765,10 +705,7 @@ const PostStatusForm = { // We check where the bottom border of form-bottom element is, this uses findOffset // to find offset relative to scrollable container (scroller) - const bottomBottomBorder = - bottomRef.offsetHeight + - findOffset(bottomRef, scrollerRef).top + - bottomBottomPadding + const bottomBottomBorder = bottomRef.offsetHeight + findOffset(bottomRef, scrollerRef).top + bottomBottomPadding const isBottomObstructed = scrollerBottomBorder < bottomBottomBorder const isFormBiggerThanScroller = scrollerHeight < formRef.offsetHeight @@ -777,13 +714,9 @@ const PostStatusForm = { // Keep form-bottom always visible so that submit button is in view EXCEPT // if form element bigger than scroller and caret isn't at the end, so that // if you scroll up and edit middle of text you won't get scrolled back to bottom - const shouldScrollToBottom = - isBottomObstructed && - !( - isFormBiggerThanScroller && - this.$refs.textarea.selectionStart !== - this.$refs.textarea.value.length - ) + const shouldScrollToBottom = isBottomObstructed && + !(isFormBiggerThanScroller && + this.$refs.textarea.selectionStart !== this.$refs.textarea.value.length) const totalDelta = shouldScrollToBottom ? bottomChangeDelta : 0 const targetScroll = Math.round(currentScroll + totalDelta) @@ -793,60 +726,53 @@ const PostStatusForm = { scrollerRef.scrollTop = targetScroll } }, - clearError() { + clearError () { this.error = null }, - changeVis(visibility) { + changeVis (visibility) { this.newStatus.visibility = visibility }, - togglePollForm() { + togglePollForm () { this.newStatus.hasPoll = !this.newStatus.hasPoll }, - setPoll(poll) { + setPoll (poll) { this.newStatus.poll = poll }, - clearPollForm() { + clearPollForm () { if (this.$refs.pollForm) { this.$refs.pollForm.clear() } }, - dismissScopeNotice() { - this.$store.dispatch('setOption', { - name: 'hideScopeNotice', - value: true, - }) + dismissScopeNotice () { + this.$store.dispatch('setOption', { name: 'hideScopeNotice', value: true }) }, - setMediaDescription(id) { + setMediaDescription (id) { const description = this.newStatus.mediaDescriptions[id] if (!description || description.trim() === '') return - return statusPoster.setMediaDescription({ - store: this.$store, - id, - description, - }) + return statusPoster.setMediaDescription({ store: this.$store, id, description }) }, - setAllMediaDescriptions() { - const ids = this.newStatus.files.map((file) => file.id) - return Promise.all(ids.map((id) => this.setMediaDescription(id))) + setAllMediaDescriptions () { + const ids = this.newStatus.files.map(file => file.id) + return Promise.all(ids.map(id => this.setMediaDescription(id))) }, - handleEmojiInputShow(value) { + handleEmojiInputShow (value) { this.emojiInputShown = value }, - updateIdempotencyKey() { + updateIdempotencyKey () { this.idempotencyKey = Date.now().toString() }, - openProfileTab() { + openProfileTab () { useInterfaceStore().openSettingsModalTab('profile') }, - propsToNative(props) { + propsToNative (props) { return propsToNative(props) }, - saveDraft() { - if (!this.disableDraft && !this.saveInhibited) { + saveDraft () { + if (!this.disableDraft && + !this.saveInhibited) { if (this.safeToSaveDraft) { - return this.$store - .dispatch('addOrSaveDraft', { draft: this.newStatus }) - .then((id) => { + return this.$store.dispatch('addOrSaveDraft', { draft: this.newStatus }) + .then(id => { if (this.newStatus.id !== id) { this.newStatus.id = id } @@ -858,34 +784,32 @@ const PostStatusForm = { }) } else if (this.hasEmptyDraft) { // There is a draft, but there is nothing in it, clear it - return this.abandonDraft().then(() => { - this.saveable = false - if (!this.shouldAutoSaveDraft) { - this.clearStatus() - this.$emit('draft-done') - } - }) + return this.abandonDraft() + .then(() => { + this.saveable = false + if (!this.shouldAutoSaveDraft) { + this.clearStatus() + this.$emit('draft-done') + } + }) } } return Promise.resolve() }, - maybeAutoSaveDraft() { + maybeAutoSaveDraft () { if (this.shouldAutoSaveDraft) { this.saveDraft(false) } }, - abandonDraft() { + abandonDraft () { return this.$store.dispatch('abandonDraft', { id: this.newStatus.id }) }, - getDraft(statusType, refId) { + getDraft (statusType, refId) { const maybeDraft = this.$store.state.drafts.drafts[this.draftId] if (this.draftId && maybeDraft) { return maybeDraft } else { - const existingDrafts = this.$store.getters.draftsByTypeAndRefId( - statusType, - refId, - ) + const existingDrafts = this.$store.getters.draftsByTypeAndRefId(statusType, refId) if (existingDrafts.length) { return existingDrafts[0] @@ -893,35 +817,35 @@ const PostStatusForm = { } // No draft available, fall back }, - requestClose() { + requestClose () { if (!this.saveable) { this.$emit('can-close') } else { this.$refs.draftCloser.requestClose() } }, - saveAndCloseDraft() { + saveAndCloseDraft () { this.saveDraft().then(() => { this.$emit('can-close') }) }, - discardAndCloseDraft() { + discardAndCloseDraft () { this.abandonDraft().then(() => { this.$emit('can-close') }) }, - addBeforeUnloadListener() { + addBeforeUnloadListener () { this._beforeUnloadListener ||= () => { this.saveDraft() } window.addEventListener('beforeunload', this._beforeUnloadListener) }, - removeBeforeUnloadListener() { + removeBeforeUnloadListener () { if (this._beforeUnloadListener) { window.removeEventListener('beforeunload', this._beforeUnloadListener) } - }, - }, + } + } } export default PostStatusForm diff --git a/src/components/post_status_modal/post_status_modal.js b/src/components/post_status_modal/post_status_modal.js index 2643f0822..ee6cd6444 100644 --- a/src/components/post_status_modal/post_status_modal.js +++ b/src/components/post_status_modal/post_status_modal.js @@ -1,34 +1,34 @@ +import PostStatusForm from '../post_status_form/post_status_form.vue' +import Modal from '../modal/modal.vue' import get from 'lodash/get' import { usePostStatusStore } from 'src/stores/post_status' -import Modal from '../modal/modal.vue' -import PostStatusForm from '../post_status_form/post_status_form.vue' const PostStatusModal = { components: { PostStatusForm, - Modal, + Modal }, - data() { + data () { return { - resettingForm: false, + resettingForm: false } }, computed: { - isLoggedIn() { + isLoggedIn () { return !!this.$store.state.users.currentUser }, - modalActivated() { + modalActivated () { return usePostStatusStore().modalActivated }, - isFormVisible() { + isFormVisible () { return this.isLoggedIn && !this.resettingForm && this.modalActivated }, - params() { + params () { return usePostStatusStore().params || {} - }, + } }, watch: { - params(newVal, oldVal) { + params (newVal, oldVal) { if (get(newVal, 'repliedUser.id') !== get(oldVal, 'repliedUser.id')) { this.resettingForm = true this.$nextTick(() => { @@ -36,23 +36,21 @@ const PostStatusModal = { }) } }, - isFormVisible(val) { + isFormVisible (val) { if (val) { - this.$nextTick( - () => this.$el && this.$el.querySelector('textarea').focus(), - ) + this.$nextTick(() => this.$el && this.$el.querySelector('textarea').focus()) } - }, + } }, methods: { - closeModal() { + closeModal () { usePostStatusStore().closePostStatusModal() }, - resetAndClose() { + resetAndClose () { usePostStatusStore().resetPostStatusModal() usePostStatusStore().closePostStatusModal() - }, - }, + } + } } export default PostStatusModal diff --git a/src/components/progress_button/progress_button.vue b/src/components/progress_button/progress_button.vue index 318260409..283a51af5 100644 --- a/src/components/progress_button/progress_button.vue +++ b/src/components/progress_button/progress_button.vue @@ -16,26 +16,23 @@ export default { props: { disabled: { - type: Boolean, + type: Boolean }, - click: { - // click event handler. Must return a promise + click: { // click event handler. Must return a promise type: Function, - default: () => Promise.resolve(), - }, + default: () => Promise.resolve() + } }, - data() { + data () { return { - progress: false, + progress: false } }, methods: { - onClick() { + onClick () { this.progress = true - this.click().then(() => { - this.progress = false - }) - }, - }, + this.click().then(() => { this.progress = false }) + } + } } diff --git a/src/components/public_and_external_timeline/public_and_external_timeline.js b/src/components/public_and_external_timeline/public_and_external_timeline.js index b6e53a4cf..bfcce6ae6 100644 --- a/src/components/public_and_external_timeline/public_and_external_timeline.js +++ b/src/components/public_and_external_timeline/public_and_external_timeline.js @@ -1,22 +1,17 @@ import Timeline from '../timeline/timeline.vue' - const PublicAndExternalTimeline = { components: { - Timeline, + Timeline }, computed: { - timeline() { - return this.$store.state.statuses.timelines.publicAndExternal - }, + timeline () { return this.$store.state.statuses.timelines.publicAndExternal } }, - created() { - this.$store.dispatch('startFetchingTimeline', { - timeline: 'publicAndExternal', - }) + created () { + this.$store.dispatch('startFetchingTimeline', { timeline: 'publicAndExternal' }) }, - unmounted() { + unmounted () { this.$store.dispatch('stopFetchingTimeline', 'publicAndExternal') - }, + } } export default PublicAndExternalTimeline diff --git a/src/components/public_timeline/public_timeline.js b/src/components/public_timeline/public_timeline.js index b9d136e29..306935445 100644 --- a/src/components/public_timeline/public_timeline.js +++ b/src/components/public_timeline/public_timeline.js @@ -1,20 +1,18 @@ import Timeline from '../timeline/timeline.vue' - const PublicTimeline = { components: { - Timeline, + Timeline }, computed: { - timeline() { - return this.$store.state.statuses.timelines.public - }, + timeline () { return this.$store.state.statuses.timelines.public } }, - created() { + created () { this.$store.dispatch('startFetchingTimeline', { timeline: 'public' }) }, - unmounted() { + unmounted () { this.$store.dispatch('stopFetchingTimeline', 'public') - }, + } + } export default PublicTimeline diff --git a/src/components/quick_filter_settings/quick_filter_settings.js b/src/components/quick_filter_settings/quick_filter_settings.js index 4e5960901..f5e4721d0 100644 --- a/src/components/quick_filter_settings/quick_filter_settings.js +++ b/src/components/quick_filter_settings/quick_filter_settings.js @@ -1,130 +1,99 @@ +import Popover from '../popover/popover.vue' +import { mapGetters } from 'vuex' +import { mapState } from 'pinia' import { library } from '@fortawesome/fontawesome-svg-core' import { faFilter, faFont, faWrench } from '@fortawesome/free-solid-svg-icons' -import { mapState } from 'pinia' import { useInterfaceStore } from 'src/stores/interface' -import { mapGetters } from 'vuex' -import Popover from '../popover/popover.vue' -library.add(faFilter, faFont, faWrench) +library.add( + faFilter, + faFont, + faWrench +) const QuickFilterSettings = { props: { conversation: Boolean, - nested: Boolean, + nested: Boolean }, components: { - Popover, + Popover }, methods: { - setReplyVisibility(visibility) { - this.$store.dispatch('setOption', { - name: 'replyVisibility', - value: visibility, - }) + setReplyVisibility (visibility) { + this.$store.dispatch('setOption', { name: 'replyVisibility', value: visibility }) this.$store.dispatch('queueFlushAll') }, - openTab(tab) { + openTab (tab) { useInterfaceStore().openSettingsModalTab(tab) - }, + } }, computed: { ...mapGetters(['mergedConfig']), ...mapState(useInterfaceStore, { - mobileLayout: (state) => state.layoutType === 'mobile', + mobileLayout: state => state.layoutType === 'mobile' }), - triggerAttrs() { + triggerAttrs () { if (this.mobileLayout) { return {} } else { return { - title: this.$t('timeline.quick_filter_settings'), + title: this.$t('timeline.quick_filter_settings') } } }, - mainClass() { + mainClass () { if (this.mobileLayout) { return 'main-button' } else { return 'dropdown-item' } }, - loggedIn() { + loggedIn () { return !!this.$store.state.users.currentUser }, replyVisibilitySelf: { - get() { - return this.mergedConfig.replyVisibility === 'self' - }, - set() { - this.setReplyVisibility('self') - }, + get () { return this.mergedConfig.replyVisibility === 'self' }, + set () { this.setReplyVisibility('self') } }, replyVisibilityFollowing: { - get() { - return this.mergedConfig.replyVisibility === 'following' - }, - set() { - this.setReplyVisibility('following') - }, + get () { return this.mergedConfig.replyVisibility === 'following' }, + set () { this.setReplyVisibility('following') } }, replyVisibilityAll: { - get() { - return this.mergedConfig.replyVisibility === 'all' - }, - set() { - this.setReplyVisibility('all') - }, + get () { return this.mergedConfig.replyVisibility === 'all' }, + set () { this.setReplyVisibility('all') } }, hideMedia: { - get() { - return ( - this.mergedConfig.hideAttachments || - this.mergedConfig.hideAttachmentsInConv - ) - }, - set() { + get () { return this.mergedConfig.hideAttachments || this.mergedConfig.hideAttachmentsInConv }, + set () { const value = !this.hideMedia this.$store.dispatch('setOption', { name: 'hideAttachments', value }) - this.$store.dispatch('setOption', { - name: 'hideAttachmentsInConv', - value, - }) - }, + this.$store.dispatch('setOption', { name: 'hideAttachmentsInConv', value }) + } }, hideMutedPosts: { - get() { - return this.mergedConfig.hideFilteredStatuses - }, - set() { + get () { return this.mergedConfig.hideFilteredStatuses }, + set () { const value = !this.hideMutedPosts - this.$store.dispatch('setOption', { - name: 'hideFilteredStatuses', - value, - }) - }, + this.$store.dispatch('setOption', { name: 'hideFilteredStatuses', value }) + } }, muteBotStatuses: { - get() { - return this.mergedConfig.muteBotStatuses - }, - set() { + get () { return this.mergedConfig.muteBotStatuses }, + set () { const value = !this.muteBotStatuses this.$store.dispatch('setOption', { name: 'muteBotStatuses', value }) - }, + } }, muteSensitiveStatuses: { - get() { - return this.mergedConfig.muteSensitiveStatuses - }, - set() { + get () { return this.mergedConfig.muteSensitiveStatuses }, + set () { const value = !this.muteSensitiveStatuses - this.$store.dispatch('setOption', { - name: 'muteSensitiveStatuses', - value, - }) - }, - }, - }, + this.$store.dispatch('setOption', { name: 'muteSensitiveStatuses', value }) + } + } + } } export default QuickFilterSettings diff --git a/src/components/quick_view_settings/quick_view_settings.js b/src/components/quick_view_settings/quick_view_settings.js index e3606d116..5c98e0f88 100644 --- a/src/components/quick_view_settings/quick_view_settings.js +++ b/src/components/quick_view_settings/quick_view_settings.js @@ -1,108 +1,82 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { - faBars, - faFolderTree, - faList, - faWrench, -} from '@fortawesome/free-solid-svg-icons' -import { mapState } from 'pinia' import Popover from 'src/components/popover/popover.vue' import QuickFilterSettings from 'src/components/quick_filter_settings/quick_filter_settings.vue' -import { useInterfaceStore } from 'src/stores/interface' import { mapGetters } from 'vuex' +import { mapState } from 'pinia' +import { library } from '@fortawesome/fontawesome-svg-core' +import { faList, faFolderTree, faBars, faWrench } from '@fortawesome/free-solid-svg-icons' +import { useInterfaceStore } from 'src/stores/interface' -library.add(faList, faFolderTree, faBars, faWrench) +library.add( + faList, + faFolderTree, + faBars, + faWrench +) const QuickViewSettings = { props: { - conversation: Boolean, + conversation: Boolean }, components: { Popover, - QuickFilterSettings, + QuickFilterSettings }, methods: { - setConversationDisplay(visibility) { - this.$store.dispatch('setOption', { - name: 'conversationDisplay', - value: visibility, - }) + setConversationDisplay (visibility) { + this.$store.dispatch('setOption', { name: 'conversationDisplay', value: visibility }) }, - openTab(tab) { + openTab (tab) { useInterfaceStore().openSettingsModalTab(tab) - }, + } }, computed: { ...mapGetters(['mergedConfig']), ...mapState(useInterfaceStore, { - mobileLayout: (state) => state.layoutType === 'mobile', + mobileLayout: state => state.layoutType === 'mobile' }), - loggedIn() { + loggedIn () { return !!this.$store.state.users.currentUser }, conversationDisplay: { - get() { - return this.mergedConfig.conversationDisplay - }, - set(newVal) { - this.setConversationDisplay(newVal) - }, + get () { return this.mergedConfig.conversationDisplay }, + set (newVal) { this.setConversationDisplay(newVal) } }, autoUpdate: { - get() { - return this.mergedConfig.streaming - }, - set() { + get () { return this.mergedConfig.streaming }, + set () { const value = !this.autoUpdate this.$store.dispatch('setOption', { name: 'streaming', value }) - }, + } }, collapseWithSubjects: { - get() { - return this.mergedConfig.collapseMessageWithSubject - }, - set() { + get () { return this.mergedConfig.collapseMessageWithSubject }, + set () { const value = !this.collapseWithSubjects - this.$store.dispatch('setOption', { - name: 'collapseMessageWithSubject', - value, - }) - }, + this.$store.dispatch('setOption', { name: 'collapseMessageWithSubject', value }) + } }, showUserAvatars: { - get() { - return this.mergedConfig.mentionLinkShowAvatar - }, - set() { + get () { return this.mergedConfig.mentionLinkShowAvatar }, + set () { const value = !this.showUserAvatars - this.$store.dispatch('setOption', { - name: 'mentionLinkShowAvatar', - value, - }) - }, + this.$store.dispatch('setOption', { name: 'mentionLinkShowAvatar', value }) + } }, muteBotStatuses: { - get() { - return this.mergedConfig.muteBotStatuses - }, - set() { + get () { return this.mergedConfig.muteBotStatuses }, + set () { const value = !this.muteBotStatuses this.$store.dispatch('setOption', { name: 'muteBotStatuses', value }) - }, + } }, muteSensitiveStatuses: { - get() { - return this.mergedConfig.muteSensitiveStatuses - }, - set() { + get () { return this.mergedConfig.muteSensitiveStatuses }, + set () { const value = !this.muteSensitiveStatuses - this.$store.dispatch('setOption', { - name: 'muteSensitiveStatuses', - value, - }) - }, - }, - }, + this.$store.dispatch('setOption', { name: 'muteSensitiveStatuses', value }) + } + } + } } export default QuickViewSettings diff --git a/src/components/quotes_timeline/quotes_timeline.js b/src/components/quotes_timeline/quotes_timeline.js index b9b3e8f10..a5f42da56 100644 --- a/src/components/quotes_timeline/quotes_timeline.js +++ b/src/components/quotes_timeline/quotes_timeline.js @@ -1,36 +1,26 @@ import Timeline from '../timeline/timeline.vue' const QuotesTimeline = { - created() { + created () { this.$store.commit('clearTimeline', { timeline: 'quotes' }) - this.$store.dispatch('startFetchingTimeline', { - timeline: 'quotes', - statusId: this.statusId, - }) + this.$store.dispatch('startFetchingTimeline', { timeline: 'quotes', statusId: this.statusId }) }, components: { - Timeline, + Timeline }, computed: { - statusId() { - return this.$route.params.id - }, - timeline() { - return this.$store.state.statuses.timelines.quotes - }, + statusId () { return this.$route.params.id }, + timeline () { return this.$store.state.statuses.timelines.quotes } }, watch: { - statusId() { + statusId () { this.$store.commit('clearTimeline', { timeline: 'quotes' }) - this.$store.dispatch('startFetchingTimeline', { - timeline: 'quotes', - statusId: this.statusId, - }) - }, + this.$store.dispatch('startFetchingTimeline', { timeline: 'quotes', statusId: this.statusId }) + } }, - unmounted() { + unmounted () { this.$store.dispatch('stopFetchingTimeline', 'quotes') - }, + } } export default QuotesTimeline diff --git a/src/components/range_input/range_input.vue b/src/components/range_input/range_input.vue index 91d3dcc3b..2f8645c0b 100644 --- a/src/components/range_input/range_input.vue +++ b/src/components/range_input/range_input.vue @@ -54,22 +54,13 @@ diff --git a/src/components/registration/registration.js b/src/components/registration/registration.js index a84031fe4..53a678680 100644 --- a/src/components/registration/registration.js +++ b/src/components/registration/registration.js @@ -1,15 +1,13 @@ import useVuelidate from '@vuelidate/core' import { required, requiredIf, sameAs } from '@vuelidate/validators' -import { DAY } from 'src/services/date_utils/date_utils.js' import { mapActions, mapState } from 'vuex' -import localeService from '../../services/locale/locale.service.js' import InterfaceLanguageSwitcher from '../interface_language_switcher/interface_language_switcher.vue' +import localeService from '../../services/locale/locale.service.js' +import { DAY } from 'src/services/date_utils/date_utils.js' import TermsOfServicePanel from '../terms_of_service_panel/terms_of_service_panel.vue' const registration = { - setup() { - return { v$: useVuelidate() } - }, + setup () { return { v$: useVuelidate() } }, data: () => ({ user: { email: '', @@ -19,15 +17,15 @@ const registration = { confirm: '', birthday: '', reason: '', - language: [''], + language: [''] }, - captcha: {}, + captcha: {} }), components: { InterfaceLanguageSwitcher, - TermsOfServicePanel, + TermsOfServicePanel }, - validations() { + validations () { return { user: { email: { required: requiredIf(() => this.accountActivationRequired) }, @@ -36,23 +34,20 @@ const registration = { password: { required }, confirm: { required, - sameAs: sameAs(this.user.password), + sameAs: sameAs(this.user.password) }, birthday: { required: requiredIf(() => this.birthdayRequired), - maxValue: (value) => { - return ( - !this.birthdayRequired || - new Date(value).getTime() <= this.birthdayMin.getTime() - ) - }, + maxValue: value => { + return !this.birthdayRequired || new Date(value).getTime() <= this.birthdayMin.getTime() + } }, reason: { required: requiredIf(() => this.accountApprovalRequired) }, - language: {}, - }, + language: {} + } } }, - created() { + created () { if ((!this.registrationOpen && !this.token) || this.signedIn) { this.$router.push({ name: 'root' }) } @@ -60,16 +55,14 @@ const registration = { this.setCaptcha() }, computed: { - token() { - return this.$route.params.token - }, - bioPlaceholder() { + token () { return this.$route.params.token }, + bioPlaceholder () { return this.replaceNewlines(this.$t('registration.bio_placeholder')) }, - reasonPlaceholder() { + reasonPlaceholder () { return this.replaceNewlines(this.$t('registration.reason_placeholder')) }, - birthdayMin() { + birthdayMin () { const minAge = this.birthdayMinAge const today = new Date() today.setUTCMilliseconds(0) @@ -80,20 +73,12 @@ const registration = { minDate.setTime(today.getTime() - minAge * DAY) return minDate }, - birthdayMinAttr() { + birthdayMinAttr () { return this.birthdayMin.toJSON().replace(/T.+$/, '') }, - birthdayMinFormatted() { - const browserLocale = localeService.internalToBrowserLocale( - this.$i18n.locale, - ) - return ( - this.user.birthday && - new Date(Date.parse(this.birthdayMin)).toLocaleDateString( - browserLocale, - { timeZone: 'UTC', day: 'numeric', month: 'long', year: 'numeric' }, - ) - ) + birthdayMinFormatted () { + const browserLocale = localeService.internalToBrowserLocale(this.$i18n.locale) + return this.user.birthday && new Date(Date.parse(this.birthdayMin)).toLocaleDateString(browserLocale, { timeZone: 'UTC', day: 'numeric', month: 'long', year: 'numeric' }) }, ...mapState({ registrationOpen: (state) => state.instance.registrationOpen, @@ -104,17 +89,15 @@ const registration = { hasSignUpNotice: (state) => !!state.users.signUpNotice.message, termsOfService: (state) => state.instance.tos, embeddedToS: (state) => state.instance.embeddedToS, - accountActivationRequired: (state) => - state.instance.accountActivationRequired, - accountApprovalRequired: (state) => - state.instance.accountApprovalRequired, + accountActivationRequired: (state) => state.instance.accountActivationRequired, + accountApprovalRequired: (state) => state.instance.accountApprovalRequired, birthdayRequired: (state) => state.instance.birthdayRequired, - birthdayMinAge: (state) => state.instance.birthdayMinAge, - }), + birthdayMinAge: (state) => state.instance.birthdayMinAge + }) }, methods: { ...mapActions(['signUp', 'getCaptcha']), - async submit() { + async submit () { this.user.nickname = this.user.username this.user.token = this.token @@ -122,9 +105,7 @@ const registration = { this.user.captcha_token = this.captcha.token this.user.captcha_answer_data = this.captcha.answer_data if (this.user.language) { - this.user.language = localeService.internalToBackendLocaleMulti( - this.user.language.filter((k) => k), - ) + this.user.language = localeService.internalToBackendLocaleMulti(this.user.language.filter(k => k)) } this.v$.$touch() @@ -143,15 +124,13 @@ const registration = { } } }, - setCaptcha() { - this.getCaptcha().then((cpt) => { - this.captcha = cpt - }) + setCaptcha () { + this.getCaptcha().then(cpt => { this.captcha = cpt }) }, - replaceNewlines(str) { + replaceNewlines (str) { return str.replace(/\s*\n\s*/g, ' \n') - }, - }, + } + } } export default registration diff --git a/src/components/remote_follow/remote_follow.js b/src/components/remote_follow/remote_follow.js index a583b6f09..951b59419 100644 --- a/src/components/remote_follow/remote_follow.js +++ b/src/components/remote_follow/remote_follow.js @@ -1,9 +1,9 @@ export default { props: ['user'], computed: { - subscribeUrl() { + subscribeUrl () { const serverUrl = new URL(this.user.statusnet_profile_url) return `${serverUrl.protocol}//${serverUrl.host}/main/ostatus` - }, - }, + } + } } diff --git a/src/components/remote_user_resolver/remote_user_resolver.js b/src/components/remote_user_resolver/remote_user_resolver.js index 430f56c84..9b5e511e0 100644 --- a/src/components/remote_user_resolver/remote_user_resolver.js +++ b/src/components/remote_user_resolver/remote_user_resolver.js @@ -1,16 +1,14 @@ const RemoteUserResolver = { data: () => ({ - error: false, + error: false }), - mounted() { + mounted () { this.redirect() }, methods: { - redirect() { - const acct = - this.$route.params.username + '@' + this.$route.params.hostname - this.$store.state.api.backendInteractor - .fetchUser({ id: acct }) + redirect () { + const acct = this.$route.params.username + '@' + this.$route.params.hostname + this.$store.state.api.backendInteractor.fetchUser({ id: acct }) .then((externalUser) => { if (externalUser.error) { this.error = true @@ -19,15 +17,15 @@ const RemoteUserResolver = { const id = externalUser.id this.$router.replace({ name: 'external-user-profile', - params: { id }, + params: { id } }) } }) .catch(() => { this.error = true }) - }, - }, + } + } } export default RemoteUserResolver diff --git a/src/components/remove_follower_button/remove_follower_button.js b/src/components/remove_follower_button/remove_follower_button.js index b8f195815..052a519ff 100644 --- a/src/components/remove_follower_button/remove_follower_button.js +++ b/src/components/remove_follower_button/remove_follower_button.js @@ -2,49 +2,47 @@ import ConfirmModal from '../confirm_modal/confirm_modal.vue' export default { props: ['user', 'relationship'], - data() { + data () { return { inProgress: false, - showingConfirmRemoveFollower: false, + showingConfirmRemoveFollower: false } }, components: { - ConfirmModal, + ConfirmModal }, computed: { - label() { + label () { if (this.inProgress) { return this.$t('user_card.follow_progress') } else { return this.$t('user_card.remove_follower') } }, - shouldConfirmRemoveUserFromFollowers() { + shouldConfirmRemoveUserFromFollowers () { return this.$store.getters.mergedConfig.modalOnRemoveUserFromFollowers - }, + } }, methods: { - showConfirmRemoveUserFromFollowers() { + showConfirmRemoveUserFromFollowers () { this.showingConfirmRemoveFollower = true }, - hideConfirmRemoveUserFromFollowers() { + hideConfirmRemoveUserFromFollowers () { this.showingConfirmRemoveFollower = false }, - onClick() { + onClick () { if (!this.shouldConfirmRemoveUserFromFollowers) { this.doRemoveUserFromFollowers() } else { this.showConfirmRemoveUserFromFollowers() } }, - doRemoveUserFromFollowers() { + doRemoveUserFromFollowers () { this.inProgress = true - this.$store - .dispatch('removeUserFromFollowers', this.relationship.id) - .then(() => { - this.inProgress = false - }) + this.$store.dispatch('removeUserFromFollowers', this.relationship.id).then(() => { + this.inProgress = false + }) this.hideConfirmRemoveUserFromFollowers() - }, - }, + } + } } diff --git a/src/components/report/report.js b/src/components/report/report.js index a4df8eb6c..6e9f21eea 100644 --- a/src/components/report/report.js +++ b/src/components/report/report.js @@ -1,43 +1,37 @@ -import RichContent from 'src/components/rich_content/rich_content.jsx' -import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import { useReportsStore } from 'src/stores/reports' import Select from '../select/select.vue' import StatusContent from '../status_content/status_content.vue' import Timeago from '../timeago/timeago.vue' +import RichContent from 'src/components/rich_content/rich_content.jsx' +import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' const Report = { - props: ['reportId'], + props: [ + 'reportId' + ], components: { Select, StatusContent, Timeago, - RichContent, + RichContent }, computed: { - report() { + report () { return useReportsStore().reports[this.reportId] || {} }, state: { - get: function () { - return this.report.state - }, - set: function (val) { - this.setReportState(val) - }, - }, + get: function () { return this.report.state }, + set: function (val) { this.setReportState(val) } + } }, methods: { - generateUserProfileLink(user) { - return generateProfileLink( - user.id, - user.screen_name, - this.$store.state.instance.restrictedNicknames, - ) + generateUserProfileLink (user) { + return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames) }, - setReportState(state) { + setReportState (state) { return useReportsStore().setReportState({ id: this.report.id, state }) - }, - }, + } + } } export default Report diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx index 1a64b813f..5adc2443a 100644 --- a/src/components/rich_content/rich_content.jsx +++ b/src/components/rich_content/rich_content.jsx @@ -1,16 +1,11 @@ -import { flattenDeep, unescape as ldUnescape } from 'lodash' -import HashtagLink from 'src/components/hashtag_link/hashtag_link.vue' -import { MENTIONS_LIMIT } from 'src/components/mentions_line/mentions_line.js' -import MentionsLine from 'src/components/mentions_line/mentions_line.vue' -import StillImage from 'src/components/still-image/still-image.vue' -import StillImageEmojiPopover from 'src/components/still-image/still-image-emoji-popover.vue' -import { convertHtmlToLines } from 'src/services/html_converter/html_line_converter.service.js' +import { unescape, flattenDeep } from 'lodash' +import { getTagName, processTextForEmoji, getAttrs } from 'src/services/html_converter/utility.service.js' import { convertHtmlToTree } from 'src/services/html_converter/html_tree_converter.service.js' -import { - getAttrs, - getTagName, - processTextForEmoji, -} from 'src/services/html_converter/utility.service.js' +import { convertHtmlToLines } from 'src/services/html_converter/html_line_converter.service.js' +import StillImageEmojiPopover from 'src/components/still-image/still-image-emoji-popover.vue' +import MentionsLine from 'src/components/mentions_line/mentions_line.vue' +import { MENTIONS_LIMIT } from 'src/components/mentions_line/mentions_line.js' +import HashtagLink from 'src/components/hashtag_link/hashtag_link.vue' import './rich_content.scss' @@ -32,7 +27,7 @@ const MAYBE_LINE_BREAKING_ELEMENTS = [ 'h2', 'h3', 'h4', - 'h5', + 'h5' ] /** @@ -57,46 +52,46 @@ export default { name: 'RichContent', components: { MentionsLine, - HashtagLink, + HashtagLink }, props: { // Original html content html: { required: true, - type: String, + type: String }, attentions: { required: false, - default: () => [], + default: () => [] }, // Emoji object, as in status.emojis, note the "s" at the end... emoji: { required: true, - type: Array, + type: Array }, // Whether to handle links or not (posts: yes, everything else: no) handleLinks: { required: false, type: Boolean, - default: false, + default: false }, // Meme arrows greentext: { required: false, type: Boolean, - default: false, + default: false }, // Faint style (for notifs) faint: { required: false, type: Boolean, - default: false, + default: false }, // Collapse newlines collapse: { required: false, type: Boolean, - default: false, + default: false }, /* Content comes from current instance * @@ -108,11 +103,11 @@ export default { isLocal: { required: false, type: Boolean, - default: true, - }, + default: true + } }, // NEVER EVER TOUCH DATA INSIDE RENDER - render() { + render () { // Pre-process HTML const { newHtml: html } = preProcessPerLine(this.html, this.greentext) let currentMentions = null // Current chain of mentions, we group all mentions together @@ -129,7 +124,10 @@ export default { let tagsIndex = 0 const renderImage = (tag) => { - return + return } const renderHashtag = (attrs, children, encounteredTextReverse) => { @@ -139,14 +137,12 @@ export default { lastTags.push(linkData) } const { url, tag, content } = linkData - return + return } const renderMention = (attrs, children) => { const linkData = getLinkData(attrs, children, mentionIndex++) - linkData.notifying = this.attentions.some( - (a) => a.statusnet_profile_url === linkData.url, - ) + linkData.notifying = this.attentions.some(a => a.statusnet_profile_url === linkData.url) writtenMentions.push(linkData) if (currentMentions === null) { currentMentions = [] @@ -156,7 +152,7 @@ export default { invisibleMentions.push(linkData) } if (currentMentions.length === 1) { - return + return } else { return '' } @@ -175,28 +171,26 @@ export default { // in MentionsLine lastSpacing = item // Don't remove last space in a container (fixes poast mentions) - return index !== array.length - 1 && currentMentions !== null - ? item.trim() - : item + return (index !== array.length - 1) && (currentMentions !== null) ? item.trim() : item } currentMentions = null if (item.includes(':')) { - item = [ - '', - processTextForEmoji(item, this.emoji, ({ shortcode, url }) => { - return ( - - ) - }), - ] + item = ['', processTextForEmoji( + item, + this.emoji, + ({ shortcode, url }) => { + return + } + )] } return item } @@ -215,24 +209,18 @@ export default { * we have a tag right next to mentions */ const mentionsLinePadding = - // Padding is only needed if we just finished parsing mentions - previouslyMentions && - // Don't add padding if content is string and has padding already - !( - children && - typeof children[0] === 'string' && - children[0].match(/^\s/) - ) - ? lastSpacing - : '' + // Padding is only needed if we just finished parsing mentions + previouslyMentions && + // Don't add padding if content is string and has padding already + !(children && typeof children[0] === 'string' && children[0].match(/^\s/)) + ? lastSpacing + : '' if (MAYBE_LINE_BREAKING_ELEMENTS.includes(Tag)) { // all the elements that can cause a line change currentMentions = null - } else if (Tag === 'img') { - // replace images with StillImage + } else if (Tag === 'img') { // replace images with StillImage return ['', [mentionsLinePadding, renderImage(opener)], ''] - } else if (Tag === 'a' && this.handleLinks) { - // replace mentions with MentionLink + } else if (Tag === 'a' && this.handleLinks) { // replace mentions with MentionLink if (fullAttrs.class && fullAttrs.class.includes('mention')) { // Handling mentions here return renderMention(attrs, children) @@ -240,11 +228,7 @@ export default { currentMentions = null } } else if (Tag === 'span') { - if ( - this.handleLinks && - fullAttrs.class && - fullAttrs.class.includes('h-card') - ) { + if (this.handleLinks && fullAttrs.class && fullAttrs.class.includes('h-card')) { return ['', children.map(processItem), ''] } } @@ -252,8 +236,11 @@ export default { if (children !== undefined) { return [ '', - [mentionsLinePadding, [opener, children.map(processItem), closer]], - '', + [ + mentionsLinePadding, + [opener, children.map(processItem), closer] + ], + '' ] } else { return ['', [mentionsLinePadding, item], ''] @@ -269,31 +256,29 @@ export default { const emptyText = item.trim() === '' if (emptyText) return item if (!encounteredTextReverse) encounteredTextReverse = true - return ldUnescape(item) + return unescape(item) } else if (Array.isArray(item)) { // Handle tag nodes const [opener, children] = item const Tag = opener === '' ? '' : getTagName(opener) switch (Tag) { - case 'a': { - // replace mentions with MentionLink + case 'a': { // replace mentions with MentionLink if (!this.handleLinks) break const fullAttrs = getAttrs(opener, () => true) const attrs = getAttrs(opener, () => true) // should only be this if ( (fullAttrs.class && fullAttrs.class.includes('hashtag')) || // Pleroma style - fullAttrs.rel === 'tag' // Mastodon style + (fullAttrs.rel === 'tag') // Mastodon style ) { return renderHashtag(attrs, children, encounteredTextReverse) } else { attrs.target = '_blank' - const newChildren = [...children] - .reverse() - .map(processItemReverse) - .reverse() + const newChildren = [...children].reverse().map(processItemReverse).reverse() - return {newChildren} + return + { newChildren } + } } case '': @@ -305,9 +290,11 @@ export default { const newChildren = Array.isArray(children) ? [...children].reverse().map(processItemReverse).reverse() : children - return {newChildren} + return + { newChildren } + } else { - return + return } } return item @@ -319,29 +306,30 @@ export default { // DO NOT USE SLOTS they cause a re-render feedback loop here. // slots updated -> rerender -> emit -> update up the tree -> rerender -> ... // at least until vue3? - const result = ( - - {this.collapse - ? pass2.map((x) => { - if (!Array.isArray(x)) return x.replace(/\n/g, ' ') - return x.map((y) => (y.type === 'br' ? ' ' : y)) - }) - : pass2} - - ) + const result = + + { + this.collapse + ? pass2.map(x => { + if (!Array.isArray(x)) return x.replace(/\n/g, ' ') + return x.map(y => y.type === 'br' ? ' ' : y) + }) + : pass2 + } + const event = { lastTags, writtenMentions, writtenTags, - invisibleMentions, + invisibleMentions } // DO NOT MOVE TO UPDATE. BAD IDEA. this.$emit('parseReady', event) return result - }, + } } const getLinkData = (attrs, children, index) => { @@ -358,7 +346,7 @@ const getLinkData = (attrs, children, index) => { url: attrs.href, tag: attrs['data-tag'], content: flattenDeep(children).join(''), - textContent, + textContent } } @@ -374,36 +362,31 @@ export const preProcessPerLine = (html, greentext) => { const greentextHandle = new Set(['p', 'div']) const lines = convertHtmlToLines(html) - const newHtml = lines - .reverse() - .map((item, index, array) => { - if (!item.text) return item - const string = item.text + const newHtml = lines.reverse().map((item, index, array) => { + if (!item.text) return item + const string = item.text - // Greentext stuff - if ( - // Only if greentext is engaged - greentext && + // Greentext stuff + if ( + // Only if greentext is engaged + greentext && // Only handle p's and divs. Don't want to affect blockquotes, code etc - item.level.every((l) => greentextHandle.has(l)) && + item.level.every(l => greentextHandle.has(l)) && // Only if line begins with '>' or '<' (string.includes('>') || string.includes('<')) - ) { - const cleanedString = string - .replace(/<[^>]+?>/gi, '') // remove all tags - .replace(/@\w+/gi, '') // remove mentions (even failed ones) - .trim() - if (cleanedString.startsWith('>')) { - return `${string}` - } else if (cleanedString.startsWith('<')) { - return `${string}` - } + ) { + const cleanedString = string.replace(/<[^>]+?>/gi, '') // remove all tags + .replace(/@\w+/gi, '') // remove mentions (even failed ones) + .trim() + if (cleanedString.startsWith('>')) { + return `${string}` + } else if (cleanedString.startsWith('<')) { + return `${string}` } + } - return string - }) - .reverse() - .join('') + return string + }).reverse().join('') return { newHtml } } diff --git a/src/components/root.style.js b/src/components/root.style.js index 54c4c6095..5075e33c8 100644 --- a/src/components/root.style.js +++ b/src/components/root.style.js @@ -27,8 +27,8 @@ export default { // Selection colors '--selectionBackground': 'color | --accent', - '--selectionText': 'color | $textColor(--accent --text no-preserve)', - }, - }, - ], + '--selectionText': 'color | $textColor(--accent --text no-preserve)' + } + } + ] } diff --git a/src/components/roundness_input/roundness_input.vue b/src/components/roundness_input/roundness_input.vue index 04b623e86..1da71ca79 100644 --- a/src/components/roundness_input/roundness_input.vue +++ b/src/components/roundness_input/roundness_input.vue @@ -36,14 +36,16 @@ import Checkbox from '../checkbox/checkbox.vue' export default { components: { - Checkbox, + Checkbox }, - props: ['name', 'label', 'modelValue', 'fallback', 'disabled'], + props: [ + 'name', 'label', 'modelValue', 'fallback', 'disabled' + ], emits: ['update:modelValue'], computed: { - present() { + present () { return typeof this.modelValue !== 'undefined' - }, - }, + } + } } diff --git a/src/components/scope_selector/scope_selector.js b/src/components/scope_selector/scope_selector.js index 9d3a3a718..462892cb6 100644 --- a/src/components/scope_selector/scope_selector.js +++ b/src/components/scope_selector/scope_selector.js @@ -1,92 +1,90 @@ import { library } from '@fortawesome/fontawesome-svg-core' import { faEnvelope, - faGlobe, faLock, faLockOpen, + faGlobe } from '@fortawesome/free-solid-svg-icons' -library.add(faEnvelope, faGlobe, faLock, faLockOpen) +library.add( + faEnvelope, + faGlobe, + faLock, + faLockOpen +) const ScopeSelector = { props: { showAll: { required: true, - type: Boolean, + type: Boolean }, userDefault: { required: true, - type: String, + type: String }, originalScope: { required: false, - type: String, + type: String }, initialScope: { required: false, - type: String, + type: String }, onScopeChange: { required: true, - type: Function, + type: Function }, unstyled: { required: false, type: Boolean, - default: true, - }, + default: true + } }, - data() { + data () { return { - currentScope: this.initialScope, + currentScope: this.initialScope } }, computed: { - showNothing() { - return ( - !this.showPublic && - !this.showUnlisted && - !this.showPrivate && - !this.showDirect - ) + showNothing () { + return !this.showPublic && !this.showUnlisted && !this.showPrivate && !this.showDirect }, - showPublic() { + showPublic () { return this.originalScope !== 'direct' && this.shouldShow('public') }, - showUnlisted() { + showUnlisted () { return this.originalScope !== 'direct' && this.shouldShow('unlisted') }, - showPrivate() { + showPrivate () { return this.originalScope !== 'direct' && this.shouldShow('private') }, - showDirect() { + showDirect () { return this.shouldShow('direct') }, - css() { + css () { const style = this.unstyled ? 'button-unstyled' : 'button-default' return { public: [style, { toggled: this.currentScope === 'public' }], unlisted: [style, { toggled: this.currentScope === 'unlisted' }], private: [style, { toggled: this.currentScope === 'private' }], - direct: [style, { toggled: this.currentScope === 'direct' }], + direct: [style, { toggled: this.currentScope === 'direct' }] } - }, + } }, methods: { - shouldShow(scope) { - return ( - this.showAll || + shouldShow (scope) { + return this.showAll || this.currentScope === scope || this.originalScope === scope || this.userDefault === scope || scope === 'direct' - ) }, - changeVis(scope) { + changeVis (scope) { this.currentScope = scope this.onScopeChange && this.onScopeChange(scope) - }, - }, + } + } } export default ScopeSelector diff --git a/src/components/screen_reader_notice/screen_reader_notice.js b/src/components/screen_reader_notice/screen_reader_notice.js index b834be531..794b855ac 100644 --- a/src/components/screen_reader_notice/screen_reader_notice.js +++ b/src/components/screen_reader_notice/screen_reader_notice.js @@ -2,22 +2,20 @@ const ScreenReaderNotice = { props: { ariaLive: { type: String, - default: 'assertive', - }, + default: 'assertive' + } }, - data() { + data () { return { - currentText: '', + currentText: '' } }, methods: { - announce(text) { + announce (text) { this.currentText = text - setTimeout(() => { - this.currentText = '' - }, 1000) - }, - }, + setTimeout(() => { this.currentText = '' }, 1000) + } + } } export default ScreenReaderNotice diff --git a/src/components/scroll_top_button/scroll_top_button.js b/src/components/scroll_top_button/scroll_top_button.js index e4b908f0b..bdc45b9b4 100644 --- a/src/components/scroll_top_button/scroll_top_button.js +++ b/src/components/scroll_top_button/scroll_top_button.js @@ -3,16 +3,16 @@ const ScrollTopButton = { fast: { type: Boolean, required: false, - default: false, - }, + default: false + } }, methods: { scrollToTop() { - const speed = this.fast ? 'instant' : 'smooth' + const speed = this.fast ? 'instant' : 'smooth'; window.scrollTo({ top: 0, behavior: speed }) - }, - }, + } + } } export default ScrollTopButton diff --git a/src/components/scrollbar.style.js b/src/components/scrollbar.style.js index fbe952076..1168f67d8 100644 --- a/src/components/scrollbar.style.js +++ b/src/components/scrollbar.style.js @@ -1,16 +1,12 @@ export default { name: 'Scrollbar', - selector: [ - '::-webkit-scrollbar-button', - '::-webkit-scrollbar-thumb', - '::-webkit-resizer', - ], + selector: ['::-webkit-scrollbar-button', '::-webkit-scrollbar-thumb', '::-webkit-resizer'], notEditable: true, // for now defaultRules: [ { directives: { - background: '--wallpaper', - }, - }, - ], + background: '--wallpaper' + } + } + ] } diff --git a/src/components/scrollbar_element.style.js b/src/components/scrollbar_element.style.js index 6f238e1f8..ef1ea8136 100644 --- a/src/components/scrollbar_element.style.js +++ b/src/components/scrollbar_element.style.js @@ -5,7 +5,7 @@ const border = (top, shadow) => ({ spread: 0, color: shadow ? '#000000' : '#FFFFFF', alpha: 0.2, - inset: true, + inset: true }) const buttonInsetFakeBorders = [border(true, false), border(false, true)] @@ -16,7 +16,7 @@ const buttonOuterShadow = { blur: 2, spread: 0, color: '#000000', - alpha: 1, + alpha: 1 } const hoverGlow = { @@ -25,7 +25,7 @@ const hoverGlow = { blur: 4, spread: 0, color: '--text', - alpha: 1, + alpha: 1 } export default { @@ -35,66 +35,68 @@ export default { states: { pressed: ':active', hover: ':is(:hover, :focus-visible, :has(:focus-visible)):not(:disabled)', - disabled: ':disabled', + disabled: ':disabled' }, - validInnerComponents: ['Text'], + validInnerComponents: [ + 'Text' + ], defaultRules: [ { directives: { background: '--fg', shadow: [buttonOuterShadow, ...buttonInsetFakeBorders], - roundness: 3, - }, + roundness: 3 + } }, { state: ['hover'], directives: { - shadow: [hoverGlow, ...buttonInsetFakeBorders], - }, + shadow: [hoverGlow, ...buttonInsetFakeBorders] + } }, { state: ['pressed'], directives: { - shadow: [buttonOuterShadow, ...inputInsetFakeBorders], - }, + shadow: [buttonOuterShadow, ...inputInsetFakeBorders] + } }, { state: ['hover', 'pressed'], directives: { - shadow: [hoverGlow, ...inputInsetFakeBorders], - }, + shadow: [hoverGlow, ...inputInsetFakeBorders] + } }, { state: ['toggled'], directives: { background: '--accent,-24.2', - shadow: [buttonOuterShadow, ...inputInsetFakeBorders], - }, + shadow: [buttonOuterShadow, ...inputInsetFakeBorders] + } }, { state: ['toggled', 'hover'], directives: { background: '--accent,-24.2', - shadow: [hoverGlow, ...inputInsetFakeBorders], - }, + shadow: [hoverGlow, ...inputInsetFakeBorders] + } }, { state: ['disabled'], directives: { background: '$blend(--inheritedBackground 0.25 --parent)', - shadow: [...buttonInsetFakeBorders], - }, + shadow: [...buttonInsetFakeBorders] + } }, { component: 'Text', parent: { component: 'Button', - state: ['disabled'], + state: ['disabled'] }, directives: { textOpacity: 0.25, - textOpacityMode: 'blend', - }, - }, - ], + textOpacityMode: 'blend' + } + } + ] } diff --git a/src/components/search/search.js b/src/components/search/search.js index 1625fe691..877d6f300 100644 --- a/src/components/search/search.js +++ b/src/components/search/search.js @@ -1,23 +1,31 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faCircleNotch, faSearch } from '@fortawesome/free-solid-svg-icons' -import { uniqBy } from 'lodash' -import map from 'lodash/map' -import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' -import Conversation from '../conversation/conversation.vue' import FollowCard from '../follow_card/follow_card.vue' +import Conversation from '../conversation/conversation.vue' import Status from '../status/status.vue' +import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' +import map from 'lodash/map' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faCircleNotch, + faSearch +} from '@fortawesome/free-solid-svg-icons' +import { uniqBy } from 'lodash' -library.add(faCircleNotch, faSearch) +library.add( + faCircleNotch, + faSearch +) const Search = { components: { FollowCard, Conversation, Status, - TabSwitcher, + TabSwitcher }, - props: ['query'], - data() { + props: [ + 'query' + ], + data () { return { loaded: false, loading: false, @@ -29,37 +37,36 @@ const Search = { statusesOffset: 0, lastStatusFetchCount: 0, - lastQuery: '', + lastQuery: '' } }, computed: { - users() { - return this.userIds.map((userId) => this.$store.getters.findUser(userId)) + users () { + return this.userIds.map(userId => this.$store.getters.findUser(userId)) }, - visibleStatuses() { + visibleStatuses () { const allStatusesObject = this.$store.state.statuses.allStatusesObject - return this.statuses.filter( - (status) => - allStatusesObject[status.id] && !allStatusesObject[status.id].deleted, + return this.statuses.filter(status => + allStatusesObject[status.id] && !allStatusesObject[status.id].deleted ) - }, + } }, - mounted() { + mounted () { this.search(this.query) }, watch: { - query(newValue) { + query (newValue) { this.searchTerm = newValue this.search(newValue) - }, + } }, methods: { - newQuery(query) { + newQuery (query) { this.$router.push({ name: 'search', query: { query } }) this.$refs.searchInput.focus() }, - search(query, searchType = null) { + search (query, searchType = null) { if (!query) { this.loading = false return @@ -76,14 +83,8 @@ const Search = { this.lastStatusFetchCount = 0 } - this.$store - .dispatch('search', { - q: query, - resolve: true, - offset: this.statusesOffset, - type: searchType, - }) - .then((data) => { + this.$store.dispatch('search', { q: query, resolve: true, offset: this.statusesOffset, type: searchType }) + .then(data => { this.loading = false const oldLength = this.statuses.length @@ -103,14 +104,14 @@ const Search = { this.lastQuery = query }) }, - resultCount(tabName) { + resultCount (tabName) { const length = this[tabName].length return length === 0 ? '' : ` (${length})` }, - onResultTabSwitch(key) { + onResultTabSwitch (key) { this.currenResultTab = key }, - getActiveTab() { + getActiveTab () { if (this.visibleStatuses.length > 0) { return 'statuses' } else if (this.users.length > 0) { @@ -121,10 +122,10 @@ const Search = { return 'statuses' }, - lastHistoryRecord(hashtag) { + lastHistoryRecord (hashtag) { return hashtag.history && hashtag.history[0] - }, - }, + } + } } export default Search diff --git a/src/components/search_bar/search_bar.js b/src/components/search_bar/search_bar.js index ebe30d303..3b297f098 100644 --- a/src/components/search_bar/search_bar.js +++ b/src/components/search_bar/search_bar.js @@ -1,27 +1,33 @@ import { library } from '@fortawesome/fontawesome-svg-core' -import { faSearch, faTimes } from '@fortawesome/free-solid-svg-icons' +import { + faTimes, + faSearch +} from '@fortawesome/free-solid-svg-icons' -library.add(faTimes, faSearch) +library.add( + faTimes, + faSearch +) const SearchBar = { data: () => ({ searchTerm: undefined, hidden: true, - error: false, + error: false }), watch: { $route: function (route) { if (route.name === 'search') { this.searchTerm = route.query.query } - }, + } }, methods: { - find(searchTerm) { + find (searchTerm) { this.$router.push({ name: 'search', query: { query: searchTerm } }) this.$refs.searchInput.focus() }, - toggleHidden() { + toggleHidden () { this.hidden = !this.hidden this.$emit('toggled', this.hidden) this.$nextTick(() => { @@ -29,8 +35,8 @@ const SearchBar = { this.$refs.searchInput.focus() } }) - }, - }, + } + } } export default SearchBar diff --git a/src/components/select/select.js b/src/components/select/select.js index 9bf9f7e23..34d64fd22 100644 --- a/src/components/select/select.js +++ b/src/components/select/select.js @@ -1,9 +1,19 @@ import { library } from '@fortawesome/fontawesome-svg-core' -import { faChevronDown } from '@fortawesome/free-solid-svg-icons' +import { + faChevronDown +} from '@fortawesome/free-solid-svg-icons' -library.add(faChevronDown) +library.add( + faChevronDown +) export default { emits: ['update:modelValue'], - props: ['modelValue', 'disabled', 'unstyled', 'kind', 'attrs'], + props: [ + 'modelValue', + 'disabled', + 'unstyled', + 'kind', + 'attrs' + ] } diff --git a/src/components/select/select_motion.vue b/src/components/select/select_motion.vue index 21262c256..45e278fc6 100644 --- a/src/components/select/select_motion.vue +++ b/src/components/select/select_motion.vue @@ -54,20 +54,20 @@ import { computed, defineEmits, defineProps, nextTick } from 'vue' const props = defineProps({ modelValue: { type: Array, - required: true, + required: true }, selectedId: { type: Number, - required: true, + required: true }, disabled: { type: Boolean, - default: false, + default: false }, getAddValue: { type: Function, - required: true, - }, + required: true + } }) const emit = defineEmits(['update:modelValue', 'update:selectedId']) @@ -116,10 +116,7 @@ const del = async () => { emit('update:modelValue', newModel) await nextTick() - emit( - 'update:selectedId', - newModel.length === 0 ? undefined : Math.max(props.selectedId - 1, 0), - ) + emit('update:selectedId', newModel.length === 0 ? undefined : Math.max(props.selectedId - 1, 0)) } diff --git a/src/components/selectable_list/selectable_list.js b/src/components/selectable_list/selectable_list.js index b08a3e9a5..10980d46a 100644 --- a/src/components/selectable_list/selectable_list.js +++ b/src/components/selectable_list/selectable_list.js @@ -1,48 +1,48 @@ -import Checkbox from '../checkbox/checkbox.vue' import List from '../list/list.vue' +import Checkbox from '../checkbox/checkbox.vue' const SelectableList = { components: { List, - Checkbox, + Checkbox }, props: { items: { type: Array, - default: () => [], + default: () => [] }, getKey: { type: Function, - default: (item) => item.id, - }, + default: item => item.id + } }, - data() { + data () { return { - selected: [], + selected: [] } }, computed: { - allKeys() { + allKeys () { return this.items.map(this.getKey) }, - filteredSelected() { - return this.allKeys.filter((key) => this.selected.indexOf(key) !== -1) + filteredSelected () { + return this.allKeys.filter(key => this.selected.indexOf(key) !== -1) }, - allSelected() { + allSelected () { return this.filteredSelected.length === this.items.length }, - noneSelected() { + noneSelected () { return this.filteredSelected.length === 0 }, - someSelected() { + someSelected () { return !this.allSelected && !this.noneSelected - }, + } }, methods: { - isSelected(item) { + isSelected (item) { return this.filteredSelected.indexOf(this.getKey(item)) !== -1 }, - toggle(checked, item) { + toggle (checked, item) { const key = this.getKey(item) const oldChecked = this.isSelected(key) if (checked !== oldChecked) { @@ -53,14 +53,14 @@ const SelectableList = { } } }, - toggleAll(value) { + toggleAll (value) { if (value) { this.selected = this.allKeys.slice(0) } else { this.selected = [] } - }, - }, + } + } } export default SelectableList diff --git a/src/components/settings_modal/admin_tabs/auth_tab.js b/src/components/settings_modal/admin_tabs/auth_tab.js index 627150587..a078291e6 100644 --- a/src/components/settings_modal/admin_tabs/auth_tab.js +++ b/src/components/settings_modal/admin_tabs/auth_tab.js @@ -1,19 +1,20 @@ -import AttachmentSetting from '../helpers/attachment_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' -import GroupSetting from '../helpers/group_setting.vue' import IntegerSetting from '../helpers/integer_setting.vue' -import ListSetting from '../helpers/list_setting.vue' -import MapSetting from '../helpers/map_setting.vue' -import SharedComputedObject from '../helpers/shared_computed_object.js' import StringSetting from '../helpers/string_setting.vue' import TupleSetting from '../helpers/tuple_setting.vue' +import GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' +import ListSetting from '../helpers/list_setting.vue' +import MapSetting from '../helpers/map_setting.vue' + +import SharedComputedObject from '../helpers/shared_computed_object.js' const AuthTab = { - provide() { + provide () { return { defaultDraftMode: true, - defaultSource: 'admin', + defaultSource: 'admin' } }, components: { @@ -25,16 +26,14 @@ const AuthTab = { AttachmentSetting, GroupSetting, ListSetting, - MapSetting, + MapSetting }, computed: { ...SharedComputedObject(), - LDAPEnabled() { - return this.$store.state.adminSettings.draft[':pleroma'][':ldap'][ - ':enabled' - ] + LDAPEnabled () { + return this.$store.state.adminSettings.draft[':pleroma'][':ldap'][':enabled'] }, - }, + } } export default AuthTab diff --git a/src/components/settings_modal/admin_tabs/emoji_tab.js b/src/components/settings_modal/admin_tabs/emoji_tab.js index 69605ff03..7c137e35f 100644 --- a/src/components/settings_modal/admin_tabs/emoji_tab.js +++ b/src/components/settings_modal/admin_tabs/emoji_tab.js @@ -1,24 +1,30 @@ +import { clone, assign } from 'lodash' +import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' +import StringSetting from '../helpers/string_setting.vue' +import Checkbox from 'components/checkbox/checkbox.vue' +import StillImage from 'components/still-image/still-image.vue' +import Select from 'components/select/select.vue' +import Popover from 'components/popover/popover.vue' +import ConfirmModal from 'components/confirm_modal/confirm_modal.vue' +import ModifiedIndicator from '../helpers/modified_indicator.vue' +import EmojiEditingPopover from '../helpers/emoji_editing_popover.vue' +import { useInterfaceStore } from 'src/stores/interface' + +import SharedComputedObject from '../helpers/shared_computed_object.js' import { library } from '@fortawesome/fontawesome-svg-core' import { faArrowsRotate, - faDownload, faFolderOpen, faServer, + faDownload } from '@fortawesome/free-solid-svg-icons' -import Checkbox from 'components/checkbox/checkbox.vue' -import ConfirmModal from 'components/confirm_modal/confirm_modal.vue' -import Popover from 'components/popover/popover.vue' -import Select from 'components/select/select.vue' -import StillImage from 'components/still-image/still-image.vue' -import { assign, clone } from 'lodash' -import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' -import { useInterfaceStore } from 'src/stores/interface' -import EmojiEditingPopover from '../helpers/emoji_editing_popover.vue' -import ModifiedIndicator from '../helpers/modified_indicator.vue' -import SharedComputedObject from '../helpers/shared_computed_object.js' -import StringSetting from '../helpers/string_setting.vue' -library.add(faArrowsRotate, faFolderOpen, faDownload, faServer) +library.add( + faArrowsRotate, + faFolderOpen, + faDownload, + faServer +) const EmojiTab = { components: { @@ -30,14 +36,14 @@ const EmojiTab = { Popover, ConfirmModal, ModifiedIndicator, - EmojiEditingPopover, + EmojiEditingPopover }, - data() { + data () { return { - knownLocalPacks: {}, - knownRemotePacks: {}, - editedMetadata: {}, + knownLocalPacks: { }, + knownRemotePacks: { }, + editedMetadata: { }, packName: '', newPackName: '', deleteModalVisible: false, @@ -45,20 +51,20 @@ const EmojiTab = { remotePackDownloadAs: '', remotePackURL: '', - remotePackFile: null, + remotePackFile: null } }, - provide() { + provide () { return { emojiAddr: this.emojiAddr } }, computed: { ...SharedComputedObject(), - pack() { + pack () { return this.packName !== '' ? this.knownPacks[this.packName] : undefined }, - packMeta() { + packMeta () { if (this.packName === '') return {} if (this.editedMetadata[this.packName] === undefined) { this.editedMetadata[this.packName] = clone(this.pack.pack) @@ -66,36 +72,31 @@ const EmojiTab = { return this.editedMetadata[this.packName] }, - knownPacks() { + knownPacks () { // Copy the object itself but not the children, so they are still passed by reference and modified const result = clone(this.knownLocalPacks) for (const instName in this.knownRemotePacks) { for (const instPack in this.knownRemotePacks[instName]) { - result[`${instPack}@${instName}`] = - this.knownRemotePacks[instName][instPack] + result[`${instPack}@${instName}`] = this.knownRemotePacks[instName][instPack] } } return result }, - downloadWillReplaceLocal() { - return ( - (this.remotePackDownloadAs.trim() === '' && - this.pack.remote && - this.pack.remote.baseName in this.knownLocalPacks) || - this.remotePackDownloadAs in this.knownLocalPacks - ) - }, + downloadWillReplaceLocal () { + return (this.remotePackDownloadAs.trim() === '' && this.pack.remote && this.pack.remote.baseName in this.knownLocalPacks) || + (this.remotePackDownloadAs in this.knownLocalPacks) + } }, methods: { - reloadEmoji() { + reloadEmoji () { this.$store.state.api.backendInteractor.reloadEmoji() }, - importFromFS() { + importFromFS () { this.$store.state.api.backendInteractor.importEmojiFromFS() }, - emojiAddr(name) { + emojiAddr (name) { if (this.pack.remote !== undefined) { // Remote pack return `${this.pack.remote.instance}/emoji/${encodeURIComponent(this.pack.remote.baseName)}/${name}` @@ -104,141 +105,115 @@ const EmojiTab = { } }, - createEmojiPack() { - this.$store.state.api.backendInteractor - .createEmojiPack({ name: this.newPackName }) - .then((resp) => resp.json()) - .then((resp) => { - if (resp === 'ok') { - return this.refreshPackList() - } else { - this.displayError(resp.error) - return Promise.reject(resp) - } - }) - .then(() => { - this.packName = this.newPackName - this.newPackName = '' - }) + createEmojiPack () { + this.$store.state.api.backendInteractor.createEmojiPack( + { name: this.newPackName } + ).then(resp => resp.json()).then(resp => { + if (resp === 'ok') { + return this.refreshPackList() + } else { + this.displayError(resp.error) + return Promise.reject(resp) + } + }).then(() => { + this.packName = this.newPackName + this.newPackName = '' + }) }, - deleteEmojiPack() { - this.$store.state.api.backendInteractor - .deleteEmojiPack({ name: this.packName }) - .then((resp) => resp.json()) - .then((resp) => { - if (resp === 'ok') { - return this.refreshPackList() - } else { - this.displayError(resp.error) - return Promise.reject(resp) - } - }) - .then(() => { - delete this.editedMetadata[this.packName] + deleteEmojiPack () { + this.$store.state.api.backendInteractor.deleteEmojiPack( + { name: this.packName } + ).then(resp => resp.json()).then(resp => { + if (resp === 'ok') { + return this.refreshPackList() + } else { + this.displayError(resp.error) + return Promise.reject(resp) + } + }).then(() => { + delete this.editedMetadata[this.packName] - this.deleteModalVisible = false - this.packName = '' - }) + this.deleteModalVisible = false + this.packName = '' + }) }, - metaEdited(prop) { + metaEdited (prop) { if (!this.pack) return const def = this.pack.pack[prop] || '' const edited = this.packMeta[prop] || '' return edited !== def }, - savePackMetadata() { - this.$store.state.api.backendInteractor - .saveEmojiPackMetadata({ name: this.packName, newData: this.packMeta }) - .then((resp) => resp.json()) - .then((resp) => { - if (resp.error !== undefined) { - this.displayError(resp.error) - return - } + savePackMetadata () { + this.$store.state.api.backendInteractor.saveEmojiPackMetadata({ name: this.packName, newData: this.packMeta }).then( + resp => resp.json() + ).then(resp => { + if (resp.error !== undefined) { + this.displayError(resp.error) + return + } - // Update actual pack data - this.pack.pack = resp - // Delete edited pack data, should auto-update itself - delete this.editedMetadata[this.packName] - }) + // Update actual pack data + this.pack.pack = resp + // Delete edited pack data, should auto-update itself + delete this.editedMetadata[this.packName] + }) }, - updatePackFiles(newFiles, packName) { + updatePackFiles (newFiles, packName) { this.knownPacks[packName].files = newFiles this.sortPackFiles(packName) }, - loadPacksPaginated(listFunction) { + loadPacksPaginated (listFunction) { const pageSize = 25 const allPacks = {} - return listFunction({ - instance: this.remotePackInstance, - page: 1, - pageSize: 0, - }) - .then((data) => data.json()) - .then((data) => { - if (data.error !== undefined) { - return Promise.reject(data.error) - } + return listFunction({ instance: this.remotePackInstance, page: 1, pageSize: 0 }) + .then(data => data.json()) + .then(data => { + if (data.error !== undefined) { return Promise.reject(data.error) } let resultingPromise = Promise.resolve({}) for (let i = 0; i < Math.ceil(data.count / pageSize); i++) { - resultingPromise = resultingPromise - .then(() => - listFunction({ - instance: this.remotePackInstance, - page: i, - pageSize, - }), - ) - .then((data) => data.json()) - .then((pageData) => { - if (pageData.error !== undefined) { - return Promise.reject(pageData.error) - } + resultingPromise = resultingPromise.then(() => listFunction({ instance: this.remotePackInstance, page: i, pageSize }) + ).then(data => data.json()).then(pageData => { + if (pageData.error !== undefined) { return Promise.reject(pageData.error) } - assign(allPacks, pageData.packs) - }) + assign(allPacks, pageData.packs) + }) } return resultingPromise }) .then(() => allPacks) - .catch((data) => { + .catch(data => { this.displayError(data) }) }, - refreshPackList() { - this.loadPacksPaginated( - this.$store.state.api.backendInteractor.listEmojiPacks, - ).then((allPacks) => { - this.knownLocalPacks = allPacks - for (const name of Object.keys(this.knownLocalPacks)) { - this.sortPackFiles(name) - } - }) - }, - listRemotePacks() { - this.loadPacksPaginated( - this.$store.state.api.backendInteractor.listRemoteEmojiPacks, - ) - .then((allPacks) => { - let inst = this.remotePackInstance - if (!inst.startsWith('http')) { - inst = 'https://' + inst + refreshPackList () { + this.loadPacksPaginated(this.$store.state.api.backendInteractor.listEmojiPacks) + .then(allPacks => { + this.knownLocalPacks = allPacks + for (const name of Object.keys(this.knownLocalPacks)) { + this.sortPackFiles(name) } + }) + }, + listRemotePacks () { + this.loadPacksPaginated(this.$store.state.api.backendInteractor.listRemoteEmojiPacks) + .then(allPacks => { + let inst = this.remotePackInstance + if (!inst.startsWith('http')) { inst = 'https://' + inst } const instUrl = new URL(inst) inst = instUrl.host for (const packName in allPacks) { allPacks[packName].remote = { baseName: packName, - instance: instUrl.origin, + instance: instUrl.origin } } @@ -247,101 +222,89 @@ const EmojiTab = { this.sortPackFiles(`${pack}@${inst}`) } }) - .catch((data) => { + .catch(data => { this.displayError(data) }) }, - downloadRemotePack() { + downloadRemotePack () { if (this.remotePackDownloadAs.trim() === '') { this.remotePackDownloadAs = this.pack.remote.baseName } - this.$store.state.api.backendInteractor - .downloadRemoteEmojiPack({ - instance: this.pack.remote.instance, - packName: this.pack.remote.baseName, - as: this.remotePackDownloadAs, - }) - .then((data) => data.json()) - .then((resp) => { + this.$store.state.api.backendInteractor.downloadRemoteEmojiPack({ + instance: this.pack.remote.instance, packName: this.pack.remote.baseName, as: this.remotePackDownloadAs + }) + .then(data => data.json()) + .then(resp => { if (resp === 'ok') { return this.refreshPackList() } else { this.displayError(resp.error) return Promise.reject(resp) } - }) - .then(() => { + }).then(() => { this.packName = this.remotePackDownloadAs this.remotePackDownloadAs = '' }) }, - downloadRemoteURLPack() { - this.$store.state.api.backendInteractor - .downloadRemoteEmojiPackZIP({ - url: this.remotePackURL, - packName: this.newPackName, - }) - .then((data) => data.json()) - .then((resp) => { + downloadRemoteURLPack () { + this.$store.state.api.backendInteractor.downloadRemoteEmojiPackZIP({ + url: this.remotePackURL, packName: this.newPackName + }) + .then(data => data.json()) + .then(resp => { if (resp === 'ok') { return this.refreshPackList() } else { this.displayError(resp.error) return Promise.reject(resp) } - }) - .then(() => { + }).then(() => { this.packName = this.newPackName this.newPackName = '' this.remotePackURL = '' }) }, - downloadRemoteFilePack() { - this.$store.state.api.backendInteractor - .downloadRemoteEmojiPackZIP({ - file: this.remotePackFile[0], - packName: this.newPackName, - }) - .then((data) => data.json()) - .then((resp) => { + downloadRemoteFilePack () { + this.$store.state.api.backendInteractor.downloadRemoteEmojiPackZIP({ + file: this.remotePackFile[0], packName: this.newPackName + }) + .then(data => data.json()) + .then(resp => { if (resp === 'ok') { return this.refreshPackList() } else { this.displayError(resp.error) return Promise.reject(resp) } - }) - .then(() => { + }).then(() => { this.packName = this.newPackName this.newPackName = '' this.remotePackURL = '' }) }, - displayError(msg) { + displayError (msg) { useInterfaceStore().pushGlobalNotice({ messageKey: 'admin_dash.emoji.error', messageArgs: [msg], - level: 'error', + level: 'error' }) }, - sortPackFiles(nameOfPack) { + sortPackFiles (nameOfPack) { // Sort by key - const sorted = Object.keys(this.knownPacks[nameOfPack].files) - .sort() - .reduce((acc, key) => { - if (key.length === 0) return acc - acc[key] = this.knownPacks[nameOfPack].files[key] - return acc - }, {}) + const sorted = Object.keys(this.knownPacks[nameOfPack].files).sort().reduce((acc, key) => { + if (key.length === 0) return acc + acc[key] = this.knownPacks[nameOfPack].files[key] + return acc + }, {}) this.knownPacks[nameOfPack].files = sorted - }, + } }, - mounted() { + mounted () { this.refreshPackList() - }, + } } export default EmojiTab diff --git a/src/components/settings_modal/admin_tabs/federation_tab.js b/src/components/settings_modal/admin_tabs/federation_tab.js index 33c688eb4..97b4e0040 100644 --- a/src/components/settings_modal/admin_tabs/federation_tab.js +++ b/src/components/settings_modal/admin_tabs/federation_tab.js @@ -1,18 +1,19 @@ -import AttachmentSetting from '../helpers/attachment_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue' -import GroupSetting from '../helpers/group_setting.vue' import IntegerSetting from '../helpers/integer_setting.vue' +import StringSetting from '../helpers/string_setting.vue' +import GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' import ListSetting from '../helpers/list_setting.vue' import ListTupleSetting from '../helpers/list_tuple_setting.vue' import MapSetting from '../helpers/map_setting.vue' + import SharedComputedObject from '../helpers/shared_computed_object.js' -import StringSetting from '../helpers/string_setting.vue' const FederationTab = { - provide() { + provide () { return { defaultDraftMode: true, - defaultSource: 'admin', + defaultSource: 'admin' } }, components: { @@ -23,11 +24,11 @@ const FederationTab = { ListSetting, ListTupleSetting, GroupSetting, - MapSetting, + MapSetting }, computed: { - ...SharedComputedObject(), - }, + ...SharedComputedObject() + } } export default FederationTab diff --git a/src/components/settings_modal/admin_tabs/frontends_tab.js b/src/components/settings_modal/admin_tabs/frontends_tab.js index 92faa169d..c63e76214 100644 --- a/src/components/settings_modal/admin_tabs/frontends_tab.js +++ b/src/components/settings_modal/admin_tabs/frontends_tab.js @@ -1,27 +1,32 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faGlobe } from '@fortawesome/free-solid-svg-icons' -import PanelLoading from 'src/components/panel_loading/panel_loading.vue' -import Popover from 'src/components/popover/popover.vue' -import { useInterfaceStore } from 'src/stores/interface' import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' -import GroupSetting from '../helpers/group_setting.vue' import IntegerSetting from '../helpers/integer_setting.vue' -import SharedComputedObject from '../helpers/shared_computed_object.js' import StringSetting from '../helpers/string_setting.vue' +import GroupSetting from '../helpers/group_setting.vue' +import Popover from 'src/components/popover/popover.vue' +import PanelLoading from 'src/components/panel_loading/panel_loading.vue' +import { useInterfaceStore } from 'src/stores/interface' -library.add(faGlobe) +import SharedComputedObject from '../helpers/shared_computed_object.js' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faGlobe +} from '@fortawesome/free-solid-svg-icons' + +library.add( + faGlobe +) const FrontendsTab = { - provide() { + provide () { return { defaultDraftMode: true, - defaultSource: 'admin', + defaultSource: 'admin' } }, - data() { + data () { return { - working: false, + working: false } }, components: { @@ -31,26 +36,26 @@ const FrontendsTab = { StringSetting, GroupSetting, PanelLoading, - Popover, + Popover }, - created() { + created () { if (this.user.rights.admin) { this.$store.dispatch('loadFrontendsStuff') } }, computed: { ...SharedComputedObject(), - frontends() { + frontends () { return this.$store.state.adminSettings.frontends - }, + } }, methods: { - canInstall(frontend) { - const fe = this.frontends.find((f) => f.name === frontend.name) + canInstall (frontend) { + const fe = this.frontends.find(f => f.name === frontend.name) if (!fe) return false return fe.refs.includes(frontend.ref) }, - getSuggestedRef(frontend) { + getSuggestedRef (frontend) { if (this.adminDraft) { const defaultFe = this.adminDraft[':pleroma'][':frontends'][':primary'] if (defaultFe?.name === frontend.name && this.canInstall(defaultFe)) { @@ -62,14 +67,13 @@ const FrontendsTab = { return frontend.refs[0] } }, - update(frontend, suggestRef) { + update (frontend, suggestRef) { const ref = suggestRef || this.getSuggestedRef(frontend) const { name } = frontend const payload = { name, ref } this.working = true - this.$store.state.api.backendInteractor - .installFrontend({ payload }) + this.$store.state.api.backendInteractor.installFrontend({ payload }) .finally(() => { this.working = false }) @@ -82,32 +86,29 @@ const FrontendsTab = { messageKey: 'admin_dash.frontend.failure_installing_frontend', messageArgs: { version: name + '/' + ref, - reason: reason.error, + reason: reason.error }, - timeout: 5000, + timeout: 5000 }) } else { useInterfaceStore().pushGlobalNotice({ level: 'success', messageKey: 'admin_dash.frontend.success_installing_frontend', messageArgs: { - version: name + '/' + ref, + version: name + '/' + ref }, - timeout: 2000, + timeout: 2000 }) } }) }, - setDefault(frontend, suggestRef) { + setDefault (frontend, suggestRef) { const ref = suggestRef || this.getSuggestedRef(frontend) const { name } = frontend - this.$store.commit('updateAdminDraft', { - path: [':pleroma', ':frontends', ':primary'], - value: { name, ref }, - }) - }, - }, + this.$store.commit('updateAdminDraft', { path: [':pleroma', ':frontends', ':primary'], value: { name, ref } }) + } + } } export default FrontendsTab diff --git a/src/components/settings_modal/admin_tabs/http_tab.js b/src/components/settings_modal/admin_tabs/http_tab.js index 91a6df68a..82e2bb010 100644 --- a/src/components/settings_modal/admin_tabs/http_tab.js +++ b/src/components/settings_modal/admin_tabs/http_tab.js @@ -1,21 +1,22 @@ -import { get } from 'lodash' -import AttachmentSetting from '../helpers/attachment_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' -import GroupSetting from '../helpers/group_setting.vue' import IntegerSetting from '../helpers/integer_setting.vue' +import StringSetting from '../helpers/string_setting.vue' +import GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' import ListSetting from '../helpers/list_setting.vue' +import TupleSetting from '../helpers/tuple_setting.vue' import MapSetting from '../helpers/map_setting.vue' import ProxySetting from '../helpers/proxy_setting.vue' + import SharedComputedObject from '../helpers/shared_computed_object.js' -import StringSetting from '../helpers/string_setting.vue' -import TupleSetting from '../helpers/tuple_setting.vue' +import { get } from 'lodash' const HTTPTab = { - provide() { + provide () { return { defaultDraftMode: true, - defaultSource: 'admin', + defaultSource: 'admin' } }, components: { @@ -28,23 +29,18 @@ const HTTPTab = { GroupSetting, ListSetting, TupleSetting, - ProxySetting, + ProxySetting }, computed: { ...SharedComputedObject(), - sslOptions() { - const desc = get( - this.$store.state.adminSettings.descriptions, - ':pleroma.:http.:adapter.:ssl_options.:versions', - ) - return new Set( - desc.suggestions.map((option) => ({ - label: option.replace(':tlsv', 'TLS v'), - value: option, - })), - ) + sslOptions () { + const desc = get(this.$store.state.adminSettings.descriptions, ':pleroma.:http.:adapter.:ssl_options.:versions') + return new Set(desc.suggestions.map(option => ({ + label: option.replace(':tlsv', 'TLS v'), + value: option + }))) }, - }, + } } export default HTTPTab diff --git a/src/components/settings_modal/admin_tabs/instance_tab.js b/src/components/settings_modal/admin_tabs/instance_tab.js index 66fe3866a..ddbd58a88 100644 --- a/src/components/settings_modal/admin_tabs/instance_tab.js +++ b/src/components/settings_modal/admin_tabs/instance_tab.js @@ -1,22 +1,22 @@ -import { get } from 'lodash' -import AttachmentSetting from '../helpers/attachment_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' +import IntegerSetting from '../helpers/integer_setting.vue' +import StringSetting from '../helpers/string_setting.vue' import ColorSetting from '../helpers/color_setting.vue' import GroupSetting from '../helpers/group_setting.vue' -import IntegerSetting from '../helpers/integer_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' import ListSetting from '../helpers/list_setting.vue' -import MapSetting from '../helpers/map_setting.vue' import PWAManifestIconsSetting from '../helpers/pwa_manifest_icons_setting.vue' +import MapSetting from '../helpers/map_setting.vue' import SharedComputedObject from '../helpers/shared_computed_object.js' -import StringSetting from '../helpers/string_setting.vue' +import { get } from 'lodash' const InstanceTab = { - provide() { + provide () { return { defaultDraftMode: true, - defaultSource: 'admin', + defaultSource: 'admin' } }, components: { @@ -29,40 +29,25 @@ const InstanceTab = { ListSetting, PWAManifestIconsSetting, MapSetting, - GroupSetting, + GroupSetting }, computed: { ...SharedComputedObject(), - providersOptions() { - const desc = get(this.$store.state.adminSettings.descriptions, [ - ':pleroma', - 'Pleroma.Web.Metadata', - ':providers', - ]) - return new Set( - desc.suggestions.map((option) => ({ - label: option.replace('Pleroma.Web.Metadata.Providers.', ''), - value: option, - })), - ) + providersOptions () { + const desc = get(this.$store.state.adminSettings.descriptions, [':pleroma', 'Pleroma.Web.Metadata', ':providers']) + return new Set(desc.suggestions.map(option => ({ + label: option.replace('Pleroma.Web.Metadata.Providers.', ''), + value: option + }))) }, - limitLocalContentOptions() { - const desc = get(this.$store.state.adminSettings.descriptions, [ - ':pleroma', - ':instance', - ':limit_to_local_content', - ]) - return new Set( - desc.suggestions.map((option) => ({ - label: - option !== 'false' - ? this.$t('admin_dash.instance.' + option) - : this.$t('general.no'), - value: option, - })), - ) - }, - }, + limitLocalContentOptions () { + const desc = get(this.$store.state.adminSettings.descriptions, [':pleroma', ':instance', ':limit_to_local_content']) + return new Set(desc.suggestions.map(option => ({ + label: option !== 'false' ? this.$t('admin_dash.instance.' + option) : this.$t('general.no'), + value: option + }))) + } + } } export default InstanceTab diff --git a/src/components/settings_modal/admin_tabs/instance_tab.vue b/src/components/settings_modal/admin_tabs/instance_tab.vue index 585fe303c..fa55cef41 100644 --- a/src/components/settings_modal/admin_tabs/instance_tab.vue +++ b/src/components/settings_modal/admin_tabs/instance_tab.vue @@ -49,16 +49,10 @@
  • - +
  • - +
  • diff --git a/src/components/settings_modal/admin_tabs/job_queues_tab.js b/src/components/settings_modal/admin_tabs/job_queues_tab.js index 66a0e7e18..b0f583c55 100644 --- a/src/components/settings_modal/admin_tabs/job_queues_tab.js +++ b/src/components/settings_modal/admin_tabs/job_queues_tab.js @@ -1,18 +1,19 @@ -import AttachmentSetting from '../helpers/attachment_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' -import GroupSetting from '../helpers/group_setting.vue' import IntegerSetting from '../helpers/integer_setting.vue' -import ListSetting from '../helpers/list_setting.vue' -import SharedComputedObject from '../helpers/shared_computed_object.js' import StringSetting from '../helpers/string_setting.vue' import TupleSetting from '../helpers/tuple_setting.vue' +import GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' +import ListSetting from '../helpers/list_setting.vue' + +import SharedComputedObject from '../helpers/shared_computed_object.js' const JobQueuesTab = { - provide() { + provide () { return { defaultDraftMode: true, - defaultSource: 'admin', + defaultSource: 'admin' } }, components: { @@ -23,11 +24,11 @@ const JobQueuesTab = { TupleSetting, AttachmentSetting, GroupSetting, - ListSetting, + ListSetting }, computed: { - ...SharedComputedObject(), - }, + ...SharedComputedObject() + } } export default JobQueuesTab diff --git a/src/components/settings_modal/admin_tabs/limits_tab.js b/src/components/settings_modal/admin_tabs/limits_tab.js index 1f9a7be54..c1126f49c 100644 --- a/src/components/settings_modal/admin_tabs/limits_tab.js +++ b/src/components/settings_modal/admin_tabs/limits_tab.js @@ -1,19 +1,20 @@ import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' import IntegerSetting from '../helpers/integer_setting.vue' -import SharedComputedObject from '../helpers/shared_computed_object.js' import StringSetting from '../helpers/string_setting.vue' +import SharedComputedObject from '../helpers/shared_computed_object.js' + const LimitsTab = { components: { BooleanSetting, ChoiceSetting, IntegerSetting, - StringSetting, + StringSetting }, computed: { - ...SharedComputedObject(), - }, + ...SharedComputedObject() + } } export default LimitsTab diff --git a/src/components/settings_modal/admin_tabs/links_tab.js b/src/components/settings_modal/admin_tabs/links_tab.js index 91bcf5d81..026b099a5 100644 --- a/src/components/settings_modal/admin_tabs/links_tab.js +++ b/src/components/settings_modal/admin_tabs/links_tab.js @@ -1,20 +1,21 @@ -import { get } from 'lodash' -import Checkbox from 'src/components/checkbox/checkbox.vue' -import AttachmentSetting from '../helpers/attachment_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' -import GroupSetting from '../helpers/group_setting.vue' import IntegerSetting from '../helpers/integer_setting.vue' +import StringSetting from '../helpers/string_setting.vue' +import GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' import ListSetting from '../helpers/list_setting.vue' +import Checkbox from 'src/components/checkbox/checkbox.vue' + import SharedComputedObject from '../helpers/shared_computed_object.js' -import StringSetting from '../helpers/string_setting.vue' +import { get } from 'lodash' const LinksTab = { - provide() { + provide () { return { defaultDraftMode: true, - defaultSource: 'admin', + defaultSource: 'admin' } }, components: { @@ -25,109 +26,84 @@ const LinksTab = { AttachmentSetting, GroupSetting, ListSetting, - Checkbox, + Checkbox }, computed: { - classIsPresent() { - return ( - this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Formatter'][ - ':class' - ] !== false - ) + classIsPresent () { + return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Formatter'][':class'] !== false }, - relIsPresent() { - return ( - this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Formatter'][ - ':rel' - ] !== false - ) + relIsPresent () { + return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Formatter'][':rel'] !== false }, - truncateIsPresent() { - return ( - this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Formatter'][ - ':truncate' - ] !== false - ) + truncateIsPresent () { + return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Formatter'][':truncate'] !== false }, - truncateDescription() { - return get(this.$store.state.adminSettings.descriptions, [ - ':pleroma', - 'Pleroma.Formatter', - ':truncate', - ]) + truncateDescription () { + return get(this.$store.state.adminSettings.descriptions, [':pleroma', 'Pleroma.Formatter', ':truncate']) }, - ttlSettersOptions() { - const desc = get( - this.$store.state.adminSettings.descriptions, - ':pleroma.:rich_media.:ttl_setters', - ) - return new Set( - desc.suggestions.map((option) => ({ - label: option.replace('Pleroma.Web.RichMedia.Parser.TTL.', ''), - value: option, - })), - ) + ttlSettersOptions () { + const desc = get(this.$store.state.adminSettings.descriptions, ':pleroma.:rich_media.:ttl_setters') + return new Set(desc.suggestions.map(option => ({ + label: option.replace('Pleroma.Web.RichMedia.Parser.TTL.', ''), + value: option + }))) }, - parsersOptions() { - const desc = get( - this.$store.state.adminSettings.descriptions, - ':pleroma.:rich_media.:parsers', - ) - return new Set( - desc.suggestions.map((option) => ({ - label: option.replace('Pleroma.Web.RichMedia.Parsers.', ''), - value: option, - })), - ) + parsersOptions () { + const desc = get(this.$store.state.adminSettings.descriptions, ':pleroma.:rich_media.:parsers') + return new Set(desc.suggestions.map(option => ({ + label: option.replace('Pleroma.Web.RichMedia.Parsers.', ''), + value: option + }))) }, - validateTLDOptions() { - return [ - { - label: this.$t('general.yes'), - value: true, - }, - { - label: this.$t('general.no'), - value: false, - }, - { - label: this.$t('admin_dash.links.no_scheme'), - value: ':no_scheme', - }, - ] + validateTLDOptions () { + return [{ + label: this.$t('general.yes'), + value: true + }, { + label: this.$t('general.no'), + value: false + }, { + label: this.$t('admin_dash.links.no_scheme'), + value: ':no_scheme' + }] }, - mediaProxyEnabled() { - return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][ - ':enabled' - ] + mediaProxyEnabled () { + return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][':enabled'] }, - mediaInvalidationProvider() { - return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][ - ':invalidation' - ][':provider'] + mediaInvalidationProvider () { + return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][':invalidation'][':provider'] }, - ...SharedComputedObject(), + ...SharedComputedObject() }, methods: { - checkRel(e) { - this.$store.commit('updateAdminDraft', { - path: [':pleroma', 'Pleroma.Formatter', ':rel'], - value: e ? '' : false, - }) + checkRel (e) { + this.$store.commit( + 'updateAdminDraft', + { + path: [':pleroma','Pleroma.Formatter',':rel'], + value: e ? '' : false + } + ) }, - checkClass(e) { - this.$store.commit('updateAdminDraft', { - path: [':pleroma', 'Pleroma.Formatter', ':class'], - value: e ? '' : false, - }) + checkClass (e) { + this.$store.commit( + 'updateAdminDraft', + { + path: [':pleroma','Pleroma.Formatter',':class'], + value: e ? '' : false + } + ) }, - checkTruncate(e) { - this.$store.commit('updateAdminDraft', { - path: [':pleroma', 'Pleroma.Formatter', ':truncate'], - value: e ? 20 : false, - }) - }, - }, + checkTruncate (e) { + this.$store.commit( + 'updateAdminDraft', + { + path: [':pleroma','Pleroma.Formatter',':truncate'], + value: e ? 20 : false + } + ) + } + } } export default LinksTab diff --git a/src/components/settings_modal/admin_tabs/mailer_tab.js b/src/components/settings_modal/admin_tabs/mailer_tab.js index 0b909334b..44b2f33df 100644 --- a/src/components/settings_modal/admin_tabs/mailer_tab.js +++ b/src/components/settings_modal/admin_tabs/mailer_tab.js @@ -1,17 +1,18 @@ -import AttachmentSetting from '../helpers/attachment_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' -import ColorSetting from '../helpers/color_setting.vue' -import GroupSetting from '../helpers/group_setting.vue' import IntegerSetting from '../helpers/integer_setting.vue' -import SharedComputedObject from '../helpers/shared_computed_object.js' import StringSetting from '../helpers/string_setting.vue' +import GroupSetting from '../helpers/group_setting.vue' +import ColorSetting from '../helpers/color_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' + +import SharedComputedObject from '../helpers/shared_computed_object.js' const MailerTab = { - provide() { + provide () { return { defaultDraftMode: true, - defaultSource: 'admin', + defaultSource: 'admin' } }, components: { @@ -21,50 +22,44 @@ const MailerTab = { StringSetting, AttachmentSetting, ColorSetting, - GroupSetting, + GroupSetting }, computed: { - adaptersLabels() { + adaptersLabels () { const prefix = 'Swoosh.Adapters.' const descriptions = this.$store.state.adminSettings.descriptions - const options = - descriptions[':pleroma']['Pleroma.Emails.Mailer'][':adapter'] - .suggestions + const options = descriptions[':pleroma']['Pleroma.Emails.Mailer'][':adapter'].suggestions - return Object.fromEntries( - options.map((value) => [value, value.replace(prefix, '')]), - ) + return Object.fromEntries(options.map(value => [ + value, value.replace(prefix, '') + ])) }, - startTLSLabels() { + startTLSLabels () { return { ':always': this.$t('admin_dash.generic_enforcement.always'), ':if_available': this.$t('admin_dash.generic_enforcement.if_available'), - ':never': this.$t('admin_dash.generic_enforcement.never'), + ':never': this.$t('admin_dash.generic_enforcement.never') } // return Object.fromEntries(options.map(value => [ // value, value.replace(prefix, '') // ])) }, - adapter() { - return this.$store.state.adminSettings.draft[':pleroma'][ - 'Pleroma.Emails.Mailer' - ][':adapter'] + adapter () { + return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Emails.Mailer'][':adapter'] }, - mailerEnabled() { - return this.$store.state.adminSettings.draft[':pleroma'][ - 'Pleroma.Emails.Mailer' - ][':enabled'] + mailerEnabled () { + return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Emails.Mailer'][':enabled'] }, - ...SharedComputedObject(), + ...SharedComputedObject() }, methods: { - adapterHasKey(key) { + adapterHasKey (key) { const descriptions = this.$store.state.adminSettings.descriptions const mailerStuff = descriptions[':pleroma']['Pleroma.Emails.Mailer'] const adapterStuff = mailerStuff[':subgroup,' + this.adapter] - return Object.hasOwn(adapterStuff, key) - }, - }, + return Object.prototype.hasOwnProperty.call(adapterStuff, key) + } + } } export default MailerTab diff --git a/src/components/settings_modal/admin_tabs/media_proxy_tab.js b/src/components/settings_modal/admin_tabs/media_proxy_tab.js index 6c7231312..af82593bc 100644 --- a/src/components/settings_modal/admin_tabs/media_proxy_tab.js +++ b/src/components/settings_modal/admin_tabs/media_proxy_tab.js @@ -1,17 +1,18 @@ -import AttachmentSetting from '../helpers/attachment_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' -import GroupSetting from '../helpers/group_setting.vue' import IntegerSetting from '../helpers/integer_setting.vue' -import ListSetting from '../helpers/list_setting.vue' -import SharedComputedObject from '../helpers/shared_computed_object.js' import StringSetting from '../helpers/string_setting.vue' +import GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' +import ListSetting from '../helpers/list_setting.vue' + +import SharedComputedObject from '../helpers/shared_computed_object.js' const MediaProxyTab = { - provide() { + provide () { return { defaultDraftMode: true, - defaultSource: 'admin', + defaultSource: 'admin' } }, components: { @@ -21,21 +22,17 @@ const MediaProxyTab = { StringSetting, AttachmentSetting, GroupSetting, - ListSetting, + ListSetting }, computed: { - mediaProxyEnabled() { - return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][ - ':enabled' - ] + mediaProxyEnabled () { + return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][':enabled'] }, - mediaInvalidationProvider() { - return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][ - ':invalidation' - ][':provider'] + mediaInvalidationProvider () { + return this.$store.state.adminSettings.draft[':pleroma'][':media_proxy'][':invalidation'][':provider'] }, - ...SharedComputedObject(), - }, + ...SharedComputedObject() + } } export default MediaProxyTab diff --git a/src/components/settings_modal/admin_tabs/monitoring_tab.js b/src/components/settings_modal/admin_tabs/monitoring_tab.js index 03b347a72..8593b9d69 100644 --- a/src/components/settings_modal/admin_tabs/monitoring_tab.js +++ b/src/components/settings_modal/admin_tabs/monitoring_tab.js @@ -1,21 +1,26 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faGlobe } from '@fortawesome/free-solid-svg-icons' -import AttachmentSetting from '../helpers/attachment_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' -import GroupSetting from '../helpers/group_setting.vue' import IntegerSetting from '../helpers/integer_setting.vue' -import ListSetting from '../helpers/list_setting.vue' -import SharedComputedObject from '../helpers/shared_computed_object.js' import StringSetting from '../helpers/string_setting.vue' +import GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' +import ListSetting from '../helpers/list_setting.vue' -library.add(faGlobe) +import SharedComputedObject from '../helpers/shared_computed_object.js' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faGlobe +} from '@fortawesome/free-solid-svg-icons' + +library.add( + faGlobe +) const MonitoringTab = { - provide() { + provide () { return { defaultDraftMode: true, - defaultSource: 'admin', + defaultSource: 'admin' } }, components: { @@ -25,12 +30,13 @@ const MonitoringTab = { StringSetting, AttachmentSetting, GroupSetting, - ListSetting, + ListSetting }, computed: { - ...SharedComputedObject(), + ...SharedComputedObject() }, - methods: {}, + methods: { + } } export default MonitoringTab diff --git a/src/components/settings_modal/admin_tabs/other_tab.js b/src/components/settings_modal/admin_tabs/other_tab.js index a31bcf307..dc6550d27 100644 --- a/src/components/settings_modal/admin_tabs/other_tab.js +++ b/src/components/settings_modal/admin_tabs/other_tab.js @@ -1,20 +1,21 @@ -import AttachmentSetting from '../helpers/attachment_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' +import IntegerSetting from '../helpers/integer_setting.vue' +import StringSetting from '../helpers/string_setting.vue' import ColorSetting from '../helpers/color_setting.vue' import GroupSetting from '../helpers/group_setting.vue' -import IntegerSetting from '../helpers/integer_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' import ListSetting from '../helpers/list_setting.vue' -import MapSetting from '../helpers/map_setting.vue' import PWAManifestIconsSetting from '../helpers/pwa_manifest_icons_setting.vue' +import MapSetting from '../helpers/map_setting.vue' + import SharedComputedObject from '../helpers/shared_computed_object.js' -import StringSetting from '../helpers/string_setting.vue' const OtherTab = { - provide() { + provide () { return { defaultDraftMode: true, - defaultSource: 'admin', + defaultSource: 'admin' } }, components: { @@ -27,11 +28,11 @@ const OtherTab = { ListSetting, PWAManifestIconsSetting, MapSetting, - GroupSetting, + GroupSetting }, computed: { - ...SharedComputedObject(), - }, + ...SharedComputedObject() + } } export default OtherTab diff --git a/src/components/settings_modal/admin_tabs/posts_tab.js b/src/components/settings_modal/admin_tabs/posts_tab.js index 654b18ed8..d9f213594 100644 --- a/src/components/settings_modal/admin_tabs/posts_tab.js +++ b/src/components/settings_modal/admin_tabs/posts_tab.js @@ -1,20 +1,21 @@ -import AttachmentSetting from '../helpers/attachment_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' +import IntegerSetting from '../helpers/integer_setting.vue' +import StringSetting from '../helpers/string_setting.vue' import ColorSetting from '../helpers/color_setting.vue' import GroupSetting from '../helpers/group_setting.vue' -import IntegerSetting from '../helpers/integer_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' import ListSetting from '../helpers/list_setting.vue' -import MapSetting from '../helpers/map_setting.vue' import PWAManifestIconsSetting from '../helpers/pwa_manifest_icons_setting.vue' +import MapSetting from '../helpers/map_setting.vue' + import SharedComputedObject from '../helpers/shared_computed_object.js' -import StringSetting from '../helpers/string_setting.vue' const PostsTab = { - provide() { + provide () { return { defaultDraftMode: true, - defaultSource: 'admin', + defaultSource: 'admin' } }, components: { @@ -27,11 +28,11 @@ const PostsTab = { ListSetting, PWAManifestIconsSetting, MapSetting, - GroupSetting, + GroupSetting }, computed: { - ...SharedComputedObject(), - }, + ...SharedComputedObject() + } } export default PostsTab diff --git a/src/components/settings_modal/admin_tabs/rates_tab.js b/src/components/settings_modal/admin_tabs/rates_tab.js index 812c25b00..c602dcc8a 100644 --- a/src/components/settings_modal/admin_tabs/rates_tab.js +++ b/src/components/settings_modal/admin_tabs/rates_tab.js @@ -3,18 +3,18 @@ import RateSetting from '../helpers/rate_setting.vue' import SharedComputedObject from '../helpers/shared_computed_object.js' const RatesTab = { - provide() { + provide () { return { defaultDraftMode: true, - defaultSource: 'admin', + defaultSource: 'admin' } }, components: { RateSetting, }, computed: { - ...SharedComputedObject(), - }, + ...SharedComputedObject() + } } export default RatesTab diff --git a/src/components/settings_modal/admin_tabs/registrations_tab.js b/src/components/settings_modal/admin_tabs/registrations_tab.js index 8ec5e0d4b..3ce6c8044 100644 --- a/src/components/settings_modal/admin_tabs/registrations_tab.js +++ b/src/components/settings_modal/admin_tabs/registrations_tab.js @@ -1,18 +1,19 @@ -import AttachmentSetting from '../helpers/attachment_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' -import GroupSetting from '../helpers/group_setting.vue' import IntegerSetting from '../helpers/integer_setting.vue' -import ListSetting from '../helpers/list_setting.vue' -import SharedComputedObject from '../helpers/shared_computed_object.js' import StringSetting from '../helpers/string_setting.vue' import TupleSetting from '../helpers/tuple_setting.vue' +import GroupSetting from '../helpers/group_setting.vue' +import AttachmentSetting from '../helpers/attachment_setting.vue' +import ListSetting from '../helpers/list_setting.vue' + +import SharedComputedObject from '../helpers/shared_computed_object.js' const RegistrationsTab = { - provide() { + provide () { return { defaultDraftMode: true, - defaultSource: 'admin', + defaultSource: 'admin' } }, components: { @@ -23,11 +24,11 @@ const RegistrationsTab = { TupleSetting, AttachmentSetting, GroupSetting, - ListSetting, + ListSetting }, computed: { - ...SharedComputedObject(), - }, + ...SharedComputedObject() + } } export default RegistrationsTab diff --git a/src/components/settings_modal/admin_tabs/uploads_tab.js b/src/components/settings_modal/admin_tabs/uploads_tab.js index 760206499..40a184db1 100644 --- a/src/components/settings_modal/admin_tabs/uploads_tab.js +++ b/src/components/settings_modal/admin_tabs/uploads_tab.js @@ -1,51 +1,46 @@ import BooleanSetting from '../helpers/boolean_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue' import IntegerSetting from '../helpers/integer_setting.vue' -import SharedComputedObject from '../helpers/shared_computed_object.js' import StringSetting from '../helpers/string_setting.vue' +import SharedComputedObject from '../helpers/shared_computed_object.js' + const UploadsTab = { - provide() { + provide () { return { defaultDraftMode: true, - defaultSource: 'admin', + defaultSource: 'admin' } }, - data() { + data () { return { - uploaders: [ - { - key: 'Pleroma.Uploaders.Local', - value: 'Pleroma.Uploaders.Local', - label: this.$t('admin_dash.uploads.local_uploader'), - }, - { - key: 'Pleroma.Uploaders.IPFS', - value: 'Pleroma.Uploaders.IPFS', - label: 'IPFS', - }, - { - key: 'Pleroma.Uploaders.S3', - value: 'Pleroma.Uploaders.S3', - label: 'S3', - }, - ], + uploaders: [{ + key: 'Pleroma.Uploaders.Local', + value: 'Pleroma.Uploaders.Local', + label: this.$t('admin_dash.uploads.local_uploader') + }, { + key: 'Pleroma.Uploaders.IPFS', + value: 'Pleroma.Uploaders.IPFS', + label: 'IPFS' + }, { + key: 'Pleroma.Uploaders.S3', + value: 'Pleroma.Uploaders.S3', + label: 'S3' + }] } }, components: { BooleanSetting, ChoiceSetting, IntegerSetting, - StringSetting, + StringSetting }, computed: { - uploader() { - return this.$store.state.adminSettings.draft[':pleroma'][ - 'Pleroma.Upload' - ][':uploader'] + uploader () { + return this.$store.state.adminSettings.draft[':pleroma']['Pleroma.Upload'][':uploader'] }, - ...SharedComputedObject(), - }, + ...SharedComputedObject() + } } export default UploadsTab diff --git a/src/components/settings_modal/helpers/attachment_setting.js b/src/components/settings_modal/helpers/attachment_setting.js index 61e00a353..c4c04b2b6 100644 --- a/src/components/settings_modal/helpers/attachment_setting.js +++ b/src/components/settings_modal/helpers/attachment_setting.js @@ -1,7 +1,7 @@ -import Attachment from 'src/components/attachment/attachment.vue' -import MediaUpload from 'src/components/media_upload/media_upload.vue' -import { fileTypeExt } from 'src/services/file_type/file_type.service.js' import Setting from './setting.js' +import { fileTypeExt } from 'src/services/file_type/file_type.service.js' +import MediaUpload from 'src/components/media_upload/media_upload.vue' +import Attachment from 'src/components/attachment/attachment.vue' export default { ...Setting, @@ -11,36 +11,34 @@ export default { acceptTypes: { type: String, required: false, - default: 'image/*', - }, + default: 'image/*' + } }, components: { ...Setting.components, MediaUpload, - Attachment, + Attachment }, computed: { ...Setting.computed, - attachment() { + attachment () { const path = this.realDraftMode ? this.draft : this.state // The "server" part is primarily for local dev, but could be useful for alt-domain or multiuser usage. - const url = path.includes('://') - ? path - : this.$store.state.instance.server + path + const url = path.includes('://') ? path : this.$store.state.instance.server + path return { mimetype: fileTypeExt(url), - url, + url } - }, + } }, methods: { ...Setting.methods, - setMediaFile(fileInfo) { + setMediaFile (fileInfo) { if (this.realDraftMode) { this.draft = fileInfo.url } else { this.configSink(this.path, fileInfo.url) } - }, - }, + } + } } diff --git a/src/components/settings_modal/helpers/boolean_setting.js b/src/components/settings_modal/helpers/boolean_setting.js index e7b56f58c..199d3d0f0 100644 --- a/src/components/settings_modal/helpers/boolean_setting.js +++ b/src/components/settings_modal/helpers/boolean_setting.js @@ -5,27 +5,27 @@ export default { ...Setting, props: { ...Setting.props, - indeterminateState: [String, Object], + indeterminateState: [String, Object] }, components: { ...Setting.components, - Checkbox, + Checkbox }, computed: { ...Setting.computed, - isIndeterminate() { + isIndeterminate () { return this.visibleState === this.indeterminateState - }, + } }, methods: { ...Setting.methods, - getValue(e) { + getValue (e) { // Basic tri-state toggle implementation if (!!this.indeterminateState && !e && this.visibleState === true) { // If we have indeterminate state, switching from true to false first goes through indeterminate return this.indeterminateState } return e - }, - }, + } + } } diff --git a/src/components/settings_modal/helpers/choice_setting.js b/src/components/settings_modal/helpers/choice_setting.js index e5bc8420e..10e043082 100644 --- a/src/components/settings_modal/helpers/choice_setting.js +++ b/src/components/settings_modal/helpers/choice_setting.js @@ -5,50 +5,50 @@ export default { ...Setting, components: { ...Setting.components, - Select, + Select }, props: { ...Setting.props, overrideOptions: { type: Boolean, - required: false, + required: false }, options: { type: Array, - required: false, + required: false }, optionLabelMap: { type: Object, required: false, - default: {}, - }, + default: {} + } }, computed: { ...Setting.computed, - realOptions() { + realOptions () { if (this.overrideOptions) { return this.options } if (this.realSource === 'admin') { if ( !this.backendDescriptionSuggestions?.length || - this.backendDescriptionSuggestions?.length === 0 + this.backendDescriptionSuggestions?.length === 0 ) { return this.options } - return this.backendDescriptionSuggestions.map((x) => ({ + return this.backendDescriptionSuggestions.map(x => ({ key: x, value: x, - label: this.optionLabelMap[x] || x, + label: this.optionLabelMap[x] || x })) } return this.options - }, + } }, methods: { ...Setting.methods, - getValue(e) { + getValue (e) { return e - }, - }, + } + } } diff --git a/src/components/settings_modal/helpers/color_setting.js b/src/components/settings_modal/helpers/color_setting.js index d9b1e1397..c286b90fe 100644 --- a/src/components/settings_modal/helpers/color_setting.js +++ b/src/components/settings_modal/helpers/color_setting.js @@ -1,16 +1,17 @@ -import ColorInput from 'src/components/color_input/color_input.vue' import Setting from './setting.js' +import ColorInput from 'src/components/color_input/color_input.vue' export default { ...Setting, components: { ...Setting.components, - ColorInput, + ColorInput }, methods: { ...Setting.methods, - getValue(e) { + getValue (e) { + console.log(e) return e - }, - }, + } + } } diff --git a/src/components/settings_modal/helpers/draft_buttons.vue b/src/components/settings_modal/helpers/draft_buttons.vue index fd2f42cdd..b07ea1ec4 100644 --- a/src/components/settings_modal/helpers/draft_buttons.vue +++ b/src/components/settings_modal/helpers/draft_buttons.vue @@ -57,15 +57,17 @@ diff --git a/src/components/settings_modal/helpers/emoji_editing_popover.vue b/src/components/settings_modal/helpers/emoji_editing_popover.vue index 9fdcdd233..d25b02da2 100644 --- a/src/components/settings_modal/helpers/emoji_editing_popover.vue +++ b/src/components/settings_modal/helpers/emoji_editing_popover.vue @@ -149,10 +149,10 @@ diff --git a/src/components/settings_modal/helpers/float_setting.vue b/src/components/settings_modal/helpers/float_setting.vue index a1c495cd1..15edb3c3e 100644 --- a/src/components/settings_modal/helpers/float_setting.vue +++ b/src/components/settings_modal/helpers/float_setting.vue @@ -10,7 +10,7 @@ import NumberSetting from './number_setting.vue' export default { components: { - NumberSetting, - }, + NumberSetting + } } diff --git a/src/components/settings_modal/helpers/help_indicator.vue b/src/components/settings_modal/helpers/help_indicator.vue index ea21ea7a3..c48f97b70 100644 --- a/src/components/settings_modal/helpers/help_indicator.vue +++ b/src/components/settings_modal/helpers/help_indicator.vue @@ -18,14 +18,16 @@ diff --git a/src/components/settings_modal/helpers/integer_setting.vue b/src/components/settings_modal/helpers/integer_setting.vue index e9b227645..8206c0c45 100644 --- a/src/components/settings_modal/helpers/integer_setting.vue +++ b/src/components/settings_modal/helpers/integer_setting.vue @@ -11,7 +11,7 @@ import NumberSetting from './number_setting.vue' export default { components: { - NumberSetting, - }, + NumberSetting + } } diff --git a/src/components/settings_modal/helpers/list_setting.js b/src/components/settings_modal/helpers/list_setting.js index c1d504cd5..def6064d0 100644 --- a/src/components/settings_modal/helpers/list_setting.js +++ b/src/components/settings_modal/helpers/list_setting.js @@ -3,43 +3,43 @@ import Setting from './setting.js' export default { ...Setting, - data() { + data () { return { newValue: '', } }, components: { ...Setting.components, - Checkbox, + Checkbox }, props: { ...Setting.props, ignoreSuggestions: { required: false, - type: Boolean, + type: Boolean }, overrideAvailableOptions: { required: false, - type: Boolean, + type: Boolean }, options: { required: false, - type: Set, + type: Set }, allowNew: { required: false, type: Boolean, - default: true, + default: true }, forceNew: { required: false, type: Boolean, - default: false, - }, + default: false + } }, computed: { ...Setting.computed, - showNew() { + showNew () { if (this.forceNew) return true if (!this.allowNew) return false @@ -52,10 +52,10 @@ export default { return true } }, - valueSet() { + valueSet () { return new Set(this.visibleState) }, - suggestionsSet() { + suggestionsSet () { const suggestions = this.backendDescriptionSuggestions if (suggestions) { return new Set(suggestions) @@ -63,14 +63,14 @@ export default { return new Set() } }, - extraEntries() { + extraEntries () { if (this.ignoreSuggestions) return [...this.valueSet.values()] if (!this.suggestionsSet) return [] return [...this.valueSet.values()].filter((x) => { return !this.builtinEntriesValueSet.has(x) }) }, - builtinEntries() { + builtinEntries () { if (this.ignoreSuggestions) return [] if (this.overrideAvailableOptions) { return [...this.options] @@ -80,19 +80,19 @@ export default { const builtins = [...this.suggestionsSet.values()] return builtins.map((option) => ({ label: option, - value: option, + value: option })) }, - builtinEntriesValueSet() { - return new Set(this.builtinEntries.map((x) => x.value)) - }, + builtinEntriesValueSet () { + return new Set(this.builtinEntries.map(x => x.value)) + } }, methods: { ...Setting.methods, - optionPresent(option) { + optionPresent (option) { return this.valueSet.has(option) }, - getValue({ event, value, index, eventType }) { + getValue ({ event, value, index, eventType }) { switch (eventType) { case 'toggle': { this.newValue = '' @@ -128,6 +128,6 @@ export default { return [...pre, string, ...post] } } - }, - }, + } + } } diff --git a/src/components/settings_modal/helpers/list_tuple_setting.js b/src/components/settings_modal/helpers/list_tuple_setting.js index 33cc725b1..2cbd93788 100644 --- a/src/components/settings_modal/helpers/list_tuple_setting.js +++ b/src/components/settings_modal/helpers/list_tuple_setting.js @@ -2,14 +2,14 @@ import ListSetting from './list_setting.js' export default { ...ListSetting, - data() { + data () { return { - newValue: ['', ''], + newValue: ['',''] } }, methods: { ...ListSetting.methods, - getValue({ event, index, eventType, tuple }) { + getValue ({ event, index, eventType, tuple }) { switch (eventType) { case 'add': { if (!this.newValue[0] || !this.newValue[1]) return this.visibleState @@ -39,6 +39,6 @@ export default { } } } - }, - }, + } + } } diff --git a/src/components/settings_modal/helpers/map_setting.js b/src/components/settings_modal/helpers/map_setting.js index 8615c90ca..ad93ceacf 100644 --- a/src/components/settings_modal/helpers/map_setting.js +++ b/src/components/settings_modal/helpers/map_setting.js @@ -7,31 +7,28 @@ export default { allowNew: { required: false, type: Boolean, - default: true, - }, + default: true + } }, - data() { + data () { return { - newValue: ['', ''], // avoiding extra complexity by just using an array instead of an object + newValue: ['',''] // avoiding extra complexity by just using an array instead of an object } }, computed: { ...Setting.computed, // state that we'll show in the UI, i.e. transforming map into list - displayState() { + displayState () { return Object.entries(this.visibleState) - }, + } }, methods: { ...Setting.methods, - getValue({ event, key, eventType, isKey }) { + getValue ({ event, key, eventType, isKey }) { switch (eventType) { case 'add': { if (key === '') return this.visibleState - const res = { - ...this.visibleState, - ...Object.fromEntries([this.newValue]), - } + const res = {...this.visibleState, ...Object.fromEntries([this.newValue])} this.newValue = ['', ''] return res } @@ -39,35 +36,35 @@ export default { case 'remove': { // initial state for this type is empty array if (Array.isArray(this.visibleState)) return this.visibleState - const newEntries = Object.entries(this.visibleState).filter( - ([k]) => k !== key, - ) + const newEntries = Object.entries(this.visibleState).filter(([k]) => k !== key) - if (newEntries.length === 0) return [] + if (newEntries.length === 0 ) return [] return Object.fromEntries(newEntries) } case 'edit': { const string = event.target.value - const newEntries = Object.entries(this.visibleState).map(([k, v]) => { - if (isKey) { - if (k === key) { - return [string, v] + const newEntries = Object + .entries(this.visibleState) + .map(([k, v]) => { + if (isKey) { + if (k === key) { + return [string, v] + } else { + return [k, v] + } } else { - return [k, v] + if (k === key) { + return [k, string] + } else { + return [k, v] + } } - } else { - if (k === key) { - return [k, string] - } else { - return [k, v] - } - } - }) + }) return Object.fromEntries(newEntries) } } - }, - }, + } + } } diff --git a/src/components/settings_modal/helpers/modified_indicator.vue b/src/components/settings_modal/helpers/modified_indicator.vue index e92cd7e49..a747cebd2 100644 --- a/src/components/settings_modal/helpers/modified_indicator.vue +++ b/src/components/settings_modal/helpers/modified_indicator.vue @@ -23,11 +23,13 @@ diff --git a/src/components/settings_modal/helpers/number_setting.js b/src/components/settings_modal/helpers/number_setting.js index e037ece28..afbf5ed58 100644 --- a/src/components/settings_modal/helpers/number_setting.js +++ b/src/components/settings_modal/helpers/number_setting.js @@ -7,33 +7,33 @@ export default { min: { type: Number, required: false, - default: 1, + default: 1 }, max: { type: Number, required: false, - default: 1, + default: 1 }, step: { type: Number, required: false, - default: 1, + default: 1 }, truncate: { type: Number, required: false, - default: 1, - }, + default: 1 + } }, methods: { ...Setting.methods, - getValue(e) { + getValue (e) { if (!this.truncate === 1) { return parseInt(e.target.value) } else if (this.truncate > 1) { return Math.trunc(e.target.value / this.truncate) * this.truncate } return parseFloat(e.target.value) - }, - }, + } + } } diff --git a/src/components/settings_modal/helpers/profile_setting_indicator.vue b/src/components/settings_modal/helpers/profile_setting_indicator.vue index 6ed401f1d..d160781b1 100644 --- a/src/components/settings_modal/helpers/profile_setting_indicator.vue +++ b/src/components/settings_modal/helpers/profile_setting_indicator.vue @@ -23,15 +23,17 @@ diff --git a/src/components/settings_modal/helpers/proxy_setting.js b/src/components/settings_modal/helpers/proxy_setting.js index 4195b8430..ca717b60b 100644 --- a/src/components/settings_modal/helpers/proxy_setting.js +++ b/src/components/settings_modal/helpers/proxy_setting.js @@ -1,19 +1,18 @@ import Checkbox from 'src/components/checkbox/checkbox.vue' import Setting from './setting.js' -const getUrl = (state) => - state?.tuple ? state.tuple[1] + ':' + state.tuple[2] : state -const getSocks = (state) => state?.tuple +const getUrl = state => state?.tuple ? state.tuple[1] + ':' + state.tuple[2] : state +const getSocks = state => state?.tuple export default { ...Setting, - data() { + data () { return { urlField: '', - socksField: false, + socksField: false } }, - created() { + created () { Setting.created() this.urlField = getUrl(this.realDraftMode ? this.draft : this.state) this.socksField = getSocks(this.realDraftMode ? this.draft : this.state) @@ -21,23 +20,23 @@ export default { computed: { ...Setting.computed, // state that we'll show in the UI, i.e. transforming map into list - displayState() { + displayState () { if (this.visibleState?.tuple) { return this.visibleState.tuple[1] + ':' + this.visibleState.tuple[2] } return this.visibleState }, - socksState() { + socksState () { return getSocks(this.visibleState) - }, + } }, components: { ...Setting.components, - Checkbox, + Checkbox }, methods: { ...Setting.methods, - getValue({ event, isProxy }) { + getValue ({ event, isProxy}) { if (isProxy) { this.socksField = event } else { @@ -45,10 +44,10 @@ export default { } if (this.socksField) { - return { tuple: [':socks5', ...this.urlField.split(':')] } + return { tuple: [ ':socks5', ...this.urlField.split(':') ] } } else { return this.urlField } - }, - }, + } + } } diff --git a/src/components/settings_modal/helpers/pwa_manifest_icons_setting.js b/src/components/settings_modal/helpers/pwa_manifest_icons_setting.js index f76672155..9986f6f39 100644 --- a/src/components/settings_modal/helpers/pwa_manifest_icons_setting.js +++ b/src/components/settings_modal/helpers/pwa_manifest_icons_setting.js @@ -1,9 +1,10 @@ import { clone } from 'lodash' +import { fileTypeExt } from 'src/services/file_type/file_type.service.js' + +import Setting from './setting.js' +import Select from 'src/components/select/select.vue' import Attachment from 'src/components/attachment/attachment.vue' import MediaUpload from 'src/components/media_upload/media_upload.vue' -import Select from 'src/components/select/select.vue' -import { fileTypeExt } from 'src/services/file_type/file_type.service.js' -import Setting from './setting.js' export default { ...Setting, @@ -11,62 +12,60 @@ export default { ...Setting.components, Select, Attachment, - MediaUpload, + MediaUpload }, computed: { ...Setting.computed, - purposeOptions() { - return ['any', 'monochrome', 'maskable'].map((value) => ({ + purposeOptions () { + return ['any','monochrome','maskable'].map(value => ({ value, key: value, - label: this.$t('admin_dash.instance.pwa.icon.' + value), + label: this.$t('admin_dash.instance.pwa.icon.' + value) })) - }, + } }, methods: { ...Setting.methods, - attachment(e) { + attachment (e) { const path = e[':src'] if (!path) { return { mimetype: '', - url: '', + url: '' } } - const url = path.includes('://') - ? path - : this.$store.state.instance.server + path + const url = path.includes('://') ? path : this.$store.state.instance.server + path return { mimetype: fileTypeExt(url), - url, + url } }, - setMediaFile({ event, index }) { + setMediaFile ({ event, index }) { this.update({ event: { target: { - value: event.url, + value: event.url }, }, index, eventType: 'edit', - field: ':src', + field: ':src' }) }, - setPurpose({ event, index }) { + setPurpose ({ event, index }) { this.update({ event: { target: { - value: event, + value: event }, }, index, eventType: 'edit', - field: ':purpose', + field: ':purpose' }) }, - getValue({ event, field, index, eventType }) { + getValue ({ event, field, index, eventType }) { switch (eventType) { case 'add': { const res = [...this.visibleState, {}] @@ -86,7 +85,7 @@ export default { const item = clone(this.visibleState[index]) const string = event.target.value - if (!string) { + if (!string) { delete item[field] } else { item[field] = string @@ -95,6 +94,6 @@ export default { return [...pre, item, ...post] } } - }, - }, + } + } } diff --git a/src/components/settings_modal/helpers/pwa_manifest_icons_setting.vue b/src/components/settings_modal/helpers/pwa_manifest_icons_setting.vue index f8054d266..20e50fe25 100644 --- a/src/components/settings_modal/helpers/pwa_manifest_icons_setting.vue +++ b/src/components/settings_modal/helpers/pwa_manifest_icons_setting.vue @@ -85,8 +85,8 @@ @update:model-value="event => setPurpose({ event, index })" >