1
0
Fork 0

Compare commits

..

2 Commits

Author SHA1 Message Date
熊佳明 0181dc4131 Fix bug 540 2024-05-26 20:41:16 +08:00
熊佳明 175e086a78 Fix bug 540 2024-05-20 20:53:14 +08:00
7 changed files with 142 additions and 115 deletions

View File

@ -1,3 +1,4 @@
// initialize from localStorage
let isRead = localStorage.getItem('readChecked') !== 'false'; // default to true let isRead = localStorage.getItem('readChecked') !== 'false'; // default to true
let isChoose = localStorage.getItem('chooseChecked') !== 'false'; let isChoose = localStorage.getItem('chooseChecked') !== 'false';
@ -8,15 +9,8 @@ function getWord() {
function fillInWord() { function fillInWord() {
let word = getWord(); let word = getWord();
if (isRead) Reader.read(word, inputSlider.value); if (isRead) Reader.read(word, inputSlider.value);
if (!isChoose) { if (!isChoose) return;
if(isHighlight){
const element = document.getElementById("selected-words3");
element.value = element.value + " " + word;
}
return;
}
const element = document.getElementById("selected-words"); const element = document.getElementById("selected-words");
localStorage.setItem('nowWords', element.value);
element.value = element.value + " " + word; element.value = element.value + " " + word;
localStorage.setItem('selectedWords', element.value); localStorage.setItem('selectedWords', element.value);
} }
@ -44,4 +38,3 @@ function onChooseClick() {
if (performance.getEntriesByType("navigation")[0].type == "reload") { if (performance.getEntriesByType("navigation")[0].type == "reload") {
Reader.stopRead(); Reader.stopRead();
} }

View File

@ -22,48 +22,39 @@ function getWord() {
function highLight() { function highLight() {
if (!isHighlight) return; if (!isHighlight) return;
let word = (getWord() + "").trim();
let articleContent = document.getElementById("article").innerHTML; // innerHTML保留HTML标签来保持部分格式且适配不同的浏览器 let articleContent = document.getElementById("article").innerHTML; // innerHTML保留HTML标签来保持部分格式且适配不同的浏览器
let pickedWords = document.getElementById("selected-words"); // words picked to the text area 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 dictionaryWords = document.getElementById("selected-words2"); // words appearing in the user's new words list
let allWords = dictionaryWords === null ? pickedWords.value + " " : 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中 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;
}
}
let totalSet = new Set(); let totalSet = new Set();
for (let i = 0; i < list.length; ++i) { for (let i = 0; i < list.length; ++i) {
list[i] = list[i].replace(/(^\W*)|(\W*$)/g, ""); // 消除单词两边的非单词字符 list[i] = list[i].replace(/(^\W*)|(\W*$)/g, ""); // 消除单词两边的非单词字符
list[i] = list[i].replace('|', "");
list[i] = list[i].replace('?', "");
if (list[i] != "" && !totalSet.has(list[i])) { if (list[i] != "" && !totalSet.has(list[i])) {
// 返回所有匹配单词的集合, 正则表达式RegExp()中, "\b"匹配一个单词的边界, g 表示全局匹配, i 表示对大小写不敏感。 // 返回所有匹配单词的集合, 正则表达式RegExp()中, "\b"匹配一个单词的边界, g 表示全局匹配, i 表示对大小写不敏感。
let matches = new Set(articleContent.match(new RegExp("\\b" + list[i] + "\\b", "gi"))); let matches = new Set(articleContent.match(new RegExp("\\b" + list[i] + "\\b", "gi")));
if (matches.has("mark")) {
// 优先处理单词为 "mark" 的情况
totalSet = new Set(["mark", ...totalSet]);
}
totalSet = new Set([...totalSet, ...matches]); totalSet = new Set([...totalSet, ...matches]);
} }
} }
// 删除所有的"<span class='highlighted'>"标签,防止标签发生嵌套 // 删除所有的mark标签,防止标签发生嵌套
articleContent = articleContent.replace(new RegExp('<span class="highlighted">',"gi"), "") articleContent = articleContent.replace(/<(mark)[^>]*>/gi, "");
articleContent = articleContent.replace(new RegExp("</span>","gi"), ""); articleContent = articleContent.replace(/<(\/mark)[^>]*>/gi, "");
// 将文章中所有出现该单词word的地方改为"<span class='highlighted'>" + word + "</span>"。 // 将文章中所有出现该单词word的地方改为"<span class='highlighted'>" + word + "</span>"。
for (let word of totalSet) { for (let word of totalSet) {
articleContent = articleContent.replace(new RegExp("\\b" + word + "\\b", "g"), "<span class='highlighted'>" + word + "</span>"); articleContent = articleContent.replace(new RegExp("\\b" + word + "\\b", "g"), "<span class='highlighted'>" + word + "</span>");
} }
document.getElementById("article").innerHTML = articleContent; document.getElementById("article").innerHTML = articleContent;
} }
function cancelHighlighting() { function cancelHighlighting() {
let articleContent = document.getElementById("article").innerHTML; let articleContent = document.getElementById("article").innerHTML;
articleContent = articleContent.replace(new RegExp('<span class="highlighted">',"gi"), "") articleContent = articleContent.replace(/<(mark)[^>]*>/gi, "");
articleContent = articleContent.replace(new RegExp("</span>","gi"), ""); articleContent = articleContent.replace(/<(\/mark)[^>]*>/gi, "");
document.getElementById("article").innerHTML = articleContent; document.getElementById("article").innerHTML = articleContent;
} }

View File

@ -112,6 +112,11 @@
<input type="checkbox" id="highlightCheckbox" onclick="toggleHighlighting()" />生词高亮 <input type="checkbox" id="highlightCheckbox" onclick="toggleHighlighting()" />生词高亮
<input type="checkbox" id="readCheckbox" onclick="onReadClick()" />大声朗读 <input type="checkbox" id="readCheckbox" onclick="onReadClick()" />大声朗读
<input type="checkbox" id="chooseCheckbox" onclick="onChooseClick()" />划词入库 <input type="checkbox" id="chooseCheckbox" onclick="onChooseClick()" />划词入库
<button onclick="saveArticle()" class="btn btn-primary">标记文章</button>
<select id="saved_articles_dropdown" style="height: 50px">
<!-- 这里将显示已经保存的文章 -->
<option></option>
</select>
<div class="range"> <div class="range">
<div class="field"> <div class="field">
<div class="sliderValue"> <div class="sliderValue">
@ -166,7 +171,6 @@
<input id="selected-words2" type="hidden" value="{{ words }}"> <input id="selected-words2" type="hidden" value="{{ words }}">
{% endif %} {% endif %}
</div> </div>
<label id="selected-words3" type="hidden"></label>
{{ yml['footer'] | safe }} {{ yml['footer'] | safe }}
{% if yml['js']['bottom'] %} {% if yml['js']['bottom'] %}
{% for js in yml['js']['bottom'] %} {% for js in yml['js']['bottom'] %}
@ -287,12 +291,89 @@
$('#not_found').hide(); $('#not_found').hide();
$('#read_all').show(); $('#read_all').show();
} }
}
function saveArticle() {
const article = {
user_level: document.getElementById('user_level').innerText,
text_level: document.getElementById('text_level').innerText,
date: document.getElementById('date').innerText.replace('Article added on: ', ''),
article_title: document.getElementById('article_title').innerText,
article_body: document.getElementById('article').innerText,
source: document.getElementById('source').innerText,
question: document.getElementById('question').innerText,
answer: document.getElementById('answer').innerText
};
const articleJSON = JSON.stringify(article);
const articleTitle = article.article_title;
const savedArticlesDropdown = document.getElementById('saved_articles_dropdown');
var option = document.createElement('option');
option.text = articleTitle;
option.value = articleJSON; // 存储序列化的JSON字符串
option.title = article.article_title;
savedArticlesDropdown.appendChild(option);
localStorage.setItem(articleTitle, articleJSON); // 以文章标题为键序列化的JSON字符串为值存储
alert("文章已标记");
}
function loadSelectedArticle() {
const selectedOption = document.getElementById('saved_articles_dropdown');
const selectedTitle = selectedOption.options[selectedOption.selectedIndex].text;
const articleJSON = localStorage.getItem(selectedTitle);
if (articleJSON) {
const today_article = JSON.parse(articleJSON); // 解析JSON字符串为对象
update(today_article); // 使用解析出的对象更新页面
}
}
window.onload = function() {
const savedArticlesDropdown = document.getElementById('saved_articles_dropdown');
savedArticlesDropdown.addEventListener('change', loadSelectedArticle);
// 先清空dropdown以防有多余的选项或重新加载页面时出现重复
savedArticlesDropdown.innerHTML = '';
// 获取localStorage中最后一个最新的键值对
let latestKey, latestValue;
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
const value = localStorage.getItem(key);
if (!latestKey) { // 第一次迭代时设置最新文章
latestKey = key;
latestValue = value;
}
}
// 首先添加最新保存的文章到下拉菜单
if (latestKey && latestValue) {
var latestOption = document.createElement('option');
latestOption.text = latestKey;
latestOption.value = latestValue;
latestOption.title = latestValue;
savedArticlesDropdown.appendChild(latestOption);
}
// 接着遍历其余文章并添加到下拉菜单
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
const value = localStorage.getItem(key);
// 确保不重复添加最新文章
if (key !== latestKey) {
var option = document.createElement('option');
option.text = key;
option.value = value;
option.title = value;
savedArticlesDropdown.appendChild(option);
}
}
savedArticlesDropdown.selectedIndex = -1;
} }
</script> </script>
</body> </body>
<style> <style>
mark { mark {
color: red; color: #{{ yml['highlight']['color'] }};
background-color: rgba(0, 0, 0, 0); background-color: rgba(0, 0, 0, 0);
} }
</style> </style>

