forked from mrlan/EnglishPal
				
			重构前端阅读js,新增阅读器全局对象,新增生词朗读按钮
							parent
							
								
									f3d609c92b
								
							
						
					
					
						commit
						03ccb3527a
					
				|  | @ -7,7 +7,9 @@ css: | ||||||
| js: | js: | ||||||
|   head: # 在页面加载之前加载 |   head: # 在页面加载之前加载 | ||||||
|     - static/js/jquery.js |     - static/js/jquery.js | ||||||
|  |     - static/js/read.js | ||||||
|     - static/js/word_operation.js |     - static/js/word_operation.js | ||||||
|  | 
 | ||||||
|   bottom: # 在页面加载完之后加载 |   bottom: # 在页面加载完之后加载 | ||||||
|     - static/js/fillword.js |     - static/js/fillword.js | ||||||
|     - static/js/highlight.js |     - static/js/highlight.js | ||||||
|  |  | ||||||
|  | @ -1,9 +1,5 @@ | ||||||
| let isRead = true; | let isRead = true; | ||||||
| let isChoose = true; | let isChoose = true; | ||||||
| let reader = window.speechSynthesis; // 全局定义朗读者,以便朗读和暂停
 |  | ||||||
| let current_position = 0; // 朗读文本的当前位置
 |  | ||||||
| let original_position = 0; // 朗读文本的初始位置
 |  | ||||||
| let to_speak = ""; // 朗读的初始内容
 |  | ||||||
| 
 | 
 | ||||||
