安全沙箱加载 javascript 畅想与实现

从一个经典的跨域脚本应用说起:

JSONP 是一个流行的跨域获取数据的方案,它原理是向文档动态插入一个 script 标签,向远程服务器发起一个脚本请求,然后远程服务器返回一个定的回调函数并传入 JSON 数据,这样完成跨域数据交换。

如页面预先定义一个全局函数:

window.jsonp534533 = function (json) {
       //...
}

向服务器发起 script 请求 JSONP

http://api.douban.com/jsonp?key=3435&type=music&callback=jsonp534533

服务器返回 js 文件

jsonp534533({
    "code": 0
    "data": [...]
})

JSONP 虽然很方便实现前端跨域,但是其弊端也是显而易见的:无法保证安全性。

由于是 script 直接执行,假若提供 JSONP 服务器返回了恶意代码 (如被黑客入侵),这样将会十分危险。恶意代码可以向页面插入广告或者直接重定向第三方站点、甚至可以窃取 cookie 用 N 种方式发送到第三方服务器,这些都直接威胁站点安全。

有没有一种纯前端的方案可以安全的加载 JSONP 呢?下面是我想到的一个方案:

javascript 沙箱

一个安全的 JSONP 脚本它只给回调函数传入数据而不应该读写 document,更严格一点是不能进行任何的 DOM 与 BOM 操作。基于此,我们可以利用空白 iframe 新建一个脚本执行环境,然后限制 iframe.contentWindow 的 DOM 与 BOM 方法,让这个环境中运行的脚本无法读写主页面,也无法发起任何通讯请求,包括 AJAX 方式 与 new Image() 、 script 方式等,与 这样理论上实现了一个 javascript 沙箱环境。

由于浏览器 DOM 与 BOM 实现机制不同,我们可以结合以下两种方式编码。

一、覆盖不安全的方法与属性

  1. this.__proto__ = {} (现代浏览器)
  2. 设置全局同名函数(IE为主)
  3. 向文档插入一个同名 name 属性的 iframe (针对opera)

二、使用 HTML5 iframe “sandbox” 属性

HTML5 iframe “sandbox” 属性可以限制 iframe 内容的权限。这个属性目前只有 chrome 、 safari 、IE10 支持,而且这个属性可选项太少,虽然能够限制 ajax 请求,但无法阻止传统的跨域请求,如 new Image 或者 script 方式。

javascript 沙箱应用场景畅想

除了安全加载 JSONP 之外,沙箱机制还可以为社交平台实现安全 javascript API 提供可能:

由于安全问题,社交平台第三方 APP 大多以 iframe 形式载入,但是由于 iframe 本身的问题,这样体验远远不能达到“原生”应用的高度。针对此我们可以给 APP 开发者设计一个应用 API,让其只能在沙箱环境中操作 APP 自身的 DOM 与有限的公用 API,而没有访问全局对象的能力,从而实现体验与安全完美合一。

scriptSandbox 项目

scriptSandbox 是上述想法而创建了一个开源项目,正如本文所述,它实现了沙箱环境用来隔离 JSONP 可能出现的危险操作。目前你也可以理解它是一个 JSONP 安全加载器,scriptSandbox 项目主页:

http://code.google.com/p/script-sandbox/

特别说明:下载包中含有测试脚本 test.js, 它除了传递 JSONP 外,还模拟了 “危险” DOM 操作,你可以在不同浏览器中测试沙箱隔离能力。欢迎您在 test.js 写“危险”代码对沙箱进行攻击,若实现下面要求均算成功成功:

  1. 获取页面 document 访问能力
  2. 获取与服务器通讯能力
  3. 弹出对话框干扰用户

欢迎您给我提交漏洞报告 :) 1987.tangbin(a)gmail.com


参考文档:
http://www.infoq.com/cn/news/2010/01/HTML-5-Sandbox-IFrame
http://w3help.org/zh-cn/causes/BX9045

2012-01-28 更新

如何安全地嵌入第三方js – FBML/caja/sandbox/ADsafe简介
caja 原理 : 前端
[翻译]JavaScript动态执行作用域

跨浏览器 HTML5 postMessage 方法以及 message 事件模拟实现

postMessage 是 HTML5 新方法,它可以实现跨域窗口之间通讯。到目前为止,只有 IE8+, Firefox 3, Opera 9, Chrome 3和 Safari 4 支持,而本篇文章主要讲述 postMessage 方法与 message 事件跨浏览器实现。

