From 8c09ede2d4528db6966c3bf4fba6644da83d10d5 Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Sat, 27 Feb 2021 18:31:53 -0800 Subject: [PATCH] feat: implement shortcut for opening/closing all CWs (#1973) Fixes #1914 --- src/intl/de.js | 1 + src/intl/en-US.js | 1 + src/intl/fr.js | 1 + .../shortcut/ScrollListShortcuts.html | 15 ++++++- .../_components/status/StatusSpoiler.html | 13 +++--- tests/serverActions.js | 5 +++ tests/spec/137-shortcuts-spoiler.js | 41 +++++++++++++++++++ 7 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 tests/spec/137-shortcuts-spoiler.js 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() +})