Compare commits
	
		
			5 Commits 
		
	
	
		
			master
			...
			Bug407-Jin
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | 9d9590328d | |
|  | dabeb0d2a9 | |
|  | 4dc2c9c591 | |
|  | 72e23f4e13 | |
|  | 5a62204864 | 
|  | @ -1,68 +1,40 @@ | ||||||
| let isRead = true; | var isRead = true; | ||||||
| let isChoose = true; | var isChoose = true; | ||||||
| let reader = window.speechSynthesis; // 全局定义朗读者,以便朗读和暂停
 | const 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; | ||||||
| } | } | ||||||
| 
 | //填充字符
 | ||||||
| function fillInWord() { | function fillingWord() { | ||||||
|     let word = getWord(); |   let word = getWord(); | ||||||
|     if (isRead) read(word); |   if (isRead) read(word); | ||||||
|     if (!isChoose) return; |   if (!isChoose) return; | ||||||
|     const element = document.getElementById("selected-words"); |   let element = document.getElementById("selected-words"); | ||||||
|     element.value = element.value + " " + word; |   element.value = element.value + " " + word; | ||||||
| } | } | ||||||
| 
 | document | ||||||
| document.getElementById("text-content").addEventListener("click", fillInWord, false); |   .getElementById("text-content") | ||||||
| 
 |   .addEventListener("click", fillingWord, false); | ||||||
| function makeUtterance(str, rate) { | //朗读单词
 | ||||||
|     let msg = new SpeechSynthesisUtterance(str); | //@word 要朗读的单词
 | ||||||
|     msg.rate = rate; | function read(word) { | ||||||
|     msg.lang = "en-US"; // TODO: add language options menu
 |   //关闭当前正在读的单词
 | ||||||
|     msg.onboundary = ev => { |   reader.cancel(); | ||||||
|         if (ev.name == "word") { |   //创建新的朗读任务
 | ||||||
|             current_position = ev.charIndex; |   let msg = new SpeechSynthesisUtterance(word); | ||||||
|         } |   reader.speak(msg); | ||||||
|     } |  | ||||||
|     return msg; |  | ||||||
| } | } | ||||||
| 
 | //关闭正在读的单词
 | ||||||
| const sliderValue = document.getElementById("rangeValue"); // 显示值
 |  | ||||||
| const inputSlider = document.getElementById("rangeComponent"); // 滑块元素
 |  | ||||||