postMessage 方法 JSONP 技术不一样,前者是前端擅长跨域文档数据即时通讯,后者擅长针对跨域服务端数据通讯,postMessage 应用场景能说明这个区别:

应用场景举例

  1. webOS 使用 iframe 嵌入第三方应用,此时 webOS 与应用需要实时接收/发送各自的消息与响应事件。
  2. 页面弹出一个由 iframe 层,嵌入第三方提供的图片上传页面,文件上传完毕后需要获取返回图片地址插入到编辑器。
  3. iframe 跨域高度自适应。

HTML5 postMessage 方法

postMessage 可以实现跨域文档的消息传输(Cross Document Messaging)。

向外界窗口发送消息:

otherWindow.postMessage(message, targetOrigin);

otherWindow: 指目标窗口,是 window.frames 属性的成员或者由 window.open 方法创建的窗口

参数说明:

  • message: 是要发送的消息,类型为 String、Object (IE8、9 不支持)
  • targetOrigin: 是限定消息接收范围,不限制请使用 ‘*’

HTML5 message 事件

绑定消息事件:

window.addEventListener('message', receiver, false);
function receiver (event) {
  if (event.origin === 'http://example.com') {
    if (event.data === 'Hello world') {
      event.source.postMessage('Hello', event.origin);
    } else {
      alert(event.data);
    };
  };
};

回调函数第一个参数接收 Event 对象,有三个常用属性:

  • data: 消息
  • origin: 消息来源地址
  • source: 源 DOMWindow 对象

message 事件在低版本浏览器下模拟实现

对于支持 postMessage 方法的浏览器直接使用它;而对于 IE6、7 采用了比较成熟的 window.name 保存数据以及跨域 iframe 静态代理动态传输方案,下面简称 Cross Frame。

Cross Frame

假设在域 www.a.com 上有页面 a.html 和代理页面 proxy-a.html , 另一个域 www.b.com 上有个页面 b.html 和代理页面 proxy-b.html,a.html 需要向 b.html 中发送消息时,页面会创建一个隐藏的 iframe 指向 proxy-b.html ,并把消息赋予 iframe.name 属性,此时 proxy-b.html 可以通过 window.name 获取到消息,由于 proxy-b.html 与 b.html 是同域,proxy-b.html 可以把消息赋予 b.html。 b.html 要给 a.html 发送消息时,原理一样。

自动捕获代理 URL

在 Cross Frame 方案中,通信双方必须确切的知道静态代理文件的 URL,显然这个极大的限制了应用范围,我们可以通过一些约定改善:静态代理文件必须置于通信页面所在域根目录,且文件名必须保持一致,如 messageEvent-proxy.html。

有了上述约定,接下来可以用一些巧妙的方法让双方自动捕获代理 URL。以 http://www.a.com/a.html 通过 iframe 嵌入 http://www.b.com/b.html 保持数据交换为例进行说明:

b.html 的静态代理路径可以通过正则分析 iframe.src 后得知;而从框架 b.html 内获取父页面就比较麻烦了,因为跨域后的 parent.location.href 属性只可写入不可读取,不过还可以借用 document.referrer 属性来分析来路地址得知父页面 url。document.referrer 是一个不稳定的属性,我们可以利用 iframe 中 window.name 刷新也不会变化的特性,用此来保存父页面 a.html 的地址。

持续跟踪 URL

a.html 第一次通过提取 iframe.src 路径可得知 b.html 的地址,假若 b.html 跳转到其他域名的时候,此时就会失去对 iframe 内静态代理的联络。 好在新页面由于能够获取父页面 a.html 保存在 window.name 的静态代理,所以我们可以在新页面初始化的时候向 a.html 传递消息告诉它新的地址,这样就能持续跟踪 iframe 中的 URL。

开源事件库 messageEvent.js

“messageEvent.js”是针对上述方案封装的 message 事件与 postMessage 方法库,它让各个浏览器之间 message 的 Event 对象成员属性统一,event.data 属性能传递多达 2MB 的文本信息,并且能让 IE6-9 浏览器像其他现代浏览一样支持 Object 类型数据进行传递 (内部使用深拷贝方式)。

若应用双方页面都采用 messageEvent.js,即可轻松实现跨域通信。

接口

  • add(callback) 添加 message 事件
  • remove(callback) 卸载 message 事件
  • postMessage(otherWindow, message, targetOrigin) 向外部窗口发送消息

通过 jQuery 使用它