View File

@ -0,0 +1,47 @@
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import logging
from helper import signup
def login(driver, home, uname, password):
driver.get(home)
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.LINK_TEXT, '登录'))).click()
driver.find_element(By.ID, 'username').send_keys(uname)
driver.find_element(By.ID, 'password').send_keys(password)
driver.find_element(By.XPATH, '//button[text()="登录"]').click()
WebDriverWait(driver, 10).until(EC.title_is(f"EnglishPal Study Room for {uname}"))
def logout(driver):
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.LINK_TEXT, '退出'))).click()
# 标记文章
def collect_article(driver):
driver.find_element(By.XPATH, '//button[text()="标记文章"]').click()
def test_collect_article(driver, URL):
try:
username, password = signup(URL, driver)
title = driver.find_element(By.ID, 'article_title').text
article = driver.find_element(By.ID, 'article').text
collect_article(driver)
collected_title = driver.execute_script('return localStorage.getItem("articleTitle");')
assert title == collected_title, "Unable to add the article to your collection."
# 退出登录
logout(driver)
# 再次登录并检查收藏状态
login(driver, URL, username, password)
rechecked_title = driver.execute_script('return localStorage.getItem("articleTitle");')
assert title == rechecked_title, "Collected article not found after re-login."
except Exception as e:
# 输出异常信息
logging.error(e)
# 关闭浏览器
driver.quit()
finally:
driver.quit()

