Преглед изворни кода

无障碍:功能开发:播放预先录制好的音频。以及示例。(音频暂时以一段音乐代替。)

任一存 пре 2 година
родитељ
комит
5a5b8e3342

+ 5 - 3
web/README.md

@@ -67,10 +67,12 @@ See [Configuration Reference](https://cli.vuejs.org/config/).
 * tabindex: 手动添加,表示这个元素需要能够被聚焦,且在被聚焦、鼠标hover时应该提取出其上储存的无障碍信息来朗读、显示。对于a、button、input等天生可以聚焦的标签,如果不写这个,则能聚焦但不会提取出无障碍信息。
 * aria-label: 手动添加,可选,表示元素在无障碍信息中显示的类型,不写的话会根据元素标签得到其在无障碍信息中显示的类型。
 * aria-description: 手动添加,可选,表示元素在无障碍信息中显示的详细描述,不写的话会拿元素的innerText作为描述。
+* aria-audio-id: 手动添加,可选。表示该元素有预先录制好的音频供朗读,并记录音频id。
 
-## 特殊node(自动添加)
-* `<style id="aria-big-cursor-style-node"></style>`: 大号光标样式代码。
-* `<style id="aria-zoom-style-node"></style>`: 缩放样式代码。
+## 特殊node
+* `<style id="aria-big-cursor-style-node"></style>`: (自动添加)大号光标样式代码。
+* `<style id="aria-zoom-style-node"></style>`: (自动添加)缩放样式代码。
+* `<code aria-audio-id="lalala"></code>`: (手动添加)如果不方便给【需要朗读专门录制的音频】的元素添加aria-audio-id attribute,则可以用替代方案:给该元素添加这个code元素作为其第一个子元素。code元素不会显示在页面中。
 
 ## 数据同步
 同一个域的多个页面的accessibility组件实例、该域下的唯一一份local storage之间的无障碍菜单设置会自动同步。

+ 4 - 0
web/src/assets/css/ariaGlobalStyle.less

@@ -1,5 +1,9 @@
 @import './common.less';
 
+code {
+  display: none;
+}
+
 .aria-active {
   .aria-theme-default {
     &:focus {

+ 24 - 0
web/src/utils.js

@@ -63,10 +63,22 @@ function extractTextForFocus(e) {
     elemDisc = meaningfulNode.innerText
   }
 
+  let elemAudioId = ''
+  const ariaElemAudioId = meaningfulNode.getAttribute('aria-audio-id')
+  if (ariaElemAudioId !== null) {
+    elemAudioId = ariaElemAudioId
+  } else {
+    let ariaElemAudioId2 = meaningfulNode.firstElementChild && meaningfulNode.firstElementChild.getAttribute('aria-audio-id')
+    if (ariaElemAudioId2) {
+      elemAudioId = ariaElemAudioId2
+    }
+  }
+  
   return {
     elemType,
     elemDisc,
     ariaNode: meaningfulNode,
+    elemAudioId,
   }
 }
 
@@ -124,10 +136,22 @@ function extractTextForMouseOver(e) {
     elemDisc = meaningfulNode.innerText
   }
 
+  let elemAudioId = ''
+  const ariaElemAudioId = meaningfulNode.getAttribute('aria-audio-id')
+  if (ariaElemAudioId !== null) {
+    elemAudioId = ariaElemAudioId
+  } else {
+    let ariaElemAudioId2 = meaningfulNode.firstElementChild && meaningfulNode.firstElementChild.getAttribute('aria-audio-id')
+    if (ariaElemAudioId2) {
+      elemAudioId = ariaElemAudioId2
+    }
+  }
+  
   return {
     elemType,
     elemDisc,
     ariaNode: meaningfulNode,
+    elemAudioId,
   }
 }
 

Разлика између датотеке није приказан због своје велике величине
+ 3 - 3
web/src/views/Search/data.js


Разлика између датотеке није приказан због своје велике величине
+ 3 - 3
web/src/views/Search/dataAll.js


+ 60 - 31
web/src/views/accessibility.vue

@@ -458,6 +458,7 @@ export default {
 
       elemType: '',
       elemDisc: '',
+      elemAudioId: '',
 
       continueReadTimeoutId: null,
       continueReadTaskId: null,
@@ -733,41 +734,67 @@ export default {
       this.mouseDownLastTime = Date.now()
     },
     planToPlayAudio(taskId, text = '') {
-      let XHR = new XMLHttpRequest()
-      const that = this
-      XHR.onreadystatechange = function() {
-        if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
-          const res = JSON.parse(this.response)
-          if (that.audioPlayer && !that.audioPlayer.ended) {
-            that.audioPlayer.pause()
+      if (this.elemAudioId) {
+        if (this.audioPlayer && !this.audioPlayer.ended) {
+          this.audioPlayer.pause()
+        }
+        this.audioPlayer = new Audio('https://culture.4dage.com/one_day_in_southern_song_dynasty_cn_de/media/%E5%8D%88-%E5%8F%A4%E7%90%B4.252acfee.mp3') // todo
+        this.audioPlayer.muted = this.ariaSettings.isMuted
+        this.audioPlayer.playbackRate = speechRateFactors[this.ariaSettings.speechRateLevel]
+        this.audioPlayer.oncanplaythrough = () => {
+          if (document.visibilityState === 'visible') {
+            this.audioPlayer.play()
+          } else {
+            this.$emit('audio-abort', taskId)
           }
-          that.audioPlayer = new Audio(ajaxOrigin + res.msg)
-          that.audioPlayer.muted = that.ariaSettings.isMuted
-          that.audioPlayer.playbackRate = speechRateFactors[that.ariaSettings.speechRateLevel]
-          that.audioPlayer.oncanplaythrough = () => {
-            if (document.visibilityState === 'visible') {
-              that.audioPlayer.play()
-            } else {
+        }
+        this.audioPlayer.onended = () => {
+          this.$emit('audio-end', taskId)
+        }
+        this.audioPlayer.onerror = (e) => {
+          console.error('audio error!', e)
+          this.$emit('audio-error', taskId)
+        }
+        this.audioPlayer.onabort = () => {
+          this.$emit('audio-abort', taskId)
+        }
+      } else {
+        let XHR = new XMLHttpRequest()
+        const that = this
+        XHR.onreadystatechange = function() {
+          if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
+            const res = JSON.parse(this.response)
+            if (that.audioPlayer && !that.audioPlayer.ended) {
+              that.audioPlayer.pause()
+            }
+            that.audioPlayer = new Audio(ajaxOrigin + res.msg)
+            that.audioPlayer.muted = that.ariaSettings.isMuted
+            that.audioPlayer.playbackRate = speechRateFactors[that.ariaSettings.speechRateLevel]
+            that.audioPlayer.oncanplaythrough = () => {
+              if (document.visibilityState === 'visible') {
+                that.audioPlayer.play()
+              } else {
+                that.$emit('audio-abort', taskId)
+              }
+            }
+            that.audioPlayer.onended = () => {
+              that.$emit('audio-end', taskId)
+            }
+            that.audioPlayer.onerror = (e) => {
+              console.error('audio error!', e)
+              that.$emit('audio-error', taskId)
+            }
+            that.audioPlayer.onabort = () => {
               that.$emit('audio-abort', taskId)
             }
           }
-          that.audioPlayer.onended = () => {
-            that.$emit('audio-end', taskId)
-          }
-          that.audioPlayer.onerror = (e) => {
-            console.error('audio error!', e)
-            that.$emit('audio-error', taskId)
-          }
-          that.audioPlayer.onabort = () => {
-            that.$emit('audio-abort', taskId)
-          }
         }
+        XHR.open("POST", `${ajaxOrigin}/api/tts/toMp3`)
+        XHR.setRequestHeader("Content-Type", "application/json;charset=UTF-8")
+        XHR.send(JSON.stringify({
+          content: text || this.elemType + (this.elemType ? ': ' : '') + this.elemDisc
+        }))
       }
-      XHR.open("POST", `${ajaxOrigin}/api/tts/toMp3`)
-      XHR.setRequestHeader("Content-Type", "application/json;charset=UTF-8")
-      XHR.send(JSON.stringify({
-        content: text || this.elemType + (this.elemType ? ': ' : '') + this.elemDisc
-      }))
     },
     keyEventHandler(e) {
       if (e.repeat) {
@@ -912,7 +939,7 @@ export default {
       if (extractedText) {
         this.elemType = extractedText.elemType
         this.elemDisc = extractedText.elemDisc
-
+        this.elemAudioId = extractedText.elemAudioId
         this.planToPlayAudio()
       }
     }, 500),
@@ -937,6 +964,7 @@ export default {
       if (extractedText) {
         this.elemType = extractedText.elemType
         this.elemDisc = extractedText.elemDisc
+        this.elemAudioId = extractedText.elemAudioId
         clearTimeout(this.continueReadTimeoutId)
         this.continueReadTimeoutId = setTimeout(() => {
           this.continueReadIteratorStoper && this.continueReadIteratorStoper()
@@ -994,7 +1022,8 @@ export default {
       if (extractedText) {
         this.elemType = extractedText.elemType
         this.elemDisc = extractedText.elemDisc
-
+        this.elemAudioId = extractedText.elemAudioId
+        
         this.planToPlayAudio(this.continueReadTaskId)
       }
     },

Разлика између датотеке није приказан због своје велике величине
+ 3 - 3
web/src/views/dataAll.js