jQuery 是一个应用比较广泛的 DOM 库,它的事件机制非常强大而精妙,可以实现自定义事件。若页面引用了 jQuery, messageEvent.js 会为为它提供支持,你可以用熟悉的jQuery api 风格编程,如:

jQuery(window).bind('message', function (event) {
      alert(event.data)
});

jQuery(window).message(function (event) {
      alert(event.data)
});

jQuery.postMessage(iframe.contentWindow, 'hello world', '*');

jQuery(window).unbind('message');

由于 jQuery 把包装后的 Event 对象用 data 属性来保存 bind 方法传入的额外数据,导致与 message 事件自身的 event.data 属性冲突——这是一个设计错误。为了让 message 事件能够正确获取 event.data,messageEvent.js 通过操作 jQuery 底层缓存强制覆盖了 bind 方法传入的附加数据 (只针对 message 类型)。当然,我仍然期待 jQuery 未来版本能够取消掉 bind 方法的鸡肋特性。

项目地址

项目主页: http://code.google.com/p/message-event/
在线阅读最新版源码: messageEvent.js | messageEvent-proxy.html

项目下载包提供了文档与示例,若有疑问或建议欢迎在本文下评论,还可以在腾讯微博上即时交流: http://t.qq.com/k/messageEvent.js


参考文档:
http://www.w3.org/TR/html5/comms.html
https://developer.mozilla.org/en/DOM/window.postMessage
http://www.blueidea.com/tech/web/2010/8049.asp
http://www.36ria.com/3890

唐斌 – 2012.01.05 – 深圳

HTML5 Powered with CSS3 / Styling, and Semantics

javascript模版引擎-tmpl的bug修复与性能优化

在平时编码中,经常要做拼接字符串的工作,如把json数据用HTML展示出来,以往字符串拼接与逻辑混在在一起会让代码晦涩不堪,加大了多人协作与维护的成本。而采用前端模板机制就能很好的解决这个问题。

精妙的 tmpl

前端模板类开源的不少,但最属 jQuery 作者 John Resig 开发的 “javascript micro templating” 最为精妙,寥寥几笔便实现了模板引擎核心功能。

它的介绍与使用方式请看作者博客:http://ejohn.org/blog/javascript-micro-templating/

让我们先看看他的源码:


麻雀虽小,五脏俱全,除了基本的数据附加外,还拥有缓存机制、逻辑支持。现在,若要我评出一个javascript 最节能的自定义函数排名,第一名是 $ 函数(document.getElementById 简版),而第二名就是 tmpl 了。

当然,它并非完美,我使用过程中发现了一些问题:

tmpl 美中不足

一、无法正确处理转义字符,如:


它就会报错。若正常工作,它应该输出:糖饼/1987

实际上解决起来很简单,添加一行正则对转义符进行转义:


二、它有时候无法正确区分第一个参数是ID还是模板。

假若页面模板ID带有下划线,如 tmpl-photo-thumb 它不会去查找这个名称的模板,会认为这传入的是原始模板直接编译输出。

原始模板与元素id最直观的区别就是是否含有空格,因此改动下正则表达式即可:


三、它内部还残有一处测试用的代码,可删除。


tmpl 效率的疑惑

直到前段时间看了百度mux一篇介绍 YayaTemplate 的软文,原文作者对各大流行的模板引擎进行了效率测试,最终得出 YayaTemplate 是最快的一个。 虽然测试结果 tmpl 不敌 YayaTemplate ,但也让我打消了对性能的顾虑,实际应用中与传统的字符串拼接差不多。它们只有进行超大规模的解析才会有较大的性能差距。(超大规模?javascript本身就不适合干这事。若哪天程序员一次性给浏览器插入上千条列表数据而其慢无比的时候,不用怀疑:问题出在了这个程序员身上,他不会爱惜用户的浏览器。)

若说到引擎效率排名问题,我倒不觉得这是不能是衡量模板引擎的首要标准,模板语法也是重要的一环,这时候 YayaTemplate 的模板语法就显得晦涩多了,它为了节省几个正则表达式而在模板语法上耍了小聪明。

先展示 YayaTemplate 的源码:


若把性能问题上升到一个“学术问题”的高度尝试去解决,为什么 tmpl 会比 YayaTemplate 慢?

语法解析?虽然 YayaTemplate 使用了一个新颖的 javascript 包裹 html 的方式作为模板语法,但最终都需要用正则表达式解析成标准的 javascript 语法,这里正则的效率不会有太大的差异,并且双方都使用了缓存机制确保只对原始模板仅进行一次解析。

