MarkIt 荧光笔
这是一个 Chrome 扩展链接,可让您突出显示任何网页上的重要文本。在 1 分钟、1 周或 1 年内重新访问该页面 - 您的数据将始终存在。
技术
- (原版)JavaScript
- 谷歌应用程序编程接口
特征
- 突出显示任何文本并按 Command+K 自动保存
- 用户可以通过一个简单的命令(Command+Shift+A)清除任何 URL 的存储突出显示
- 在所有设备上同步 - 如果您在笔记本电脑上突出显示文本,然后在手机上查看同一网页,您的突出显示就会在那里(如果您在两台设备上都登录了 Chrome)。
我存储的数据结构(对象)
highlights = {
google.com: {
text1: ["query selector", index, note, color]
text2: ["query selector", index, note, color]
},
yahoo.com: {
text3: ["query selector", index, note, color],
text4: ["query selector", index, note, color]
},
https://developer.mozilla.org/en-US/docs/Web/API/document/execCommand: {
"When an HTML document has been switched to designMode, its document object exposes an execCommand": ["p.summary", 20],
"A DOMString specifying the name of the command to execute. See Commands for a list of possible commands.": ["p", 0, "example note", #CFFFDF]
}
}
它是如何运作的
我有两个脚本加载在每个页面上。第一个是background.js,它监听特定事件。 Command+K 事件触发一个函数,将脚本注入浏览器 (injection_script.js),突出显示所选文本。
要突出显示,请将鼠标拖动到某些文本上,然后按 Command+K。这会触发一个调用其他几个函数的函数。事件顺序:
- 抓取选定的文本
- “打开”设计模式,允许我们对 DOM 进行临时更改
- 如果背景已经突出显示,那么我们需要删除突出显示:
- 选择文本周围的<span>标签并设置style.backgroundColor=透明(移除突出显示)
- 从存储中获取“亮点”对象 -
chrome.storage.get()
- 循环遍历所有键(即保存的突出显示)以查找匹配项,并将其从存储中删除
- 否则,将文本包裹在 <span> 中并应用背景颜色
- 页面刷新时:从存储中检索“亮点”
- 如果活动 URL 没有数据,则将键设置为当前 URL,将值设置为空对象 (aol.com: {})
- 如果有,从存储中获取高亮数据结构(chrome.storage.get())
- 为所选文本检索并分配有效的查询选择器值(这将用于查询 DOM 并稍后应用突出显示。请参阅上面的对象结构以进行说明)
- 如果突出显示文本的父元素有类名,则存储字符串“element.className”(“p.firstParagraph”、“h2.sectionHeader”等)
- 如果没有类名,则存储字符串“element”(“p”、“h2”、“li”等)
- 为键(突出显示的文本)提供一个值(包含 2 个值的数组 - 第一个是查询选择器,第二个是所选文本在父元素中出现的位置的索引)
- 我存储字符串的索引,因为如果我只存储文本和查询选择器,假设您在“p”标签下突出显示了“the”,那么在刷新页面时应用突出显示时,“the”的每次出现都会在“p”标签下突出显示。 “p”标签将突出显示。添加 indexOf 值可以让我验证索引是否与 DOM 匹配,然后才应用突出显示,因此我将突出显示应用到正确的单词。
- 使用 chrome.storage.set() 存储包含新突出显示文本的更新后的突出显示变量
- “关闭”设计模式
每个页面上运行的第二个 JavaScript 文件是 content_script.js。它检查是否存在名为“highlights”的存储对象。如果没有,则意味着用户从未突出显示任何内容。然后它创建一个空对象并将其存储在 Chrome 中。
如果它找到“突出显示”对象,则会检查是否存储了活动 URL 的数据。如果不存在,脚本将返回。
如果该 URL 存储了突出显示:
- applyHighlights() 函数运行
- 它需要两个参数,“highlights”对象和活动 URL
- 循环访问存储对象的键(键是存储的突出显示,而这些键的值是包含 querySelector 和 indexOf 值的数组)
- 运行 document.body.querySelectorAll() 以获取所有匹配节点的数组
- 循环遍历每个返回的节点,如果innerHTML包含与对象键(突出显示的文本)匹配的“字符串”并且具有相同的indexOf值: 1. 运行 .replace() 函数,将匹配的文本包装在 <span> 标记中,并使用背景颜色的内联样式属性
- 旁注:我最初递归地遍历每个 DOM 节点来检查匹配项,但存储 querySelector 值并将仅匹配节点的 HTML 值与我存储的值进行比较要快得多。
下一版本的升级
- 存储您突出显示的特定字符串
- “从 jQuery.com 下载 jQuery 库”。
- 如果突出显示第二个“jQuery”,则存储的值将是第一个实例的值。
- 这是因为我存储的 indexOf 值在第一个匹配后返回
- PLAN - 开始计算跨度标签后的索引
- 无法跨块元素突出显示(如果将突出显示从 h2 拖到 ap 标记中,则只有 h2 会注册)
- 进行中:允许用户选择突出显示颜色
- 在扩展 popup.html 中显示页面的突出显示数量和实际突出显示数量
- 限制/边缘情况:电子邮件、PDF
- 我请求每个网站的权限。有些网站阻止“*”访问 (cnn.com)
- 如果您在一个元素中突出显示“jQuery”,则在另一个元素中再次突出显示它,第二个元素将覆盖第一个元素(因为键相同)
- 如果父元素是内联标签,则innertext/html indexOf不会注册(-1),或者它在内联标签末尾结束突出显示找到span标签的索引并在那里开始indexOf
- 折叠模式 - 将文档折叠到仅存储突出显示的父元素
已解决的问题
- 存储跨越内联元素标签(a、em、st 等)的突出显示
- 之前,只保存了内联标签之前的文本,因为我存储了innerText
- 我通过存储innerHTML 解决了这个问题
- 此更改引起的问题是我存储了innerText的indexOf,这会将突出显示重新应用到文本元素内的标准文本,例如“p”标签。但是对于内联元素周围的项目,indexOf 是不同的,因为indexOf 计算标签中的每个字符。
- 为了解决这个问题,我比较了innerText.indexOf 和innerHTML.indexOf 值,并在将突出显示应用于用户再次访问的页面时将每个值与匹配节点进行比较。
- 如果您双击以突出显示某个部分,则 indexOf 值将不会注册,因此我的应用程序无法重新应用突出显示
- 为了解决这个问题,我将 .toString() 和 .trim() 方法添加到 indexOf(...)
- 突出显示 < a > 标记将删除页面加载时的链接。
未来的升级
## 示例图像
边缘情况
- 如果类名改变
- 解决方案:如果类名在DOM中不存在,则从查询选择器中去掉类名,只搜索元素标签节点
- 如果内容被按钮隐藏,我的突出显示将不会注册,因为它会搜索 on_load 并且内容仅在浏览器事件后显示(这就是它不适用于电子邮件的原因)
允许某人访问 popup.html 上的所有突出显示 允许用户更改突出显示颜色 修复内联元素突出显示错误