feat: implement shortcut for opening/closing all CWs (#1973)
Fixes #1914
This commit is contained in:
parent
a21a889f5f
commit
8c09ede2d4
|
@ -155,6 +155,7 @@ export default {
|
||||||
<li><kbd>p</kbd> das Profil des Verfassers öffnen</li>
|
<li><kbd>p</kbd> das Profil des Verfassers öffnen</li>
|
||||||
<li><kbd>l</kbd> den Link des aktuellen Tröts in einem neuen Tab öffnen</li>
|
<li><kbd>l</kbd> den Link des aktuellen Tröts in einem neuen Tab öffnen</li>
|
||||||
<li><kbd>x</kbd> den Text hinter der Inhaltswarnung anzeigen oder verbergen</li>
|
<li><kbd>x</kbd> den Text hinter der Inhaltswarnung anzeigen oder verbergen</li>
|
||||||
|
<li><kbd>z</kbd> den Text hinter der Inhaltswarnung anzeigen oder verbergen (alle)</li>
|
||||||
`,
|
`,
|
||||||
mediaHotkeys: `
|
mediaHotkeys: `
|
||||||
<li><kbd>←</kbd> / <kbd>→</kbd> zum nächsten oder vorherigen Inhalt gehen</li>
|
<li><kbd>←</kbd> / <kbd>→</kbd> zum nächsten oder vorherigen Inhalt gehen</li>
|
||||||
|
|
|
@ -156,6 +156,7 @@ export default {
|
||||||
<li><kbd>p</kbd> to open the author's profile</li>
|
<li><kbd>p</kbd> to open the author's profile</li>
|
||||||
<li><kbd>l</kbd> to open the card's link in a new tab</li>
|
<li><kbd>l</kbd> to open the card's link in a new tab</li>
|
||||||
<li><kbd>x</kbd> to show or hide text behind content warning</li>
|
<li><kbd>x</kbd> to show or hide text behind content warning</li>
|
||||||
|
<li><kbd>z</kbd> to show or hide all content warnings in a thread</li>
|
||||||
`,
|
`,
|
||||||
mediaHotkeys: `
|
mediaHotkeys: `
|
||||||
<li><kbd>←</kbd> / <kbd>→</kbd> to go to next or previous</li>
|
<li><kbd>←</kbd> / <kbd>→</kbd> to go to next or previous</li>
|
||||||
|
|
|
@ -156,6 +156,7 @@ export default {
|
||||||
<li><kbd>p</kbd> pour voir le profile de l'auteur</li>
|
<li><kbd>p</kbd> pour voir le profile de l'auteur</li>
|
||||||
<li><kbd>l</kbd> pour ouvrir un lien de carte dans un nouvel onglet</li>
|
<li><kbd>l</kbd> pour ouvrir un lien de carte dans un nouvel onglet</li>
|
||||||
<li><kbd>x</kbd> pour afficher ou cacher le texte caché derrière une avertissement</li>
|
<li><kbd>x</kbd> pour afficher ou cacher le texte caché derrière une avertissement</li>
|
||||||
|
<li><kbd>z</kbd> pour afficher ou cacher toutes les avertissements</li>
|
||||||
`,
|
`,
|
||||||
mediaHotkeys: `
|
mediaHotkeys: `
|
||||||
<li><kbd>←</kbd> / <kbd>→</kbd> pour voir la prochaine ou dernière image</li>
|
<li><kbd>←</kbd> / <kbd>→</kbd> pour voir la prochaine ou dernière image</li>
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
} from '../../_utils/shortcuts'
|
} from '../../_utils/shortcuts'
|
||||||
import { smoothScroll } from '../../_utils/smoothScroll'
|
import { smoothScroll } from '../../_utils/smoothScroll'
|
||||||
import { getScrollContainer } from '../../_utils/scrollContainer'
|
import { getScrollContainer } from '../../_utils/scrollContainer'
|
||||||
|
import { store } from '../../_store/store'
|
||||||
|
import { emit } from '../../_utils/eventBus'
|
||||||
|
|
||||||
const VISIBILITY_CHECK_DELAY_MS = 600
|
const VISIBILITY_CHECK_DELAY_MS = 600
|
||||||
|
|
||||||
|
@ -32,8 +34,10 @@
|
||||||
export default {
|
export default {
|
||||||
data: () => ({
|
data: () => ({
|
||||||
activeItemChangeTime: 0,
|
activeItemChangeTime: 0,
|
||||||
elements: document.getElementsByClassName('shortcut-list-item')
|
elements: document.getElementsByClassName('shortcut-list-item'),
|
||||||
|
spoilersShown: false
|
||||||
}),
|
}),
|
||||||
|
store: () => store,
|
||||||
oncreate () {
|
oncreate () {
|
||||||
addShortcutFallback(scope, this)
|
addShortcutFallback(scope, this)
|
||||||
},
|
},
|
||||||
|
@ -45,6 +49,15 @@
|
||||||
if (shouldIgnoreEvent(event)) {
|
if (shouldIgnoreEvent(event)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (event.key === 'z' && this.store.get().currentTimeline.startsWith('status/')) {
|
||||||
|
// if we're in a thread, toggle all content warnings on or off
|
||||||
|
event.stopPropagation()
|
||||||
|
event.preventDefault()
|
||||||
|
const { spoilersShown } = this.get()
|
||||||
|
emit('toggleAllSpoilers', !spoilersShown)
|
||||||
|
this.set({ spoilersShown: !spoilersShown })
|
||||||
|
return
|
||||||
|
}
|
||||||
if (event.key === 'j' || event.key === 'ArrowDown') {
|
if (event.key === 'j' || event.key === 'ArrowDown') {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
|
@ -52,12 +52,15 @@
|
||||||
import { registerClickDelegate } from '../../_utils/delegate'
|
import { registerClickDelegate } from '../../_utils/delegate'
|
||||||
import { mark, stop } from '../../_utils/marks'
|
import { mark, stop } from '../../_utils/marks'
|
||||||
import { emojifyText } from '../../_utils/emojifyText'
|
import { emojifyText } from '../../_utils/emojifyText'
|
||||||
|
import { on } from '../../_utils/eventBus'
|
||||||
import escapeHtml from 'escape-html'
|
import escapeHtml from 'escape-html'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
oncreate () {
|
oncreate () {
|
||||||
|
this.toggleSpoilers = this.toggleSpoilers.bind(this)
|
||||||
const { elementId } = this.get()
|
const { elementId } = this.get()
|
||||||
registerClickDelegate(this, elementId, () => this.toggleSpoilers())
|
registerClickDelegate(this, elementId, () => this.toggleSpoilers())
|
||||||
|
on('toggleAllSpoilers', this, this.toggleSpoilers)
|
||||||
},
|
},
|
||||||
store: () => store,
|
store: () => store,
|
||||||
components: {
|
components: {
|
||||||
|
@ -71,13 +74,13 @@
|
||||||
elementId: ({ uuid }) => `spoiler-${uuid}`
|
elementId: ({ uuid }) => `spoiler-${uuid}`
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleSpoilers () {
|
toggleSpoilers (shown) {
|
||||||
requestAnimationFrame(() => {
|
|
||||||
mark('clickSpoilerButton')
|
|
||||||
const { uuid } = this.get()
|
const { uuid } = this.get()
|
||||||
const { spoilersShown } = this.store.get()
|
const { spoilersShown } = this.store.get()
|
||||||
spoilersShown[uuid] = !spoilersShown[uuid]
|
spoilersShown[uuid] = typeof shown === 'undefined' ? !spoilersShown[uuid] : !!shown
|
||||||
this.store.set({ spoilersShown })
|
this.store.set({ spoilersShown })
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
mark('clickSpoilerButton')
|
||||||
this.fire('recalculateHeight')
|
this.fire('recalculateHeight')
|
||||||
stop('clickSpoilerButton')
|
stop('clickSpoilerButton')
|
||||||
})
|
})
|
||||||
|
|
|
@ -54,6 +54,11 @@ export async function postReplyAs (username, text, inReplyTo) {
|
||||||
inReplyTo, null, false, null, 'public')
|
inReplyTo, null, false, null, 'public')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function postReplyWithSpoilerAs (username, text, inReplyTo, spoilerText) {
|
||||||
|
return postStatus(instanceName, users[username].accessToken, text,
|
||||||
|
inReplyTo, null, false, spoilerText, 'public')
|
||||||
|
}
|
||||||
|
|
||||||
export async function deleteAs (username, statusId) {
|
export async function deleteAs (username, statusId) {
|
||||||
return deleteStatus(instanceName, users[username].accessToken, statusId)
|
return deleteStatus(instanceName, users[username].accessToken, statusId)
|
||||||
}
|
}
|
||||||
|
|
41
tests/spec/137-shortcuts-spoiler.js
Normal file
41
tests/spec/137-shortcuts-spoiler.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import {
|
||||||
|
getNthStatus, getNthStatusContent, getNthStatusSpoiler, getUrl, sleep
|
||||||
|
} from '../utils'
|
||||||
|
import { loginAsFoobar } from '../roles'
|
||||||
|
import { postReplyWithSpoilerAs, postWithSpoilerAndPrivacyAs } from '../serverActions'
|
||||||
|
|
||||||
|
fixture`137-shortcut-spoiler.js`
|
||||||
|
.page`http://localhost:4002`
|
||||||
|
|
||||||
|
test('Can toggle all spoilers with shortcut', async t => {
|
||||||
|
const { id: statusId1 } = await postWithSpoilerAndPrivacyAs('admin', 'the content', 'yolo', 'public')
|
||||||
|
const { id: statusId2 } = await postReplyWithSpoilerAs('admin', 'the content', statusId1, 'haha')
|
||||||
|
await postReplyWithSpoilerAs('admin', 'the content', statusId2, 'wheeee')
|
||||||
|
await sleep(500)
|
||||||
|
await loginAsFoobar(t)
|
||||||
|
await t
|
||||||
|
.expect(getNthStatusSpoiler(1).innerText).eql('wheeee')
|
||||||
|
.click(getNthStatus(1))
|
||||||
|
.expect(getUrl()).contains('/statuses')
|
||||||
|
.expect(getNthStatusSpoiler(1).innerText).eql('yolo')
|
||||||
|
.expect(getNthStatusSpoiler(2).innerText).eql('haha')
|
||||||
|
.expect(getNthStatusSpoiler(3).innerText).eql('wheeee')
|
||||||
|
.expect(getNthStatusContent(1).visible).notOk()
|
||||||
|
.expect(getNthStatusContent(2).visible).notOk()
|
||||||
|
.expect(getNthStatusContent(3).visible).notOk()
|
||||||
|
await sleep(500)
|
||||||
|
await t
|
||||||
|
.pressKey('z')
|
||||||
|
.expect(getNthStatusContent(1).innerText).contains('the content')
|
||||||
|
.expect(getNthStatusContent(2).innerText).contains('the content')
|
||||||
|
.expect(getNthStatusContent(3).innerText).contains('the content')
|
||||||
|
.expect(getNthStatusContent(1).visible).ok()
|
||||||
|
.expect(getNthStatusContent(2).visible).ok()
|
||||||
|
.expect(getNthStatusContent(3).visible).ok()
|
||||||
|
await sleep(500)
|
||||||
|
await t
|
||||||
|
.pressKey('z')
|
||||||
|
.expect(getNthStatusContent(1).visible).notOk()
|
||||||
|
.expect(getNthStatusContent(2).visible).notOk()
|
||||||
|
.expect(getNthStatusContent(3).visible).notOk()
|
||||||
|
})
|
Loading…
Reference in a new issue