数据转换?模板引擎会把数据最终以变量的形式保存在闭包中,以好让模板获取到。这里先对比下一下双方的变量声明机制:

YayaTemplate 使用传统传递参数的形式实现。它通过遍历数据对象,把对象的名值分离,然后分别把对象成员名称作为new Function的参数名(即变量名),然后使用函数的appley调用方式传给那些参数。

tmpl 则使用了javascript不常用的 with 语句实现。 实现方式很简洁,省去了var这个关键字。

tmpl 性能问题就出在 with 上面。javascript 提供的 with 语句,本意是想用来更快捷的访问对象的属性。不幸的是,with语句在语言中的存在,就严重影响了 javascript 引擎的速度,因为它阻止了变量名的词法作用域绑定。

优化 tmpl

tmpl 若去掉 with 语句,而改用传统的传参性能立即大提升,经过实测在24万条数据下 firefox 能提高 5 倍,chrome 2.4 倍,opera 1.84倍,safari 2.1倍,IE6 1.1倍,IE9 1.35倍,最终与 YayaTemplate 不分上下。

测试地址:http://www.planeart.cn/demo/tmpl/tmpl.html

tmpl 优化版最终代码:


模板引擎依赖 Function 构造器实现,它与 eval 一样提供了使用文本访问 javascript 解析引擎的方法,这也会让性能显著的降低,但此时 javascript 中已别无他法。

使用 Function 构造器还会对参数名称有所限制,所以导致数据成员命名必须与 javascript 变量名规范保持一致,否则会报错。好在这个错误可以在运行的时候立马被发现,而不会成为一颗地雷。

tmpl 使用小窍门

一、缓存优化。

tmpl 默认对嵌入到页面中的模板进行了缓存优化(即第一个参数为ID的时候),它只会对模板进行一次分析。若原始模板是直接传入到 tmpl 第一个参数中,且需要多次使用的话,建议用公用变量缓存起来,需要解析数据的时候再使用,以获得相同的优化效果。如:


二、避免未定义的变量引起系统崩溃。

若模板中定义了一个变量输出,而且传入数据却少了这个项目就会出现变量未定义的错误,从而引起整个程序的崩溃。如果无法确保数据完整性,仍然有方法可以对对其成员进行探测。原版中暗含变量保存了原始传入的数据,即 obj ;而在我的升级版本中则是关键字 this,如:


三、调试模板。

由于模板引擎是用文本的调用的 javascript 引擎,调试工具无法定位到出错的行。在 升级版本 中你可以用调试工具输出编译好的模板缓存。例如调试这个模板:



输出缓存:


日志结果:


现在你可以看到模板引擎编译好的javascript语句,可以对照这检查模板是否存在错误。($1318348744541是一个随机名称的临时数组,可忽略)

最后非常感谢 tmpl 原作者 与 YayaTemplate 作者的付出,正因为此我才有机会深入分析实现机制,解决问题并从中受益。独乐不如众乐,分享之。

2011-10-24更新:
无忧脚本有精彩评论,可以移步至: http://bbs.51js.com/thread-89114-1-1.html

唐斌 – 2011.10.09 – 湖南-长沙

梦想

从公司回来已经是10点多了,感觉到有点渴,于是在商店里面买杯绿豆粥。在店里遇到一个小女生打招呼,我准备请她吃东西,她婉拒,可能是不好意思吧,后来邀她在湖边聊天。

她现在在学校图书馆里面的咖啡厅当服务员,而去年我图书馆那呆了很长一段时间,经常在那写代码或做设计等。她们老板与我们也是好朋友,大家慢慢的与店里面的老员工都熟悉起来,如果生日还会相互叫上一起吃蛋糕等。她与其他店员不同,做事与谈吐显得特别沉稳、细心。她今年才满16岁,人也长得漂亮,可能漂亮的女生都会显得成熟吧,如果她自己不说估计没有几个人能能够猜出年龄。

她与其他店里的员工一样,每天上午11点工作到晚上10点,平时几乎不放假,薪酬不到1500。我想这个数字很多人是无法想象的,在深圳,如果不是包吃住几乎无法生存下来。

我问她:“你准备继续再这里呆多久呢?”

“我不知道呢,不过我不想继续这样下去”

“你还小呢,才16岁啊,你这个时候我才高一呢。你都出来两年了,知道累了吧,现在去学校读书或者去学一门技能也不迟啊,你初中没毕业就出来工作你爸妈不反对你吗?”

