在Chrome 扩展中使用 Handlebars

Chrome 扩展中无法直接使用 Handlebars,最好使用预编译功能在开发环境中将模板处理好然后直接使用。

Chrome 扩展可以访问到各种用户敏感数据,比如 cookie 之类,所以 Chrome 团队对它的限制非常严格(见 Using eval in Chrome Extensions. Safely.),比如常规环境下完全不能使用 evalnew Function()。这给我们使用 Handlebars 之类的模板工具带来不小的麻烦。

一个解决方案就是使用上文中介绍的 sandbox。将可能使用到 eval 的代码放到一个独立沙盒中,不让它访问到那些敏感信息;然后通过 postMessage API 与之进行数据通讯,完成模板生成工作。

我觉得这个方案不太理想。首先我不喜欢 <iframe>;其次每次渲染模板还要 post 来 post 去,渲染结果也是异步传递(这点暂时存疑)。

另一套方案,则是利用 Handlebars 的预编译功能,将模板在开发环境中编译成函数,在扩展中直接使用。这样做的好处也很明显,因为发布插件时也会先处理代码,这个时候将模板处理完,工作效率更高。

等写完再补充具体代码吧。

Chrome表单验证和keyup导致的灵异问题

chrome的表单验证在keydown之后触发,可能会导致依赖keyup事件的一些东西出问题。

先说下环境,Mac OS El Capitan + Chrome 46,框架是Backbone + Boostrap。

我做了一个自动搜索组件,独立测试时一切正常,放到产品中,别的都没问题,只有回车会出问题。代码在这里

不用说,这个问题很诡异,调试了半天没有头绪,只能通过观察现象去推测:

  1. 没有报错
  2. 除了回车,其它功能正常
  3. 除了回车,keyUpHandler都能被正确触发
  4. 回车后,光标跳到其它元素

看来看去,第4条最可疑——我按的是回车,它会什么会跳到别的单元格呢?

这次运气比较好,表单中的接下来的几个元素刚好是日期,用到Bootstrap Datetimepicker这个插件,focus之后会自动填充日期。于是我发现,每次跳到的“其它元素”,都是原先空白的,而且是required的;不会跳到固定的,或者紧挨着的那个文本框。

于是我便想,会不会是:

  1. 表单submitkeydown之后触发
  2. 触发之后进行表单验证,发现有未填的required元素,于是跳到该元素并提示
  3. Bootstrap Datetimepicker响应focus时间,填入日期,提示消失
  4. 我的Typeahead响应blur事件,隐藏列表
  5. keyup事件触发,但是输入框已没有焦点,就没有触发

这个推测看起来有点道理,于是我把侦听的事件改成keydown,问题果然解决。

一个诡异问题的排查

这个问题本身其实不能称之为问题,记下来只是我觉得排查经历挺典型的,值得分享。

这个问题本身其实不能称之为问题,记下来只是我觉得排查经历挺典型的,值得分享。

先说下我的环境:MacOS 10.8.2 + Chrome 23.x + Bootstrap 2.2.1 + jQuery 1.8.2。事情是这样的,我本来在开发一个新功能,顺便把老页面重构一下,貌似一切正常。重构完毕后,我想随手测试一下重构后的页面,发现下拉菜单竟然不能点击了,或者说,点击完全失效了。

这让我很恐慌,因为类似的重构过程我近段时间来做的不是一次两次,这次我应该没有任何冒险的改动才是。这种情况下出现的Bug,一般都很棘手。于是,我打开以前的某个页面——同样经历了重构,但是通过了测试,并且在一顿时间的使用中完全没有问题——发现里面的下拉菜单同样点击失效了。于是,真正的排查开始了。

继续阅读“一个诡异问题的排查”

诡异的Chrome插件事件机制

Chrome插件在content script里使用JQ广播事件,可能会无法在页面里侦听。换做原生的就没有问题。

最近尝试开发Chrome插件,自然使用JQ来当基础。结果遇到一个问题:

我使用“程序注入(Programmatic injection)”的方式执行代码,试图实现自动填写表单的功能。因为目标网页的表单比较智能,前面的选项会影响后面选项的内容,所以必须在val(value)之后广播change事件来触发后面表单内容的填充。

结果失败了。直接在浏览器里使用控制台运行代码,没有问题,所以代码本身应该正确;确认需要的JS文件已经一一加载。于是我开始了漫长而挫折的调试之路。多次失败之后,我打开《英雄无敌三》换换心情……玩了一会儿游戏意外退出了,而我灵机一动,会不会是JQ广播事件的问题?在控制台调试没有问题,但是在content script里就不行,很可能是chrome把两段代码放在彼此隔离的环境中运行导致的。于是我放弃直接$(selector).change(),改用原生的dispatchEvent,结果,运行成功!

于是我猜,应该是JQ和Chrome的插件机制稍有冲突。可能以后做插件的话,还是Closure Library好些吧。

PS:写插件的好处是不用考虑兼容性,朝着Chrome写就行了。

Google新产品风格滚动条的实现方法

让页面当中的滚动条使用Google产品风格

Google全线产品改版后,褒贬不一。不过它们滚动条看起来很漂亮,简单好看,有点Ubuntu的感觉。

不过实现起来并不复杂,研究之后,发现是这样定义CSS的:

::-webkit-scrollbar{
  width:6px;
}
::-webkit-scrollbar-track-piece{
  background:none;
}
::-webkit-scrollbar-thumb {
  background:#DCD9DE;
  border-radius:6px;
}
::-webkit-scrollbar-thumb:hover {
  background:#EAE6EA;
}

当然,看到”-webkit“,自然只有webkit内核的浏览器比如Chrome才生效(我没有测试Safari)。具体支持哪些样式暂时还不确定,Google搜索“-webkit-scrollbar”竟然没有结果。已知background、border这些都没问题,:hover这样的伪类也支持,margin、padding似乎没有作用。以后再慢慢研究吧。