View File

@ -1,7 +1,5 @@
import random import random
import string import string
import time
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support import expected_conditions as EC

View File

@ -1,44 +0,0 @@
import random
import string
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from helper import signup
def has_punctuation(s):
return any(c in string.punctuation for c in s)
def select_one(driver):
elem = driver.find_element(By.ID, 'article')
essay_content = elem.text
valid_word = random.choice([word for word in essay_content.split() if len(word) >= 6 and not has_punctuation(
word) and 'font>' not in word and 'br>' not in word and 'p>' not in word])
driver.find_element(By.ID, 'selected-words').send_keys(valid_word)
driver.find_element(By.ID, 'article').click()
return valid_word
def select_two(driver):
word = driver.find_element(By.CLASS_NAME, 'highlighted')
# 创建ActionChains对象
actions = ActionChains(driver)
actions.move_to_element(word)
# 模拟鼠标按下并拖动以选择文本
actions.double_click()
actions.perform()
def test_selected_second_word(driver, URL):
try:
signup(URL, driver)
selected_words = select_one(driver);
assert selected_words.strip() != "", "选中的单词被放置框中"
select_two(driver)
selected_second_words = driver.find_element(By.ID, 'selected-words').get_attribute('value')
assert selected_second_words.strip() == "", "选中的单词被删除"
finally:
driver.quit()

View File

@ -1,39 +0,0 @@
from selenium.webdriver.common.action_chains import ActionChains
from helper import signup
def test_highlight(driver, URL):
try:
# 打开网页
driver.get(URL)
driver.maximize_window()
# 注册
signup(URL, driver)
# 取消勾选“划词入库按钮”
highlight_checkbox = driver.find_element_by_id("chooseCheckbox")
driver.execute_script("arguments[0].click();", highlight_checkbox)
article = driver.find_element_by_id("article")
# 创建 ActionChains 对象
actions = ActionChains(driver)
# 移动鼠标到起点位置
actions.move_to_element(article)
# actions.move_to_element_with_offset(article, 50, 100)
# 按下鼠标左键
actions.click_and_hold()
# 拖动鼠标到结束位置
actions.move_by_offset(400,50)
# 释放鼠标左键
actions.release()
# 执行操作链
actions.perform()
# time.sleep(10)
assert driver.find_elements_by_class_name("highlighted") is not None
finally:
# 测试结束后关闭浏览器
driver.quit()