她停顿了一会儿说:

“如果继续上学,那也是靠自己……”

这时候我隐隐约约感觉到自己说错话了,小心的问道:

“是不是爸妈不支持你上学?”

“是的……我是想读书,他们不让我”

说完她便侧过头去哭了起来,我整个人此时都傻了,不知所措。我只是出于对一个朋友、一个简单到几乎如萍水相逢的朋友,简单不能再简单的关心与建议,没有想到却碰到了别人心里深处的伤痛。难怪她会相对同龄人表现的如此成熟稳重,我想换作谁都无法在少年承受这么命运,看到听到的更多是一个少年将从此堕落的故事。

我此时想不到任何语言来安慰她,之前我觉得想要改变自己的命运得不断丰富自己的阅历,在学校读书的经历就是其中之一。我们一生花了大部分时间在学校,虽然每个人从学校出来后都说没有学到什么,其实并不是这样。虽然学历只是一个表面的东西,但真正造就人的还是这段经历,这段不用衣食发愁的岁月,可以展现出自己的天赋、收获真挚的友谊、寻找单纯的爱情……如果少年的时候在外面漂泊,一两年可能会比学校里面的同龄人有更大的收获,但两年之后呢?社会漂泊带来的收益会越来越少,因为此时实际上生活圈子越来越固定,直至定型成为人一生的标志,这样很难被改变,甚至这个时候人会不断的走下坡路。

我想起了约翰·克利斯朵夫的一句名言:大部分人在二三十岁上就死去了,因为过了这个年龄,他们只是自己的影子,此后的余生则是在模仿自己中度过,日复一日,更机械,更装腔作势地重复他们在有生之年的所作所为,所思所想,所爱所恨。

但此刻面对这个无助的小女孩,我才真切的感觉到“梦想”是一种奢侈,对她来说可望不可及的东西,我用“梦想”伤害了她。

我对她讲我自己的经历,说我的失败与成长,我告诉她我从我初中的不懂事、到高中跌入一个自己从来没有接触过的环境,身边的同学全部都是富家子弟、那些年得意的事情、以及最终的失败的痛苦与不甘,说起高四的时光……

这时候她笑了,说哪有会“高四”,我说我们把复读当作高四。

我还和她说起我后来来了一个新同桌,她打扮得十分妖艳,感觉二十三四岁了(后来才得知她才16岁,北京某艺校出来参加湖南的高考)。我很反感她这造型,4天没和她说一句话,那段时间常常会有一些初中生趴在教室外窗台围观她,才得知她原来是一个选秀节目的明星,后来在湖南卫视当主持去了……

她问我她名字,是哪个节目的主持人,说实在的这些我真的不太记得了,我要去QQ找找,反正不是谢娜。

我继续和她聊起我大学毕业,以及现在的创业以及生存压力,我告诉她每个人其实都有自己的苦,只有自己知道,一般不会对别人说起,正如现在你不和我说,我就不会知道你这些,当然你也不知道我的这些失败的经历。我告诉她,我从微博上看到了很多悲催的事情,比如一个父亲,大儿子被3鹿奶粉给弄残了,小儿子被毒疫[miao]给弄残了,他不甘心,进行诉求,结果最后被判了几年……

她说我知道社会很黑暗。我说你其实并没有真正接触到黑暗,对吧?现在很多人都比自己苦上千倍,照样要好好活着,我们都还很年轻,相信总有一天会更美好。

我并不希望今天说的东西让她回去睡不着,更怕看到别人哭,后面聊了一些愉悦的话题,总算让氛围慢慢轻松起来。我回来感慨万千,我是幸福的,哪怕失败了,一直以来都有父母亲的支持。同时我也是不幸的,我正如其他所有同龄人一样,背负着时代赋予的压力,在高楼大厦之间缓慢前行,却从来没有感受过改变过时代。

梦想这个东西在我们所处的时代其实一个奢侈品,谁拥有了绝对不敢拿出来,只有把它藏在内心深处,生怕被人看见,要么被人眼红,要么被人嘲讽。梦想它不是必需品,生存才是人类最基本的需求,又有多少拥有梦想的人在这个过程中被磨灭?也许下一个可能就是你我。涂磊说,既然大家都很无奈,那就互相的无奈下去,看看谁能够在无奈之中活的更加精彩,人来到这个世界上,不就是在互相比拼,看谁能够承受得更多吗?

