我如何摆脱一千个标签...

...而且晚了3年。理想情况下,应该是这样的:用户启动浏览器,浏览器显示用户的需求。但是,尽管未实现,但您必须使用搜索引擎。理想情况下,应该是这样的:用户打开搜索引擎,输入搜索查询,并显示用户的需求。但是,尽管“我感到很幸运”按钮不能很好地工作(尽管最近在该方向上出现了明显的变化),但有时您必须从搜索结果页面转到几个地址。

显然,使用搜索引擎的场景在历史上是固定的(当互联网很慢时):进入搜索结果页面,我在后台打开了几个选项卡,而其余的在加载时,已经可以读取第一个选项卡了。如果我在其中一个标签上找到了必要的信息,则其余的必须手动关闭。如果它没有立即关闭,则选项卡将保持挂起状态,从而增加浏览器中打开的选项卡的数量,通常,此后很少打开。

此外,如果单击带有在新窗口中打开的链接的页面,则会创建几个(逻辑上)选项卡式的选项卡。找到所需信息后,您将永远无法记住已连接的标签页,也无法关闭所有内容,这还会导致打开的标签页数量激增。

我一直需要“找到”按钮,该按钮会在我之后清除搜索的结果(我们称其为“我很幸运”)。进入浏览器扩展世界后,我认为在这种情况下这可能会有所帮助。因此,开始变得朦胧地开始想要编写可以解决我的问题的扩展程序。

我会告诉你我的故事,我将按时间顺序带领故事,结论可能出乎意料。

迈向的第一步


我要做的第一件事是建立基础架构:webpack + babel现在,我不喜欢babel在每个模块中为其助手提供重复的代码。可以将其配置为使用该对象babelHelper,但是随后babelHelper需要在webpack配置中连接代码文件将这样的文件保存在项目中并指向它entry很丑陋,我为webpack制作了一个插件,该插件可以自动为我完成此任务。在第一步上花费了大量的精力并为扩展本身编写了更多代码之后,我放慢了速度。

插入

基础


时间流逝,只有webpack的插件可用,但不能以任何方式解决我的问题。每次我搜索某项内容但没有关闭标签时,都会有一个想法:“完成扩展很高兴……”欲望越来越大,如今,一天,质量就变成了质量。

现在该说说主要思想了:
用户进入搜索结果页面-SICKLE,我们解析搜索结果,保存自己的链接地址,当用户单击其中一个地址后,向他显示带有其他地址和“ Found”按钮的通知关闭标签页。