| function getWord() { | function getWord() { | ||||||
|     return window.getSelection ? window.getSelection() : document.selection.createRange().text; |     return window.getSelection ? window.getSelection() : document.selection.createRange().text; | ||||||
|  | @ -11,7 +7,7 @@ function getWord() { | ||||||
| 
 | 
 | ||||||
| function fillInWord() { | function fillInWord() { | ||||||
|     let word = getWord(); |     let word = getWord(); | ||||||
|     if (isRead) read(word); |     if (isRead) Reader.read(word, inputSlider.value); | ||||||
|     if (!isChoose) return; |     if (!isChoose) return; | ||||||
|     const element = document.getElementById("selected-words"); |     const element = document.getElementById("selected-words"); | ||||||
|     element.value = element.value + " " + word; |     element.value = element.value + " " + word; | ||||||
|  | @ -19,50 +15,17 @@ function fillInWord() { | ||||||
| 
 | 
 | ||||||
| document.getElementById("text-content").addEventListener("click", fillInWord, false); | document.getElementById("text-content").addEventListener("click", fillInWord, false); | ||||||
| 
 | 
 | ||||||
| function makeUtterance(str, rate) { | const sliderValue = document.getElementById("rangeValue"); | ||||||
|     let msg = new SpeechSynthesisUtterance(str); | const inputSlider = document.getElementById("rangeComponent"); | ||||||
|     msg.rate = rate; |  | ||||||
|     msg.lang = "en-US"; // TODO: add language options menu
 |  | ||||||
|     msg.onboundary = ev => { |  | ||||||
|         if (ev.name == "word") { |  | ||||||
|             current_position = ev.charIndex; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     return msg; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const sliderValue = document.getElementById("rangeValue"); // 显示值
 |  | ||||||
| const inputSlider = document.getElementById("rangeComponent"); // 滑块元素
 |  | ||||||
| inputSlider.oninput = () => { | inputSlider.oninput = () => { | ||||||
|     let value = inputSlider.value; // 获取滑块的值
 |     let value = inputSlider.value; | ||||||
|     sliderValue.textContent = value + '×'; |     sliderValue.textContent = value + '×'; | ||||||
|     if (!reader.speaking) return; |  | ||||||
|     reader.cancel(); |  | ||||||
|     let msg = makeUtterance(to_speak.substring(original_position + current_position), value); |  | ||||||
|     original_position = original_position + current_position; |  | ||||||
|     current_position = 0; |  | ||||||
|     reader.speak(msg); |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| function read(s) { |  | ||||||
|     to_speak = s.toString(); |  | ||||||
|     original_position = 0; |  | ||||||
|     current_position = 0; |  | ||||||
|     let msg = makeUtterance(to_speak, inputSlider.value); |  | ||||||
|     reader.speak(msg); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function onReadClick() { | function onReadClick() { | ||||||
|     isRead = !isRead; |     isRead = !isRead; | ||||||
|     if (!isRead) { |  | ||||||
|         reader.cancel(); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function onChooseClick() { | function onChooseClick() { | ||||||
|     isChoose = !isChoose; |     isChoose = !isChoose; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| function stopRead() { |  | ||||||
|     reader.cancel(); |  | ||||||
| } |  | ||||||
|  | @ -0,0 +1,36 @@ | ||||||
|  | // read.js
 | ||||||
|  | var Reader = (function() { | ||||||
|  |     let reader = window.speechSynthesis; | ||||||
|  |     let current_position = 0; | ||||||
|  |     let original_position = 0; | ||||||
|  |     let to_speak = ""; | ||||||
|  | 
 | ||||||
|  |     function makeUtterance(str, rate) { | ||||||
|  |         let msg = new SpeechSynthesisUtterance(str); | ||||||
|  |         msg.rate = rate; | ||||||
|  |         msg.lang = "en-US"; | ||||||
|  |         msg.onboundary = ev => { | ||||||
|  |             if (ev.name == "word") { | ||||||
|  |                 current_position = ev.charIndex; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return msg; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function read(s, rate) { | ||||||
|  |         to_speak = s.toString(); | ||||||
|  |         original_position = 0; | ||||||
|  |         current_position = 0; | ||||||
|  |         let msg = makeUtterance(to_speak, rate); | ||||||
|  |         reader.speak(msg); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function stopRead() { | ||||||
|  |         reader.cancel(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return { | ||||||
|  |         read: read, | ||||||
|  |         stopRead: stopRead | ||||||
|  |     }; | ||||||
|  | })(); | ||||||
|  | @ -62,6 +62,13 @@ function delete_word(theWord) { | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function read_word(theWord) { | ||||||
|  |     let to_speak = $("#word_" + theWord).text(); | ||||||
|  |     original_position = 0; | ||||||
|  |     current_position = 0; | ||||||
|  |     Reader.read(to_speak, inputSlider.value); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*  | /*  | ||||||
|  * interface Word { |  * interface Word { | ||||||
|  *   word: string, |  *   word: string, | ||||||
|  | @ -95,6 +102,7 @@ function wordTemplate(word) { | ||||||
|         <a class="btn btn-success" onclick="familiar('${word.word}')" role="button">熟悉</a> |         <a class="btn btn-success" onclick="familiar('${word.word}')" role="button">熟悉</a> | ||||||
|         <a class="btn btn-warning" onclick="unfamiliar('${word.word}')" role="button">不熟悉</a> |         <a class="btn btn-warning" onclick="unfamiliar('${word.word}')" role="button">不熟悉</a> | ||||||
|         <a class="btn btn-danger" onclick="delete_word('${word.word}')" role="button">删除</a> |         <a class="btn btn-danger" onclick="delete_word('${word.word}')" role="button">删除</a> | ||||||
|  |         <a class="btn btn-info" onclick="read_word('${word.word}')" role="button">朗读</a> | ||||||
|     </p>`; |     </p>`; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -131,6 +131,7 @@ | ||||||
|                     <a class="btn btn-success" onclick="familiar('{{ word }}')" role="button">熟悉</a> |                     <a class="btn btn-success" onclick="familiar('{{ word }}')" role="button">熟悉</a> | ||||||
|                     <a class="btn btn-warning" onclick="unfamiliar('{{ word }}')" role="button">不熟悉</a> |                     <a class="btn btn-warning" onclick="unfamiliar('{{ word }}')" role="button">不熟悉</a> | ||||||
|                     <a class="btn btn-danger" onclick="delete_word('{{ word }}')" role="button">删除</a> |                     <a class="btn btn-danger" onclick="delete_word('{{ word }}')" role="button">删除</a> | ||||||
|  |                     <a class="btn btn-info" onclick="read_word('{{ word }}')" role="button">朗读</a> | ||||||
|                 </p> |                 </p> | ||||||
|             {% endfor %} |             {% endfor %} | ||||||
|         </div> |         </div> | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue