Bläddra i källkod

:art: fix https://github.com/Vanessa219/vditor/issues/1611

Vanessa 1 år sedan
förälder
incheckning
80d22da7ee
1 ändrade filer med 60 tillägg och 54 borttagningar
  1. 60 54
      src/ts/markdown/speechRender.ts

+ 60 - 54
src/ts/markdown/speechRender.ts

@@ -5,56 +5,63 @@ declare global {
         vditorSpeechRange: Range;
     }
 }
+
 export const speechRender = (element: HTMLElement, lang: keyof II18n = "zh_CN") => {
     if (typeof speechSynthesis === "undefined" || typeof SpeechSynthesisUtterance === "undefined") {
         return;
     }
+
+    const getVoice = () => {
+        const voices = speechSynthesis.getVoices();
+        let currentVoice: SpeechSynthesisVoice;
+        let defaultVoice;
+        voices.forEach((item) => {
+            if (item.lang === lang.replace("_", "-")) {
+                currentVoice = item;
+            }
+            if (item.default) {
+                defaultVoice = item;
+            }
+        });
+        if (!currentVoice) {
+            currentVoice = defaultVoice;
+        }
+        return currentVoice;
+    };
+
     let playSVG = '<svg><use xlink:href="#vditor-icon-play"></use></svg>';
     let pauseSVG = '<svg><use xlink:href="#vditor-icon-pause"></use></svg>';
     if (!document.getElementById("vditorIconScript")) {
         playSVG = '<svg viewBox="0 0 32 32"><path d="M3.436 0l25.128 16-25.128 16v-32z"></path></svg>';
         pauseSVG = '<svg viewBox="0 0 32 32"><path d="M20.617 0h9.128v32h-9.128v-32zM2.255 32v-32h9.128v32h-9.128z"></path></svg>';
     }
-    let speechDom: HTMLDivElement = document.querySelector(".vditor-speech");
+
+    let speechDom: HTMLButtonElement = document.querySelector(".vditor-speech");
     if (!speechDom) {
-        speechDom = document.createElement("div");
+        speechDom = document.createElement("button");
         speechDom.className = "vditor-speech";
-        document.body.insertAdjacentElement("beforeend", speechDom);
-
-        const getVoice = () => {
-            const voices = speechSynthesis.getVoices();
-            let currentVoice;
-            let defaultVoice;
-            voices.forEach((item) => {
-                if (item.lang === lang.replace("_", "-")) {
-                    currentVoice = item;
-                }
-                if (item.default) {
-                    defaultVoice = item;
-                }
-            });
-            if (!currentVoice) {
-                currentVoice = defaultVoice;
-            }
-            return currentVoice;
-        };
-
+        element.insertAdjacentElement("beforeend", speechDom);
         if (speechSynthesis.onvoiceschanged !== undefined) {
             speechSynthesis.onvoiceschanged = getVoice;
         }
+    }
+    const voice = getVoice();
+    const utterThis = new SpeechSynthesisUtterance();
+    utterThis.voice = voice;
+    utterThis.onend = utterThis.onerror = () => {
+        speechDom.style.display = "none";
+        speechSynthesis.cancel();
+        speechDom.classList.remove("vditor-speech--current");
+        speechDom.innerHTML = playSVG;
+    };
 
-        const voice = getVoice();
-        speechDom.onclick = () => {
-            if (speechDom.className === "vditor-speech") {
-                const utterThis = new SpeechSynthesisUtterance(speechDom.getAttribute("data-text"));
-                utterThis.voice = voice;
-                utterThis.onend = () => {
-                    speechDom.className = "vditor-speech";
-                    speechSynthesis.cancel();
-                    speechDom.innerHTML = playSVG;
-                };
+    element.addEventListener(window.ontouchstart !== undefined ? "touchend" : "click", (event) => {
+        const target = event.target as HTMLElement
+        if (target.classList.contains("vditor-speech") || target.parentElement.classList.contains("vditor-speech")) {
+            if (!speechDom.classList.contains("vditor-speech--current")) {
+                utterThis.text = speechDom.getAttribute("data-text");
                 speechSynthesis.speak(utterThis);
-                speechDom.className = "vditor-speech vditor-speech--current";
+                speechDom.classList.add("vditor-speech--current");
                 speechDom.innerHTML = pauseSVG;
             } else {
                 if (speechSynthesis.speaking) {
@@ -67,35 +74,34 @@ export const speechRender = (element: HTMLElement, lang: keyof II18n = "zh_CN")
                     }
                 }
             }
-
             setSelectionFocus(window.vditorSpeechRange);
-        };
-
-        document.body.addEventListener("click", () => {
-            if (getSelection().toString().trim() === "" && speechDom.style.display === "block") {
-                speechDom.className = "vditor-speech";
-                speechSynthesis.cancel();
-                speechDom.style.display = "none";
-            }
-        });
-    }
+            element.focus();
+            return;
+        }
 
-    element.addEventListener("mouseup", (event: MouseEvent) => {
-        const text = getSelection().toString().trim();
+        speechDom.style.display = "none";
         speechSynthesis.cancel();
-        if (getSelection().toString().trim() === "") {
-            if (speechDom.style.display === "block") {
-                speechDom.className = "vditor-speech";
-                speechDom.style.display = "none";
-            }
+        speechDom.classList.remove("vditor-speech--current");
+        speechDom.innerHTML = playSVG;
+
+        if (getSelection().rangeCount === 0) {
             return;
         }
-        window.vditorSpeechRange = getSelection().getRangeAt(0).cloneRange();
-        const rect = getSelection().getRangeAt(0).getBoundingClientRect();
+        const range = getSelection().getRangeAt(0)
+        const text = range.toString().trim();
+        if (!text) {
+            return;
+        }
+        window.vditorSpeechRange = range.cloneRange();
+        const rect = range.getBoundingClientRect();
         speechDom.innerHTML = playSVG;
         speechDom.style.display = "block";
         speechDom.style.top = (rect.top + rect.height + document.querySelector("html").scrollTop - 20) + "px";
-        speechDom.style.left = (event.clientX + 2) + "px";
+        if (window.ontouchstart !== undefined) {
+            speechDom.style.left = ((event as TouchEvent).changedTouches[(event as TouchEvent).changedTouches.length - 1].pageX + 2) + "px";
+        } else {
+            speechDom.style.left = ((event as MouseEvent).clientX + 2) + "px";
+        }
         speechDom.setAttribute("data-text", text);
     });
 };