当您转到页面时,可能会有多种选择。最简单:一个请求-来自服务器的一个响应(200最困难的是:一个请求-多个服务器重定向(3xx),然后是客户端重定向(使用<meta/>或javascript),历史记录API也位于最上方而且,它们之间的组合通常是大多数网站的类别。

简单过渡案例:

简单过渡的情况(答案200)

复杂的过渡案例:

复杂的过渡案例(3xx +客户端重定向)

也就是说,保存页面地址并仅对其进行检查并不总是足够的。因此,您需要创建一个逻辑转换,在其中记录路径上遇到的所有地址,然后检查逻辑转换是否包含存储的地址。任务很明确,但是并不是所有的事情都那么直接执行。

在Chrome中,有两个与导航相关的API:webNavigationwebRequest-每个都有自己的事件。前者-连接转换和浏览器UI,后者-基础网络请求。因此,如果页面的地址更改是由于历史记录API引起的,则后者不会发生任何事件,并且如果在网络请求期间发生重定向,则前者根本不会报告它。因此,有必要使用两个API,从每个API的每个事件中收集少量信息,以形成一个逻辑转换。

一些细节
, webNavigation (wN) :

onBeforeNavigate -> onCommitted -> onDOMContentLoaded -> onCompleted

webRequest (wR):

onBeforeRequest -> [onBeforeRedirect -> onBeforeRequest]* -> onCompleted | onErrorOccurred

wR wN ( ), .. - wN.onBeforeNavigate wR.onBeforeRequest, - . .

, , .

发展历程


...让我们回到数量增长为质量的时刻。从开发开始到现在已经花费了大量时间:浏览器开始支持es6模块shadow DOM和其他现代功能。为了构建项目,我转到了Rollup,这一次我不必编写插件。建立基础-能够在任何选项卡中获取有关任何过渡的信息的能力之后,仍然需要实施解析支持的SICKLES并在相关页面上显示通知的逻辑。

第一个任务是非常原始的:我们知道SICKLE的地址,使用内容脚本进入页面内容,获取我们感兴趣的数据,保存它,等待用户转到其中一个页面向他显示其他页面的通知。

对于第二项任务,您需要实现通知本身,即在页面上向用户显示的内容。在这里,内容脚本也无法做到。

最初,只有一个处理程序(也称为控制器)负责用户与搜索引擎的交互过程中的逻辑。然后这个想法出现了,为什么当用户只是单击在新选项卡中打开的链接时,为什么不在相关选项卡上显示通知。我不得不重做逻辑,使其更具通用性。类似于中间件React / Redux,您可以连接多个Transition处理程序,将来它们将使您能够实现在扩展程序设置中禁用/启用各种处理程序的功能。

隐私


由于通知是屏幕底部的面板,并且已添加到页面布局,因此页面上的脚本可以使用与该页面上任何其他元素相同的方式访问此元素。也就是说,从理论上讲,该页面可以找出您使用了哪个搜索查询,在哪个搜索引擎中以及向您提供了哪些其他页面,这不是很好。

一种称为影子DOM的技术可以解决。不建议closed mode在创建时在网络使用它shadowRoot,因为它意义不大(shadowRoot如果要以编程方式访问它,您仍然必须将指向元素的链接存储在某个位置;您还可以重新定义attachShadow创建函数shadowRoot在打开模式下,重新定义后加载的脚本将已经使用该函数的新版本。

对于扩展,情况并非如此。内容脚本和页面脚本生活在平行世界中。页面中的脚本无权访问内容脚本中定义的对象,而内容脚本以对象的DOM功能的本机实现运行(页面中脚本的重写功能对内容脚本所使用的功能没有影响)。结合这两个条件,我们看到可以shadowRoot通过将链接存储在变量中来创建带有私有元素的元素

在这种情况下,页面中的脚本将只能访问wrapper元素,该元素将为空。他将无法接收请求的文本或建议的页面。必须注意不要在通知中提供任何链接到生成的事件中的任何元素或纯文本。因此,在扩展名中,生成的id用于事件中,并且后台脚本已经可以理解该id对它的要求。对于页面,此ID毫无意义。

翻译困难


最初,该扩展程序仅针对Google Chrome开发,但是由于WebExtensions API的存在,我脑海中的某个地方仍然能够移植到其他浏览器。webextension-polyfill的存在激发了人们的信心。但是,无论如何。此扩展程序的polyphil仅带来了使用带有承诺的chrome API的功能。

Firefox已成为今年的令人失望的一年。事实证明Firefox chrome API不匹配(错误1543647错误1595621)对于扩展程序的正常运行至关重要,我们可以说它在此浏览器中不起作用(如预期的那样)。

维瓦尔第(Vivaldi)是最接近的,但也不是没有成本的。事件wN.onCreatedNavigationTarget当用户使用鼠标中键或通过Shift|Ctrl+鼠标左键而不是chrome API中wN.onCommitted transitionType == 'start_page'包含的event 而不是event)来打开链接时,就不会发生这种情况,因此,并非在所有情况下,扩展程序都可以正常工作。同样在Vivaldi中,扩展功能热键不起作用。在这种情况下,Chrome的杀手级功能是什么,它使您可以快速浏览选项卡并关闭它们,而无需使用鼠标。

结论


在编写代码期间,用于显示通知的逻辑发生了多次更改,每次都简化了。结果,事实证明,可能不是用逻辑转换来围堵花园,而是捕捉用户的“相关转换”(如果wN.onCommitted有一个标志transitionType指示转换的目的,在许多情况下是“链接”,这意味着用户切换了通过引用),这将大大简化代码并在许多情况下(但并非在所有情况下)都可以工作。

另外,不在主题之内,我期望在webExtensions API方面具有更多的兼容性与往常一样,当您不需要对旧版本的支持时,生活在现代浏览器中是件好事。CSS动画是一件很了不起的事情:您过去使用js库的目的现在已经在CSS的几行中完成了。自定义元素在扩展中不起作用,但是影子DOM起作用,从而允许您利用其所有功能。

扩张
chrome web store: Handy Search

Source: https://habr.com/ru/post/undefined/


All Articles