| inputSlider.oninput = () => { |  | ||||||
|     let value = inputSlider.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; |   let isRead = !isRead; | ||||||
|     if (!isRead) { |   if (!isRead) { | ||||||
|         reader.cancel(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function onChooseClick() { |  | ||||||
|     isChoose = !isChoose; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function stopRead() { |  | ||||||
|     reader.cancel(); |     reader.cancel(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | //取消当前选择
 | ||||||
|  | function onChooseClick() { | ||||||
|  |   isChoose = !isChoose; | ||||||
| } | } | ||||||
|  | @ -1,154 +1,265 @@ | ||||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||||
| <html lang="en"> | <html lang="en"> | ||||||
| <head> |   <head> | ||||||
|     <meta charset="UTF-8"> |     <meta charset="UTF-8" /> | ||||||
|     <meta name="viewport" |     <meta | ||||||
|           content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=3.0, user-scalable=yes"/> |       name="viewport" | ||||||
|     <meta name="format-detection" content="telephone=no"/> |       content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=3.0, user-scalable=yes" | ||||||
|  |     /> | ||||||
|  |     <meta name="format-detection" content="telephone=no" /> | ||||||
| 
 | 
 | ||||||
|     {{ yml['header'] | safe }} |     {{ yml['header'] | safe }} {% if yml['css']['item'] %} {% for css in | ||||||
|     {% if yml['css']['item'] %} |     yml['css']['item'] %} | ||||||
|         {% for css in yml['css']['item'] %} |     <link href="{{ css }}" rel="stylesheet" /> | ||||||
|             <link href="{{ css }}" rel="stylesheet"> |     {% endfor %} {% endif %} {% if yml['js']['head'] %} {% for js in | ||||||
|         {% endfor %} |     yml['js']['head'] %} | ||||||
|     {% endif %} |     <script src="{{ js }}"></script> | ||||||
|     {% if yml['js']['head'] %} |     {% endfor %} {% endif %} | ||||||
|         {% for js in yml['js']['head'] %} |  | ||||||
|             <script src="{{ js }}"></script> |  | ||||||
|         {% endfor %} |  | ||||||
|     {% endif %} |  | ||||||
| 
 | 
 | ||||||
|     <title>EnglishPal Study Room for {{ username }}</title> |     <title>EnglishPal Study Room for {{ username }}</title> | ||||||
| 
 | 
 | ||||||
|     <style> |     <style> | ||||||
|         .shaking { |       .shaking { | ||||||
|             animation: shakes 1600ms ease-in-out; |         animation: shakes 1600ms ease-in-out; | ||||||
|         } |       } | ||||||
| 
 | 
 | ||||||
|         @keyframes shakes { |       @keyframes shakes { | ||||||
|             10%, 90% { transform: translate3d(-1px, 0, 0); } |         10%, | ||||||
|             20%, 50% { transform: translate3d(+2px, 0, 0); } |         90% { | ||||||
|             30%, 70% { transform: translate3d(-4px, 0, 0); } |           transform: translate3d(-1px, 0, 0); | ||||||
|             40%, 60% { transform: translate3d(+4px, 0, 0); } |  | ||||||
|             50% { transform: translate3d(-4px, 0, 0); } |  | ||||||
|         } |         } | ||||||
|  |         20%, | ||||||
|  |         50% { | ||||||
|  |           transform: translate3d(+2px, 0, 0); | ||||||
|  |         } | ||||||
|  |         30%, | ||||||
|  |         70% { | ||||||
|  |           transform: translate3d(-4px, 0, 0); | ||||||
|  |         } | ||||||
|  |         40%, | ||||||
|  |         60% { | ||||||
|  |           transform: translate3d(+4px, 0, 0); | ||||||
|  |         } | ||||||
|  |         50% { | ||||||
|  |           transform: translate3d(-4px, 0, 0); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|     </style> |     </style> | ||||||
| </head> |   </head> | ||||||
| <body> |   <body> | ||||||
| <div class="container-fluid"> |     <div class="container-fluid"> | ||||||
|     <p><b>English Pal for <font id="username" color="red">{{ username }}</font></b> |       <p> | ||||||
|         {% if username ==  admin_name %} |         <b | ||||||
|         <a class="btn btn-secondary" href="/admin" role="button" onclick="stopRead()">管理</a> |           >English Pal for | ||||||
|  |           <font id="username" color="red">{{ username }}</font></b | ||||||
|  |         > | ||||||
|  |         {% if username == admin_name %} | ||||||
|  |         <a | ||||||
|  |           class="btn btn-secondary" | ||||||
|  |           href="/admin" | ||||||
|  |           role="button" | ||||||
|  |           onclick="stopRead()" | ||||||
|  |           >管理</a | ||||||
|  |         > | ||||||
|         {% endif %} |         {% endif %} | ||||||
|         <a class="btn btn-secondary" href="/logout" role="button" onclick="stopRead()">退出</a> |         <a | ||||||
|         <a class="btn btn-secondary" href="/reset" role="button" onclick="stopRead()">重设密码</a> |           class="btn btn-secondary" | ||||||
|     </p> |           href="/logout" | ||||||
| {#    {% for message in flashed_messages %}#} {# 根据user_service.userpage,取消了参数flashed_messages,因此注释了这段代码 #} |           role="button" | ||||||
| {#        <div class="alert alert-warning" role="alert">Congratulations! {{ message }}</div>#} |           onclick="stopRead()" | ||||||
| {#    {% endfor %}#} |           >退出</a | ||||||
|  |         > | ||||||
|  |         <a | ||||||
|  |           class="btn btn-secondary" | ||||||
|  |           href="/reset" | ||||||
|  |           role="button" | ||||||
|  |           onclick="stopRead()" | ||||||
|  |           >重设密码</a | ||||||
|  |         > | ||||||
|  |       </p> | ||||||
|  |       {# {% for message in flashed_messages %}#} {# | ||||||
|  |       根据user_service.userpage,取消了参数flashed_messages,因此注释了这段代码 | ||||||
|  |       #} {# | ||||||
|  |       <div class="alert alert-warning" role="alert"> | ||||||
|  |         Congratulations! {{ message }} | ||||||
|  |       </div> | ||||||
|  |       #} {# {% endfor %}#} | ||||||
| 
 | 
 | ||||||
|     <a class="btn btn-success" href="/{{ username }}/reset" role="button"> 下一篇 Next Article </a> |       <a | ||||||
|     {% if session.get('existing_articles') != None and session.get('existing_articles')["index"] !=0 %} |         class="btn btn-success" | ||||||
|         <a class="btn btn-success" href="/{{ username }}/back" role="button"> 上一篇 Previous Article </a> |         href="/{{ username }}/reset" | ||||||
|     {% endif %} |         role="button" | ||||||
|  |         onclick="stopRead()" | ||||||
|  |       > | ||||||
|  |         下一篇 Next Article | ||||||
|  |       </a> | ||||||
|  |       {% if session.get('existing_articles') != None and | ||||||
|  |       session.get('existing_articles')["index"] !=0 %} | ||||||
|  |       <a | ||||||
|  |         class="btn btn-success" | ||||||
|  |         href="/{{ username }}/back" | ||||||
|  |         role="button" | ||||||
|  |         onclick="stopRead()" | ||||||
|  |       > | ||||||
|  |         上一篇 Previous Article | ||||||
|  |       </a> | ||||||
|  |       {% endif %} | ||||||
| 
 | 
 | ||||||
|     <p><b>阅读文章并回答问题</b></p> |       <p><b>阅读文章并回答问题</b></p> | ||||||
|     <div id="text-content"> |       <div id="text-content"> | ||||||
|         {% if today_article %} |         {% if today_article %} | ||||||
|             <div class="alert alert-success" role="alert">According to your word list, your level is <span class="badge bg-success">{{ today_article["user_level"] }}</span>  and we have chosen an article with a difficulty level of <span class="badge bg-success">{{ today_article["text_level"] }}</span> for you.</div> |         <div class="alert alert-success" role="alert"> | ||||||
|                 <p class="text-muted">Article added on: {{ today_article["date"] }}</p><br/> |           According to your word list, your level is | ||||||
|             <div class="p-3 mb-2 bg-light text-dark"><br/> |           <span class="badge bg-success" | ||||||
|             <p class="display-5">{{ today_article["article_title"] }}</p><br/> |             >{{ today_article["user_level"] }}</span | ||||||
|             <p class="lead"><font id="article" size=2>{{ today_article["article_body"] }}</font></p><br/> |           > | ||||||
|             <p><small class="text-muted">{{ today_article['source'] }}</small></p><br/> |           and we have chosen an article with a difficulty level of | ||||||
|             <p><b>{{ today_article['question'] }}</b></p><br/> |           <span class="badge bg-success" | ||||||
|                 <script type="text/javascript"> |             >{{ today_article["text_level"] }}</span | ||||||
|                     function toggle_visibility(id) { {# https://css-tricks.com/snippets/javascript/showhide-element/#} |           > | ||||||
|                         const e = document.getElementById(id); |           for you. | ||||||
|                         if(e.style.display === 'block') |  | ||||||
|                             e.style.display = 'none'; |  | ||||||
|                         else |  | ||||||
|                             e.style.display = 'block'; |  | ||||||
|                     } |  | ||||||
|                 </script> |  | ||||||
|                 <button onclick="toggle_visibility('answer');">ANSWER</button> |  | ||||||
|                 <div id="answer" style="display:none;">{{ today_article['answer'] }}</div><br/> |  | ||||||
|             </div> |  | ||||||
|         {% else %} |  | ||||||
|             <div class="alert alert-success" role="alert"> |  | ||||||
|                 <p class="text-muted"><span class="badge bg-success">Notes:</span><br>No article is currently available for you. You can try again a few times or mark new words in the passage to improve your level.</p> |  | ||||||
|             </div> |  | ||||||
|         {% endif %} |  | ||||||
|     </div> |  | ||||||
| 
 |  | ||||||
|     <input type="checkbox" onclick="toggleHighlighting()" checked/>生词高亮 |  | ||||||
|     <input type="checkbox" onclick="onReadClick()" checked/>大声朗读 |  | ||||||
|     <input type="checkbox" onclick="onChooseClick()" checked/>划词入库 |  | ||||||
|     <div class="range"> |  | ||||||
|         <div class="field"> |  | ||||||
|             <div class="sliderValue"> |  | ||||||
|                 <span id="rangeValue">1×</span> |  | ||||||
|             </div> |  | ||||||
|             <input type="range" id="rangeComponent" min="0.5" max="2" value="1" step="0.25"/> |  | ||||||
|         </div> |         </div> | ||||||
|     </div> |         <p class="text-muted">Article added on: {{ today_article["date"] }}</p> | ||||||
|     <p><b>收集生词吧</b> (可以在正文中划词,也可以复制黏贴)</p> |         <br /> | ||||||
|     <form method="post" action="/{{ username }}"> |         <div class="p-3 mb-2 bg-light text-dark"> | ||||||
|         <textarea name="content" id="selected-words" rows="10" cols="120"></textarea><br/> |           <br /> | ||||||
|         <input type="submit" value="把生词加入我的生词库"/> |           <p class="display-5">{{ today_article["article_title"] }}</p> | ||||||
|         <input type="reset" value="清除"/> |           <br /> | ||||||
|     </form> |           <p class="lead"> | ||||||
|     {% if session.get['thisWord'] %} |             <font id="article" size="2" | ||||||
|         <script type="text/javascript"> |               >{{ today_article["article_body"] }}</font | ||||||
|             //point to the anchor in the page whose id is aaa if it exists |             > | ||||||
|             window.onload = function () { |           </p> | ||||||
|                 var element = document.getElementsByName("aaa"); |           <br /> | ||||||
|                 if (element != null) |           <p><small class="text-muted">{{ today_article['source'] }}</small></p> | ||||||
|                     document.getElementsByName("aaa")[0].scrollIntoView(true); |           <br /> | ||||||
|  |           <p><b>{{ today_article['question'] }}</b></p> | ||||||
|  |           <br /> | ||||||
|  |           <script type="text/javascript"> | ||||||
|  |             function toggle_visibility(id) { {# https://css-tricks.com/snippets/javascript/showhide-element/#} | ||||||
|  |                 const e = document.getElementById(id); | ||||||
|  |                 if(e.style.display === 'block') | ||||||
|  |                     e.style.display = 'none'; | ||||||
|  |                 else | ||||||
|  |                     e.style.display = 'block'; | ||||||
|             } |             } | ||||||
|         </script> |           </script> | ||||||
|     {% endif %} |           <button onclick="toggle_visibility('answer');">ANSWER</button> | ||||||
| 
 |           <div id="answer" style="display: none"> | ||||||
|     {% if d_len > 0 %} |             {{ today_article['answer'] }} | ||||||
|         <p> |           </div> | ||||||
|             <b>我的生词簿</b>  |           <br /> | ||||||
|             <label for="move_dynamiclly"> |  | ||||||
|                 <input type="checkbox" name="move_dynamiclly" id="move_dynamiclly" checked> |  | ||||||
|                 允许动态调整顺序 |  | ||||||
|             </label> |  | ||||||
|         </p> |  | ||||||
|         <a name="aaa"></a> |  | ||||||
|         <div class="word-container"> |  | ||||||
|             {% for x in lst3 %} |  | ||||||
|                 {% set word = x[0] %} |  | ||||||
|                 {% set freq = x[1] %} |  | ||||||
|                 {% if session.get('thisWord') == x[0] and session.get('time') == 1 %} |  | ||||||
|                 {% endif %} |  | ||||||
|                 <p id='p_{{ word }}' class="new-word" > |  | ||||||
|                     <a id="word_{{ word }}"  class="btn btn-light" href='http://youdao.com/w/eng/{{ word }}/#keyfrom=dict2.index' |  | ||||||
|                     role="button">{{ word }}</a> |  | ||||||
|                     ( <a id="freq_{{ word }}" title="{{ word }}">{{ freq }}</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-danger" onclick="delete_word('{{ word }}')" role="button">删除</a> |  | ||||||
|                 </p> |  | ||||||
|             {% endfor %} |  | ||||||
|         </div> |         </div> | ||||||
|         <input id="selected-words2" type="hidden" value="{{ words }}"> |         {% else %} | ||||||
|     {% endif %} |         <div class="alert alert-success" role="alert"> | ||||||
| </div> |           <p class="text-muted"> | ||||||
| {{ yml['footer'] | safe }} |             <span class="badge bg-success">Notes:</span><br />No article is | ||||||
| {% if yml['js']['bottom'] %} |             currently available for you. You can try again a few times or mark | ||||||
|     {% for js in yml['js']['bottom'] %} |             new words in the passage to improve your level. | ||||||
|         <script src="{{ js }}"></script> |           </p> | ||||||
|     {% endfor %} |         </div> | ||||||
| {% endif %} |         {% endif %} | ||||||
| </body> |       </div> | ||||||
| <style> | 
 | ||||||
|  |       <input type="checkbox" onclick="toggleHighlighting()" checked />生词高亮 | ||||||
|  |       <input type="checkbox" onclick="onReadClick()" checked />大声朗读 | ||||||
|  |       <input type="checkbox" onclick="onChooseClick()" checked />划词入库 | ||||||
|  |       <div class="range"> | ||||||
|  |         <div class="field"> | ||||||
|  |           <div class="sliderValue"> | ||||||
|  |             <span id="rangeValue">1×</span> | ||||||
|  |           </div> | ||||||
|  |           <input | ||||||
|  |             type="range" | ||||||
|  |             id="rangeComponent" | ||||||
|  |             min="0.5" | ||||||
|  |             max="2" | ||||||
|  |             value="1" | ||||||
|  |             step="0.25" | ||||||
|  |           /> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <p><b>收集生词吧</b> (可以在正文中划词,也可以复制黏贴)</p> | ||||||
|  |       <form method="post" action="/{{ username }}"> | ||||||
|  |         <textarea | ||||||
|  |           name="content" | ||||||
|  |           id="selected-words" | ||||||
|  |           rows="10" | ||||||
|  |           cols="120" | ||||||
|  |         ></textarea | ||||||
|  |         ><br /> | ||||||
|  |         <input type="submit" value="把生词加入我的生词库" /> | ||||||
|  |         <input type="reset" value="清除" /> | ||||||
|  |       </form> | ||||||
|  |       {% if session.get['thisWord'] %} | ||||||
|  |       <script type="text/javascript"> | ||||||
|  |         //point to the anchor in the page whose id is aaa if it exists | ||||||
|  |         window.onload = function () { | ||||||
|  |           var element = document.getElementsByName("aaa"); | ||||||
|  |           if (element != null) | ||||||
|  |             document.getElementsByName("aaa")[0].scrollIntoView(true); | ||||||
|  |         }; | ||||||
|  |       </script> | ||||||
|  |       {% endif %} {% if d_len > 0 %} | ||||||
|  |       <p> | ||||||
|  |         <b>我的生词簿</b> | ||||||
|  |         <label for="move_dynamiclly"> | ||||||
|  |           <input | ||||||
|  |             type="checkbox" | ||||||
|  |             name="move_dynamiclly" | ||||||
|  |             id="move_dynamiclly" | ||||||
|  |             checked | ||||||
|  |           /> | ||||||
|  |           允许动态调整顺序 | ||||||
|  |         </label> | ||||||
|  |       </p> | ||||||
|  |       <a name="aaa"></a> | ||||||
|  |       <div class="word-container"> | ||||||
|  |         {% for x in lst3 %} {% set word = x[0] %} {% set freq = x[1] %} {% if | ||||||
|  |         session.get('thisWord') == x[0] and session.get('time') == 1 %} {% endif | ||||||
|  |         %} | ||||||
|  |         <p id="p_{{ word }}" class="new-word"> | ||||||
|  |           <a | ||||||
|  |             id="word_{{ word }}" | ||||||
|  |             class="btn btn-light" | ||||||
|  |             href="http://youdao.com/w/eng/{{ word }}/#keyfrom=dict2.index" | ||||||
|  |             role="button" | ||||||
|  |             >{{ word }}</a | ||||||
|  |           > | ||||||
|  |           ( <a id="freq_{{ word }}" title="{{ word }}">{{ freq }}</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-danger" | ||||||
|  |             onclick="delete_word('{{ word }}')" | ||||||
|  |             role="button" | ||||||
|  |             >删除</a | ||||||
|  |           > | ||||||
|  |         </p> | ||||||
|  |         {% endfor %} | ||||||
|  |       </div> | ||||||
|  |       <input id="selected-words2" type="hidden" value="{{ words }}" /> | ||||||
|  |       {% endif %} | ||||||
|  |     </div> | ||||||
|  |     {{ yml['footer'] | safe }} {% if yml['js']['bottom'] %} {% for js in | ||||||
|  |     yml['js']['bottom'] %} | ||||||
|  |     <script src="{{ js }}"></script> | ||||||
|  |     {% endfor %} {% endif %} | ||||||
|  |   </body> | ||||||
|  |   <style> | ||||||
|     mark { |     mark { | ||||||
|         color: #{{ yml['highlight']['color'] }}; |         color: #{{ yml['highlight']['color'] }}; | ||||||
|         background-color: rgba(0, 0, 0, 0); |         background-color: rgba(0, 0, 0, 0); | ||||||
|     } |     } | ||||||
| </style> |   </style> | ||||||
| 
 |  | ||||||
| </html> | </html> | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue