Skip to content

Commit

Permalink
Merge pull request #1460 from maykinmedia/issue/2623-A11y-pause-speec…
Browse files Browse the repository at this point in the history
…hsynthesis

♿ [#2623] A11y Fix and add SpeechSynthesis pause/stop functionality
  • Loading branch information
alextreme authored and pi-sigma committed Nov 6, 2024
2 parents a7ce5c9 + 904fd1d commit fd99416
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

<li class="accessibility-header__list-item">
{% trans "Lees voor" as link_text %}
{% link href="#" icon="volume_up" text=link_text extra_classes="accessibility--read" %}
{% trans "Pauzeer" as alt_link_text %}
{% link href="#" icon="volume_up" text=link_text extra_classes="accessibility--read" data_text=link_text data_alt_text=alt_link_text data_icon="volume_up" data_alt_icon="pause" %}
</li>

<li class="accessibility-header__list-item">
Expand Down
73 changes: 64 additions & 9 deletions src/open_inwoner/js/components/accessibility/read.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
const readOutButtons = document.querySelectorAll('.accessibility--read')
export class ReadOut {
static selector = '.accessibility--read'

class ReadOut {
constructor(node) {
this.node = node

this.speechSynthesis = window.speechSynthesis
this.SpeechSynthesisUtterance = window.SpeechSynthesisUtterance
this.isPaused = false // Track if speech is paused
this.isReading = false // Track if speech is currently reading

if ('speechSynthesis' in window) {
this.node.addEventListener('click', this.read)
this.node.addEventListener('click', this.handleReadPauseToggle)
} else {
this.node.parentElement.remove()
}
Expand All @@ -22,31 +25,78 @@ class ReadOut {
if (speechSynthesis.onvoiceschanged !== undefined) {
speechSynthesis.onvoiceschanged = populateVoiceList
}

window.addEventListener('beforeunload', this.stopSpeech)
}

stopSpeech = () => {
if (this.speechSynthesis.speaking || this.isPaused) {
this.speechSynthesis.cancel()
this.isPaused = false
this.isReading = false
this.updateButtonTextAndIcon(false)
}
}

read = (event) => {
handleReadPauseToggle = (event) => {
event.preventDefault()

if (this.speechSynthesis.speaking) {
if (this.speechSynthesis.speaking && !this.isPaused) {
// Pausing only when playing
this.speechSynthesis.pause()
} else if (this.speechSynthesis.paused) {
this.isPaused = true
this.updateButtonTextAndIcon(false)
} else if (this.isPaused) {
// Resume when paused
this.speechSynthesis.resume()
this.isPaused = false
this.updateButtonTextAndIcon(true)
} else {
// When speech is not playing, start it
let main = document.querySelector('.grid__main')
if (!main) {
main = document.querySelector('main')
}

// console.log(main.innerText)
// console.log(main.textContent)
let text = this.getText(main)
// console.log(text)
const utterThis = new this.SpeechSynthesisUtterance(text)

utterThis.onend = () => {
this.isReading = false
this.updateButtonTextAndIcon(false)
}

const utterThis = new SpeechSynthesisUtterance(text)
this.speechSynthesis.speak(utterThis)
this.isReading = true
this.isPaused = false
this.updateButtonTextAndIcon(true) // Switch when speech starts
}
}

updateButtonTextAndIcon(isReading) {
const linkText = this.node.querySelector('.link__text')
const icon = this.node.querySelector('.material-icons')

linkText.textContent = isReading
? this.node.dataset.altText
: this.node.dataset.text

icon.textContent = isReading
? this.node.dataset.altIcon
: this.node.dataset.icon

this.node.setAttribute(
'aria-label',
isReading ? this.node.dataset.altText : this.node.dataset.text
)
this.node.setAttribute(
'title',
isReading ? this.node.dataset.altText : this.node.dataset.text
)
}

getText = (node) => {
let baseText = ''
if (node.getAttribute('aria-hidden')) {
Expand Down Expand Up @@ -84,4 +134,9 @@ class ReadOut {
}
}

;[...readOutButtons].forEach((readOutButton) => new ReadOut(readOutButton))
/**
* Controls reading of content
*/
document
.querySelectorAll(ReadOut.selector)
.forEach((readOutButton) => new ReadOut(readOutButton))
24 changes: 15 additions & 9 deletions src/open_inwoner/search/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from open_inwoner.configurations.models import SiteConfiguration
from open_inwoner.openzaak.clients import MultiZgwClientProxy, build_zaken_clients
from open_inwoner.openzaak.models import ZGWApiGroupConfig
from open_inwoner.openzaak.utils import get_user_fetch_parameters
from open_inwoner.openzaak.utils import get_user_fetch_parameters, is_zaak_visible
from open_inwoner.utils.mixins import PaginationMixin
from open_inwoner.utils.views import CommonPageMixin, LoginMaybeRequiredMixin, LogMixin

Expand Down Expand Up @@ -89,15 +89,21 @@ def search(self, form):
api_group = ZGWApiGroupConfig.objects.resolve_group_from_hints(
client=case_result.client
)
return HttpResponseRedirect(
reverse(
"cases:case_detail",
kwargs={
"object_id": str(case_result.result[0].uuid),
"api_group_id": api_group.id,
},
)
zaak = case_result.result[0]
zaaktype = api_group.catalogi_client.fetch_single_case_type(
zaak.zaaktype
)
zaak.zaaktype = zaaktype
if is_zaak_visible(zaak):
return HttpResponseRedirect(
reverse(
"cases:case_detail",
kwargs={
"object_id": str(zaak.uuid),
"api_group_id": api_group.id,
},
)
)

# perform search
results = search_products(query, filters=data)
Expand Down

0 comments on commit fd99416

Please sign in to comment.