diff --git a/src/intl/de.js b/src/intl/de.js
index 69b855bd..5a707f6f 100644
--- a/src/intl/de.js
+++ b/src/intl/de.js
@@ -155,6 +155,7 @@ export default {
p das Profil des Verfassers öffnen
l den Link des aktuellen Tröts in einem neuen Tab öffnen
x den Text hinter der Inhaltswarnung anzeigen oder verbergen
+ z den Text hinter der Inhaltswarnung anzeigen oder verbergen (alle)
`,
mediaHotkeys: `
← / → zum nächsten oder vorherigen Inhalt gehen
diff --git a/src/intl/en-US.js b/src/intl/en-US.js
index 8489ea0a..43697d8c 100644
--- a/src/intl/en-US.js
+++ b/src/intl/en-US.js
@@ -156,6 +156,7 @@ export default {
p to open the author's profile
l to open the card's link in a new tab
x to show or hide text behind content warning
+ z to show or hide all content warnings in a thread
`,
mediaHotkeys: `
← / → to go to next or previous
diff --git a/src/intl/fr.js b/src/intl/fr.js
index 0acde0ac..ed8a833d 100644
--- a/src/intl/fr.js
+++ b/src/intl/fr.js
@@ -156,6 +156,7 @@ export default {
p pour voir le profile de l'auteur
l pour ouvrir un lien de carte dans un nouvel onglet
x pour afficher ou cacher le texte caché derrière une avertissement
+ z pour afficher ou cacher toutes les avertissements
`,
mediaHotkeys: `
← / → pour voir la prochaine ou dernière image
diff --git a/src/routes/_components/shortcut/ScrollListShortcuts.html b/src/routes/_components/shortcut/ScrollListShortcuts.html
index b51f105c..393e3e9c 100644
--- a/src/routes/_components/shortcut/ScrollListShortcuts.html
+++ b/src/routes/_components/shortcut/ScrollListShortcuts.html
@@ -11,6 +11,8 @@
} from '../../_utils/shortcuts'
import { smoothScroll } from '../../_utils/smoothScroll'
import { getScrollContainer } from '../../_utils/scrollContainer'
+ import { store } from '../../_store/store'
+ import { emit } from '../../_utils/eventBus'
const VISIBILITY_CHECK_DELAY_MS = 600
@@ -32,8 +34,10 @@
export default {
data: () => ({
activeItemChangeTime: 0,
- elements: document.getElementsByClassName('shortcut-list-item')
+ elements: document.getElementsByClassName('shortcut-list-item'),
+ spoilersShown: false
}),
+ store: () => store,
oncreate () {
addShortcutFallback(scope, this)
},
@@ -45,6 +49,15 @@
if (shouldIgnoreEvent(event)) {
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') {
event.stopPropagation()
event.preventDefault()
diff --git a/src/routes/_components/status/StatusSpoiler.html b/src/routes/_components/status/StatusSpoiler.html
index 2aba5e5b..203dcf39 100644
--- a/src/routes/_components/status/StatusSpoiler.html
+++ b/src/routes/_components/status/StatusSpoiler.html
@@ -52,12 +52,15 @@
import { registerClickDelegate } from '../../_utils/delegate'
import { mark, stop } from '../../_utils/marks'
import { emojifyText } from '../../_utils/emojifyText'
+ import { on } from '../../_utils/eventBus'
import escapeHtml from 'escape-html'
export default {
oncreate () {
+ this.toggleSpoilers = this.toggleSpoilers.bind(this)
const { elementId } = this.get()
registerClickDelegate(this, elementId, () => this.toggleSpoilers())
+ on('toggleAllSpoilers', this, this.toggleSpoilers)
},
store: () => store,
components: {
@@ -71,13 +74,13 @@
elementId: ({ uuid }) => `spoiler-${uuid}`
},
methods: {
- toggleSpoilers () {
+ toggleSpoilers (shown) {
+ const { uuid } = this.get()
+ const { spoilersShown } = this.store.get()
+ spoilersShown[uuid] = typeof shown === 'undefined' ? !spoilersShown[uuid] : !!shown
+ this.store.set({ spoilersShown })
requestAnimationFrame(() => {
mark('clickSpoilerButton')
- const { uuid } = this.get()
- const { spoilersShown } = this.store.get()
- spoilersShown[uuid] = !spoilersShown[uuid]
- this.store.set({ spoilersShown })
this.fire('recalculateHeight')
stop('clickSpoilerButton')
})
diff --git a/tests/serverActions.js b/tests/serverActions.js
index ea833ed1..aabbb6c7 100644
--- a/tests/serverActions.js
+++ b/tests/serverActions.js
@@ -54,6 +54,11 @@ export async function postReplyAs (username, text, inReplyTo) {
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) {
return deleteStatus(instanceName, users[username].accessToken, statusId)
}
diff --git a/tests/spec/137-shortcuts-spoiler.js b/tests/spec/137-shortcuts-spoiler.js
new file mode 100644
index 00000000..ba6403f4
--- /dev/null
+++ b/tests/spec/137-shortcuts-spoiler.js
@@ -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()
+})