forked from mrlan/EnglishPal
Fix bug 578
parent
8cbc7c9a0c
commit
9dab83219a
|
@ -0,0 +1,5 @@
|
|||
function toggleCheckboxSelection(checkStatus) {
|
||||
// used in userpage_post.html
|
||||
const checkBoxes = document.getElementsByName('marked');
|
||||
checkBoxes.forEach((checkbox) => { checkbox.checked = checkStatus;} );
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
let isRead = true;
|
||||
let isChoose = true;
|
||||
let isRead = localStorage.getItem('readChecked') !== 'false'; // default to true
|
||||
let isChoose = localStorage.getItem('chooseChecked') !== 'false';
|
||||
|
||||
function getWord() {
|
||||
return window.getSelection ? window.getSelection() : document.selection.createRange().text;
|
||||
|
@ -8,10 +8,18 @@ function getWord() {
|
|||
function fillInWord() {
|
||||
let word = getWord();
|
||||
if (isRead) Reader.read(word, inputSlider.value);
|
||||
if (!isChoose) return;
|
||||
const element = document.getElementById("selected-words");
|
||||
if (!isChoose) {
|
||||
if(isHighlight){
|
||||
const element = document.getElementById("selected-words3");
|
||||
element.value = element.value + " " + word;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const element = document.getElementById("selected-words");
|
||||
localStorage.setItem('nowWords', element.value);
|
||||
element.value = element.value + " " + word;
|
||||
localStorage.setItem('selectedWords', element.value);
|
||||
}
|
||||
|
||||
document.getElementById("text-content").addEventListener("click", fillInWord, false);
|
||||
|
||||
|
@ -24,8 +32,16 @@ inputSlider.oninput = () => {
|
|||
|
||||
function onReadClick() {
|
||||
isRead = !isRead;
|
||||
localStorage.setItem('readChecked', isRead);
|
||||
}
|
||||
|
||||
function onChooseClick() {
|
||||
isChoose = !isChoose;
|
||||
localStorage.setItem('chooseChecked', isChoose);
|
||||
}
|
||||
|
||||
// 如果网页刷新,停止播放声音
|
||||
if (performance.getEntriesByType("navigation")[0].type == "reload") {
|
||||
Reader.stopRead();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
let isHighlight = true;
|
||||
let isHighlight = localStorage.getItem('highlightChecked') !== 'false'; // default to true
|
||||
|
||||
function cancelBtnHandler() {
|
||||
cancelHighlighting();
|
||||
|
@ -22,62 +22,48 @@ function getWord() {
|
|||
|
||||
function highLight() {
|
||||
if (!isHighlight) return;
|
||||
let articleContent = document.getElementById("article").innerText; //将原来的.innerText改为.innerHtml,使用innerText会把原文章中所包含的<br>标签去除,导致处理后的文章内容失去了原来的格式
|
||||
let word = (getWord() + "").trim();
|
||||
let articleContent = document.getElementById("article").innerHTML; // innerHTML保留HTML标签来保持部分格式,且适配不同的浏览器
|
||||
let pickedWords = document.getElementById("selected-words"); // words picked to the text area
|
||||
let dictionaryWords = document.getElementById("selected-words2"); // words appearing in the user's new words list
|
||||
let allWords = ""; //初始化allWords的值,避免进入判断后编译器认为allWords未初始化的问题
|
||||
if(dictionaryWords != null){//增加一个判断,检查生词本里面是否为空,如果为空,allWords只添加选中的单词
|
||||
allWords = pickedWords.value + " " + dictionaryWords.value;
|
||||
let allWords = dictionaryWords === null ? pickedWords.value + " " : pickedWords.value + " " + dictionaryWords.value;
|
||||
highlightWords = document.getElementById("selected-words3");
|
||||
allWords = highlightWords == null ? allWords : allWords + " " + highlightWords.value;
|
||||
const list = allWords.split(" "); // 将所有的生词放入一个list中
|
||||
if(word !== null && word !== "" && word !== " "){
|
||||
let articleContent_fb2 = articleContent;
|
||||
if(localStorage.getItem("nowWords").indexOf(word) !== -1 || localStorage.getItem("nowWords").indexOf(word.toLowerCase()) !== -1){
|
||||
articleContent = articleContent.replace(new RegExp('<span class="highlighted">' + word + '</span>', "gi"), word);
|
||||
pickedWords.value = localStorage.getItem("nowWords").replace(word,"");
|
||||
document.getElementById("article").innerHTML = articleContent;
|
||||
return;
|
||||
}
|
||||
else{
|
||||
allWords = pickedWords.value + " ";
|
||||
}
|
||||
const list = allWords.split(" ");//将所有的生词放入一个list中,用于后续处理
|
||||
let totalSet = new Set();
|
||||
for (let i = 0; i < list.length; ++i) {
|
||||
list[i] = list[i].replace(/(^\s*)|(\s*$)/g, ""); //消除单词两边的空字符
|
||||
list[i] = list[i].replace(/(^\W*)|(\W*$)/g, ""); // 消除单词两边的非单词字符
|
||||
list[i] = list[i].replace('|', "");
|
||||
list[i] = list[i].replace('?', "");
|
||||
if (list[i] !== "" && "<mark>".indexOf(list[i]) === -1 && "</mark>".indexOf(list[i]) === -1) {
|
||||
//将文章中所有出现该单词word的地方改为:"<mark>" + word + "<mark>"。 正则表达式RegExp()中,"\\b"代表单词边界匹配。
|
||||
|
||||
//修改代码
|
||||
let articleContent_fb = articleContent; //文章副本
|
||||
while(articleContent_fb.toLowerCase().indexOf(list[i].toLowerCase()) !== -1 && list[i]!=""){
|
||||
//找到副本中和list[i]匹配的第一个单词(第一种匹配情况),并赋值给list[i]。
|
||||
const index = articleContent_fb.toLowerCase().indexOf(list[i].toLowerCase());
|
||||
list[i] = articleContent_fb.substring(index, index + list[i].length);
|
||||
|
||||
articleContent_fb = articleContent_fb.substring(index + list[i].length); // 使用副本中list[i]之后的子串替换掉副本
|
||||
articleContent = articleContent.replace(new RegExp("\\b"+list[i]+"\\b","g"),"<mark>" + list[i] + "</mark>");
|
||||
if (list[i] != "" && !totalSet.has(list[i])) {
|
||||
// 返回所有匹配单词的集合, 正则表达式RegExp()中, "\b"匹配一个单词的边界, g 表示全局匹配, i 表示对大小写不敏感。
|
||||
let matches = new Set(articleContent.match(new RegExp("\\b" + list[i] + "\\b", "gi")));
|
||||
totalSet = new Set([...totalSet, ...matches]);
|
||||
}
|
||||
}
|
||||
// 删除所有的"<span class='highlighted'>"标签,防止标签发生嵌套
|
||||
articleContent = articleContent.replace(new RegExp('<span class="highlighted">',"gi"), "")
|
||||
articleContent = articleContent.replace(new RegExp("</span>","gi"), "");
|
||||
// 将文章中所有出现该单词word的地方改为:"<span class='highlighted'>" + word + "</span>"。
|
||||
for (let word of totalSet) {
|
||||
articleContent = articleContent.replace(new RegExp("\\b" + word + "\\b", "g"), "<span class='highlighted'>" + word + "</span>");
|
||||
}
|
||||
document.getElementById("article").innerHTML = articleContent;
|
||||
}
|
||||
|
||||
function cancelHighlighting() {
|
||||
let articleContent = document.getElementById("article").innerText;//将原来的.innerText改为.innerHtml,原因同上
|
||||
let pickedWords = document.getElementById("selected-words");
|
||||
const dictionaryWords = document.getElementById("selected-words2");
|
||||
const list = pickedWords.value.split(" ");
|
||||
if (pickedWords != null) {
|
||||
for (let i = 0; i < list.length; ++i) {
|
||||
list[i] = list[i].replace(/(^\s*)|(\s*$)/g, "");
|
||||
if (list[i] !== "") { //原来判断的代码中,替换的内容为“list[i]”这个字符串,这明显是错误的,我们需要替换的是list[i]里的内容
|
||||
articleContent = articleContent.replace(new RegExp("<mark>"+list[i]+"</mark>", "g"), list[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dictionaryWords != null) {
|
||||
let list2 = pickedWords.value.split(" ");
|
||||
for (let i = 0; i < list2.length; ++i) {
|
||||
list2 = dictionaryWords.value.split(" ");
|
||||
list2[i] = list2[i].replace(/(^\s*)|(\s*$)/g, "");
|
||||
if (list2[i] !== "") { //原来代码中,替换的内容为“list[i]”这个字符串,这明显是错误的,我们需要替换的是list[i]里的内容
|
||||
articleContent = articleContent.replace(new RegExp("<mark>"+list2[i]+"</mark>", "g"), list2[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
let articleContent = document.getElementById("article").innerHTML;
|
||||
articleContent = articleContent.replace(new RegExp('<span class="highlighted">',"gi"), "")
|
||||
articleContent = articleContent.replace(new RegExp("</span>","gi"), "");
|
||||
document.getElementById("article").innerHTML = articleContent;
|
||||
}
|
||||
|
||||
|
@ -97,6 +83,7 @@ function toggleHighlighting() {
|
|||
isHighlight = true;
|
||||
highLight();
|
||||
}
|
||||
localStorage.setItem('highlightChecked', isHighlight);
|
||||
}
|
||||
|
||||
showBtnHandler();
|
|
@ -9,7 +9,7 @@ var Reader = (function() {
|
|||
msg.rate = rate;
|
||||
msg.lang = "en-US";
|
||||
msg.onboundary = ev => {
|
||||
if (ev.name == "word") {
|
||||
if (ev.name === "word") {
|
||||
current_position = ev.charIndex;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ function familiar(theWord) {
|
|||
let new_freq = freq - 1;
|
||||
const allow_move = document.getElementById("move_dynamiclly").checked;
|
||||
if (allow_move) {
|
||||
|
||||
if (new_freq <= 0) {
|
||||
removeWord(theWord);
|
||||
} else {
|
||||
|
@ -114,7 +113,7 @@ function removeWord(word) {
|
|||
// 根据词频信息删除元素
|
||||
word = word.replace('&', '&');
|
||||
const element_to_remove = document.getElementById(`p_${word}`);
|
||||
if (element_to_remove != null) {
|
||||
if (element_to_remove !== null) {
|
||||
element_to_remove.remove();
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +128,7 @@ function renderWord(word) {
|
|||
for (const current of container.children) {
|
||||
const cur_word = parseWord(current);
|
||||
// 找到第一个词频比它小的元素,插入到这个元素前面
|
||||
if (compareWord(cur_word, word) == -1) {
|
||||
if (compareWord(cur_word, word) === -1) {
|
||||
container.insertBefore(new_element, current);
|
||||
inserted = true;
|
||||
break;
|
||||
|
@ -165,17 +164,32 @@ function elementFromString(string) {
|
|||
* 当first大于second时返回1
|
||||
*/
|
||||
function compareWord(first, second) {
|
||||
if (first.freq < second.freq) {
|
||||
return -1;
|
||||
if (first.freq !== second.freq) {
|
||||
return first.freq < second.freq ? -1 : 1;
|
||||
}
|
||||
if (first.freq > second.freq) {
|
||||
return 1;
|
||||
}
|
||||
if (first.word < second.word) {
|
||||
return -1;
|
||||
}
|
||||
if (first.word > second.word) {
|
||||
return 1;
|
||||
if (first.word !== second.word) {
|
||||
return first.word < second.word ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 生词csv导出 */
|
||||
function exportToCSV() {
|
||||
let csvContent = "data:text/csv;charset=utf-8,Word,Frequency\n";
|
||||
let rows = document.querySelectorAll(".new-word");
|
||||
|
||||
rows.forEach(row => {
|
||||
let word = row.querySelector("a.btn-light").innerText;
|
||||
let freq = row.querySelector("a[title]").innerText;
|
||||
csvContent += word + "," + freq + "\n";
|
||||
});
|
||||
|
||||
let encodedUri = encodeURI(csvContent);
|
||||
let link = document.createElement("a");
|
||||
link.setAttribute("href", encodedUri);
|
||||
link.setAttribute("download", "word_list.csv");
|
||||
document.body.appendChild(link);
|
||||
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
|
@ -34,9 +34,9 @@
|
|||
<div class="alert alert-success" role="alert">共有文章 <span class="badge bg-success"> {{ number_of_essays }} </span> 篇</div>
|
||||
<p>粘贴1篇文章 (English only)</p>
|
||||
<form method="post" action="/">
|
||||
<textarea name="content" rows="10" cols="120"></textarea><br/>
|
||||
<textarea name="content" id="article" rows="10" cols="120"></textarea><br/>
|
||||
<input type="submit" value="get文章中的词频"/>
|
||||
<input type="reset" value="清除"/>
|
||||
<input type="reset" value="清除" onclick="clearArticle()"/>
|
||||
</form>
|
||||
{% if d_len > 0 %}
|
||||
<p><b>最常见的词</b></p>
|
||||
|
@ -44,6 +44,7 @@
|
|||
<a href="http://youdao.com/w/eng/{{x[0]}}/#keyfrom=dict2.index">{{x[0]}}</a> {{x[1]}}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<p class="text-muted">Version: 20240618</p>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
|
||||
</div>
|
||||
{{ yml['footer'] | safe }}
|
||||
|
@ -52,5 +53,22 @@
|
|||
<script src="{{ js }}" ></script>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<script type="text/javascript">
|
||||
// IIFE, avoid polluting the global scope
|
||||
(function() {
|
||||
const articleInput = document.querySelector('#article');
|
||||
articleInput.value = localStorage.getItem('article') || '';
|
||||
|
||||
articleInput.addEventListener('input', function() {
|
||||
localStorage.setItem('article', articleInput.value);
|
||||
});
|
||||
|
||||
window.clearArticle = function() {
|
||||
localStorage.removeItem('article');
|
||||
articleInput.value = '';
|
||||
};
|
||||
})();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<!DOCTYPE html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
|
@ -28,21 +28,11 @@
|
|||
}
|
||||
|
||||
@keyframes shakes {
|
||||
10%, 90% {
|
||||
transform: translate3d(-1px, 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);
|
||||
}
|
||||
10%, 90% { transform: translate3d(-1px, 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); }
|
||||
}
|
||||
|
||||
.lead{
|
||||
|
@ -82,22 +72,13 @@
|
|||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<button class="arrow" id="load_next_article" onclick="load_next_article();Reader.stopRead()"
|
||||
title="下一篇 Next Article">⇨
|
||||
</button>
|
||||
<button class="arrow" id="load_pre_article" onclick="load_pre_article();Reader.stopRead()" style="display: none"
|
||||
title="上一篇 Previous Article">⇦
|
||||
</button>
|
||||
<button class="arrow" id="load_next_article" onclick="load_next_article();Reader.stopRead()" title="下一篇 Next Article">⇨</button>
|
||||
<button class="arrow" id="load_pre_article" onclick="load_pre_article();Reader.stopRead()" style="display: none" title="上一篇 Previous Article">⇦</button>
|
||||
|
||||
<p><b>阅读文章并回答问题</b></p>
|
||||
<div id="text-content">
|
||||
<div id="found">
|
||||
<div class="alert alert-success" role="alert">According to your word list, your level is <span
|
||||
class="text-decoration-underline" id="user_level">{{ today_article["user_level"] }}</span> and we
|
||||
have chosen an article with a difficulty level of <span class="text-decoration-underline"
|
||||
id="text_level">{{ today_article["text_level"] }}</span>
|
||||
for you.
|
||||
</div>
|
||||
<div class="alert alert-success" role="alert">According to your word list, your level is <span class="text-decoration-underline" id="user_level">{{ today_article["user_level"] }}</span> and we have chosen an article with a difficulty level of <span class="text-decoration-underline" id="text_level">{{ today_article["text_level"] }}</span> for you.</div>
|
||||
<p class="text-muted" id="date">Article added on: {{ today_article["date"] }}</p><br/>
|
||||
<div class="p-3 mb-2 bg-light text-dark" style="margin: 0 0.5%;"><br/>
|
||||
<p class="display-6" id="article_title">{{ today_article["article_title"] }}</p><br/>
|
||||
|
@ -117,13 +98,11 @@
|
|||
}
|
||||
</script>
|
||||
<button onclick="toggle_visibility('answer');">ANSWER</button>
|
||||
<div id="answer" style="display:none;">{{ today_article['answer'] }}</div>
|
||||
<br/>
|
||||
<div id="answer" style="display:none;">{{ today_article['answer'] }}</div><br/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-success" role="alert" id="not_found" style="display:none;">
|
||||
<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>
|
||||
<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>
|
||||
<div class="alert alert-success" role="alert" id="read_all" style="display:none;">
|
||||
<p class="text-muted"><span class="badge bg-success">Notes:</span><br>You've read all the articles.</p>
|
||||
|
@ -166,6 +145,8 @@
|
|||
允许动态调整顺序
|
||||
</label>
|
||||
</p>
|
||||
<!--添加导出按钮-->
|
||||
<button class="btn btn-primary" onclick="exportToCSV()">导出</button>
|
||||
<a name="aaa"></a>
|
||||
<div class="word-container">
|
||||
{% for x in lst3 %}
|
||||
|
@ -174,8 +155,7 @@
|
|||
{% 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'
|
||||
<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>
|
||||
|
@ -186,8 +166,10 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
<input id="selected-words2" type="hidden" value="{{ words }}">
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
<label id="selected-words3" type="hidden"></label>
|
||||
{{ yml['footer'] | safe }}
|
||||
{% if yml['js']['bottom'] %}
|
||||
{% for js in yml['js']['bottom'] %}
|
||||
|
@ -245,7 +227,6 @@
|
|||
|
||||
|
||||
function load_next_article(){
|
||||
$("#load_next_article").prop("disabled", true)
|
||||
$.ajax({
|
||||
url: '/get_next_article/{{username}}',
|
||||
dataType: 'json',
|
||||
|
@ -256,12 +237,9 @@
|
|||
check_pre(data['visited_articles']);
|
||||
check_next(data['result_of_generate_article']);
|
||||
}
|
||||
}, complete: function (xhr, status) {
|
||||
$("#load_next_article").prop("disabled", false)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function load_pre_article(){
|
||||
$.ajax({
|
||||
url: '/get_pre_article/{{username}}',
|
||||
|
@ -275,7 +253,6 @@
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
function update(today_article){
|
||||
$('#user_level').html(today_article['user_level']);
|
||||
$('#text_level').html(today_article["text_level"]);
|
||||
|
@ -286,15 +263,10 @@
|
|||
$('#question').html(today_article["question"]);
|
||||
$('#answer').html(today_article["answer"]);
|
||||
document.querySelector('#text_level').classList.add('mark'); // highlight text difficult level for 2 seconds
|
||||
setTimeout(() => {
|
||||
document.querySelector('#text_level').classList.remove('mark');
|
||||
}, 2000);
|
||||
setTimeout(() => {document.querySelector('#text_level').classList.remove('mark');}, 2000);
|
||||
document.querySelector('#user_level').classList.add('mark'); // do the same thing for user difficulty level
|
||||
setTimeout(() => {
|
||||
document.querySelector('#user_level').classList.remove('mark');
|
||||
}, 2000);
|
||||
setTimeout(() => {document.querySelector('#user_level').classList.remove('mark');}, 2000);
|
||||
}
|
||||
|
||||
<!-- 检查是否存在上一篇或下一篇,不存在则对应按钮隐藏-->
|
||||
function check_pre(visited_articles){
|
||||
if((visited_articles=='')||(visited_articles['index']<=0)){
|
||||
|
@ -305,11 +277,9 @@
|
|||
sessionStorage.setItem('pre_page_button', 'show')
|
||||
}
|
||||
}
|
||||
|
||||
function check_next(result_of_generate_article){
|
||||
if(result_of_generate_article == "found"){
|
||||
$('#found').show();
|
||||
$('#not_found').hide();
|
||||
$('#found').show();$('#not_found').hide();
|
||||
$('#read_all').hide();
|
||||
}else if(result_of_generate_article == "not found"){
|
||||
$('#found').hide();
|
||||
|
@ -325,7 +295,7 @@
|
|||
</body>
|
||||
<style>
|
||||
mark {
|
||||
color: #{{ yml['highlight']['color'] }};
|
||||
color: red;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue