web-barrier-free
Version:
[](./LICENSE) [](https://github.com/karma-runner/karma-cover
240 lines (219 loc) • 7.79 kB
text/typescript
import defaultOptions from './default'
import {
consoleClassName,
consoleDomId,
emphasizeClassName,
getGather,
IGather,
optionsArr,
showBarDomId,
testReadMode
} from './util'
import { outHandler, overHandler } from './handlers'
import './index.css'
class Wbf {
public opening: boolean = false
public readMode: readMode = 'finger'
public language: language
public rate: number
public pitch: number
public volume: number
public showBarEl: HTMLDivElement | null = null
public needConsole: boolean = true
public externalFn: Function | null = null
private readonly overHandler
private readonly outHandler
constructor (options?: Options) {
// options init
if (options == null) options = defaultOptions
options?.readMode !== undefined && (this.readMode = options.readMode)
options?.needConsole !== undefined &&
(this.needConsole = options.needConsole)
this.language = options?.language ?? defaultOptions.language
this.rate = options?.rate ?? defaultOptions.rate
this.pitch = options?.pitch ?? defaultOptions.pitch
this.volume = options?.volume ?? defaultOptions.volume
this.externalFn = options?.externalFn ?? null
this.overHandler = (e: { target: HTMLElement }) => overHandler(e, this)
this.outHandler = (e: { target: HTMLElement }) => outHandler(e, this)
}
open (): void {
/**
* Change mode to start wbf
* And according to the options to determine whether to open the console dom
*/
if (this.opening) return
this.changeMode(this.readMode)
if (this.showBarEl == null) {
const showBar = this.createShowBarDom()
this.showBarEl = showBar
}
this.addHandler()
this.opening = true
this.needConsole && this.createConsole()
}
close (): void {
/**
* Remove was added emphasize elements
* Cancel current speechSynthesis
* Remove the corresponding listener event
* Remove console and showBar
*
*/
const emphasizeEls = document.querySelectorAll(`.${emphasizeClassName}`)
emphasizeEls.forEach((el) => {
this.removeEmphasize(el)
})
speechSynthesis.cancel()
document.removeEventListener('mouseover', this.overHandler)
document.removeEventListener('mouseout', this.outHandler)
this.removeShowBarDom()
this.removeConsole()
this.opening = false
}
// You can modify the properties of wbf through this method, but you cannot modify the opening state
changeOptions (keyName: string, value): void {
if (optionsArr.includes[keyName] === false && this[keyName] !== undefined) {
throw new Error(`${keyName} options do not exist on wbf`)
}
if (keyName === 'opening') throw new Error(`${keyName} cannot be changed `)
if (typeof value === 'number') {
value >= 2 && (value = 2)
}
this[keyName] = value
}
// You can modify the wbf by this method reading mode
changeMode (readMode: readMode): void {
if (!testReadMode(readMode)) {
throw new Error(`readMode not includes this ${readMode}`)
}
this.readMode = readMode
if (readMode !== 'finger') {
const allText = document.body.innerText
this.playAudio(allText)
}
}
addHandler (): void {
document.addEventListener('mouseover', this.overHandler)
document.addEventListener('mouseout', this.outHandler)
}
createUtterance (str): SpeechSynthesisUtterance {
const msg = new SpeechSynthesisUtterance()
msg.text = str
msg.lang = this.language
msg.pitch = this.pitch
msg.rate = this.rate
msg.volume = this.volume
return msg
}
playAudio (str: string): SpeechSynthesisUtterance | undefined {
if (this.externalFn != null) {
this.externalFn(str)
} else {
speechSynthesis.cancel()
const msg = this.createUtterance(str)
speechSynthesis.speak(msg)
return msg
}
}
emphasize (el: HTMLElement | Element): void {
el.classList.add(emphasizeClassName)
}
removeEmphasize (el: HTMLElement | Element): void {
el.classList.remove(emphasizeClassName)
}
createShowBarDom (): HTMLDivElement {
const prev = document.getElementById(showBarDomId) as HTMLDivElement | null
if (prev != null) return prev
const showBar = document.createElement('div')
showBar.id = showBarDomId
showBar.style.position = 'fixed'
showBar.style.bottom = '0px'
showBar.style.left = '0px'
showBar.style.width = '100%'
showBar.style.minHeight = '50px'
showBar.style.maxHeight = '300px'
showBar.style.fontWeight = 'bold'
showBar.style.textAlign = 'center'
showBar.style.wordBreak = 'break-word;'
showBar.style.overflow = 'hidden'
showBar.style.background = 'white'
showBar.style.border = '2px solid #eee'
document.body.appendChild(showBar)
return showBar
}
createConsole (): void {
const prev = document.getElementById(consoleDomId)
if (prev != null) return
const consoleEl = document.createElement('div')
consoleEl.id = consoleDomId
const gather: IGather = getGather(this.language)
consoleEl.classList.add(consoleClassName)
consoleEl.innerHTML = `
<div class="${consoleClassName}-main">
<div>
<button id="_wbfClose">${gather.close}</button>
<button id="_wbfContinuousRead">${gather.continuousRead}</button>
<button id="_wbfFingerRead">${gather.fingerRead}</button>
</div>
|
<div>
${gather.volume}
<button id="_wbfAddVolume">+</button>
<button id="_wbfReduceVolume">-</button>
</div>
|
<div>
${gather.rate}
<button id="_wbfAddRate">+</button>
<button id="_wbfReduceRate">-</button>
</div>
</div>`
document.body.insertBefore(consoleEl, document.body.firstChild)
const closeBtn = document.getElementById('_wbfClose')
const continuousReadBtn = document.getElementById('_wbfContinuousRead')
const fingerReadBtn = document.getElementById('_wbfFingerRead')
const addVolumeBtn = document.getElementById('_wbfAddVolume')
const reduceVolumeBtn = document.getElementById('_wbfReduceVolume')
const addRateBtn = document.getElementById('_wbfAddRate')
const reduceRateBtn = document.getElementById('_wbfReduceRate')
closeBtn != null && (closeBtn.onclick = () => this.close())
continuousReadBtn != null &&
(continuousReadBtn.onclick = () => this.changeMode('continuous'))
fingerReadBtn != null &&
(fingerReadBtn.onclick = () => this.changeMode('finger'))
addVolumeBtn != null &&
(addVolumeBtn.onclick = () => this.changeOptions('volume', ++this.volume))
reduceVolumeBtn != null &&
(reduceVolumeBtn.onclick = () =>
this.changeOptions('volume', --this.volume))
addRateBtn != null &&
(addRateBtn.onclick = () => this.changeOptions('rate', ++this.rate))
reduceRateBtn != null &&
(reduceRateBtn.onclick = () => this.changeOptions('rate', --this.rate))
}
removeConsole (): void {
const consoleEl = document.getElementById(consoleDomId)
if (consoleEl != null) {
consoleEl.remove()
}
}
removeShowBarDom (): void {
if (this.showBarEl != null) {
this.showBarEl.remove()
this.showBarEl = null
}
}
}
type readMode = 'finger' | 'continuous'
export type language = 'en' | 'zh-CN'
interface Options {
readMode?: readMode
language?: language
rate?: number
pitch?: number
externalFn?: Function
volume?: number
needConsole?: boolean
}
export default Wbf