此时已经很晚了,我很久没有写这么长的日志了,那无助的小女孩、朋友以及自己:晚安,新的一天会更好,因为自己永远年轻!

 

唐斌,2011年9月8号凌晨4点于深圳

创建数据共享接口——简化框架之间相互传值

很多框架存在父子关系,操作起来十分麻烦,很多同学经常出现这样悲催的代码:

window.parent.document.getElementById("main")
.contentWindow.document.getElementById('input').value =
document.getElementById('myIframe')
.contentWindow.document.getElementById('s0').value;

其实这个问题可以被大大的简化,框架应用中有一个固定不变的窗口叫window.top,如果我们把数据缓存到这个页面,其下所有框架都可以获取到,无论子页面如何变幻。不需要采用Cookie,也不需要采用什么HTML5本地数据库策略,你只需要每个页面引用一个js文件,内容如下:

var share = {

	/**
	 * 跨框架数据共享接口
	 * @param	{String}	存储的数据名
	 * @param	{Any}		将要存储的任意数据(无此项则返回被查询的数据)
	 */
	data: function (name, value) {
		var top = window.top,
			cache = top['_CACHE'] || {};
		top['_CACHE'] = cache;

		return value !== undefined ? cache[name] = value : cache[name];
	},

	/**
	 * 数据共享删除接口
	 * @param	{String}	删除的数据名
	 */
	removeData: function (name) {
		var cache = window.top['_CACHE'];
		if (cache && cache[name]) delete cache[name];
	}

};

这个寥寥数行的方法可以共享任意类型的数据供各个框架页面读取,它与页面名称、层级毫无关系,就算哪天框架页面层级被修改,你也完全不用担心,它可正常工作。

例如,如我们可以在A页面存入共享数据:

share.data(‘myblog’, ‘http://www.planeart.cn’);
share.data(‘editTitle’, function (val) {
document.title = val;
});

然后某框架页面任意取A页面的数据

alert(‘我的博客地址是: ‘ + share.data(‘myblog’);
var editTitle = share.data(‘editTitle’);
editTitle(‘我已经获取到了数据’);

对,就这么简单!你还可以在artDialog4.0.0 的iframeTools扩展中看到此技术身影。

planeArt.cn原创,原文地址

javascript克隆元素样式

这是一个实验用的玩意,它可以克隆指定元素的最终样式,并包装成一个css类,它还可以证明Oprea 11.10 是个混球:
Continue reading ‘javascript克隆元素样式’

文本框根据输入内容自适应高度

我最烦wordpress编辑器容器那狭窄的高度,每次都需要手动调节,很不好用。其实现代浏览器大多都支持文本框尺寸调节功能,绝大多数情况下却没有自动适应来得爽快,在网络上发现一方法比较简单的实现文本框高度自适应,于是封装了这个函数,准备以后应用到项目中。

Continue reading ‘文本框根据输入内容自适应高度’

关于微博超链接的可用性

一个典型的场景:

早上起床打开电脑,阅读新微博,不断的翻页后,发现一个有意思的人儿,于是去点击用户名去看他/她的主页,看完后再按浏览器后退键返回我的主页,这时候你会发现浏览器滚动条并未停留在之前的位置,这就意味着你需要重新点击“更多”,找到原来的地方继续阅读,如果列表很长的话会很抓狂……

Continue reading ‘关于微博超链接的可用性’

关于javascript function对象那些迷惑

js中function对象是一个令人着迷的东西,但由于他太过于灵活,常常令人迷惑,下面我贴一些代码:
Continue reading ‘关于javascript function对象那些迷惑’

关于artDialog

artDialog并未停止开发,我很忙,很忙,老的代码很久未接触了,所以很多API或网友提的问题我无法快速给出解决方案。我的blog评论默认是不公开的,所以很多关于artDialog的留言都积压在评论列表里面未解决,留言或者email我后面会逐一回复。

artDialog最宝贵的就是API与UI,我也看到有一开源对话框组件借鉴了artDialog API或使用了artDialog的UI,深感荣幸。如果你不愿意等待我的artDialog4,你可以去看我在phpChina发dialogTools,dialogTools是一个用于创建自定义对话框的小工具集,它自身不具备UI,但可以很方便的让你设计的层/表格实现可拖动位置、调节尺寸、跟随元素、设置锁屏遮罩。

dialog tools: http://bbs.phpchina.com/thread-213148-1-1.html
aero psd: http://code.google.com/p/artdialog/downloads/detail?name=aero.psd&can=2&q=