<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>realazy &#187; JS / Dom</title>
	<atom:link href="http://chen.xianan.name/blog/category/javascript-dom/feed/" rel="self" type="application/rss+xml" />
	<link>http://chen.xianan.name/blog</link>
	<description>web 标准，前端开发，编程感悟，生活杂想</description>
	<lastBuildDate>Thu, 13 Aug 2009 15:30:19 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>AIR 的尝试</title>
		<link>http://chen.xianan.name/blog/2009/01/11/ifan-on-air/</link>
		<comments>http://chen.xianan.name/blog/2009/01/11/ifan-on-air/#comments</comments>
		<pubDate>Sun, 11 Jan 2009 10:46:35 +0000</pubDate>
		<dc:creator>realazy</dc:creator>
				<category><![CDATA[JS / Dom]]></category>

		<guid isPermaLink="false">http://realazy.org/blog/?p=188</guid>
		<description><![CDATA[最近利用 Adobe AIR 做了一个饭否客户端：爱饭，并将之开源。使用 HTML, CSS 和 JavaScript 对着 API 文档照虎画猫，大概三个星期完工，有一些感想和总结。

AIR 的开发对 Web 开发者非常友好，基本上不需要额外的程序知识了，甚至可以使用已有的 JS 库，爱饭就使用了 YUI。但是生成的程序有一通病，那就是占用内存高（爱饭在 Windows 下占用 40m 左右），而且不存在优化之说。做严肃的应用 AIR 还是上不了台面。很多时候觉得，打开一个 AIR 程序，其实就是打开了一个浏览器。
absolute 的 CSS 布局方式非常灵活，对窗口缩放这种情况具有非常好的适应性。使用 webkit 引擎的 AIR 对 absolute 完全支持。如果是 IE 这种支持残缺的引擎，那得费非常多的 JS 代码。在 AIR 下写 CSS 有一种莫名的快感。正好 24ways 上发布了一篇关于 absolute 方式布局的文章，免却了我的罗嗦，见：Absolute Columns。
AIR 对 Linux 的支持还是存在缺失，比如无法给窗口加阴影，看来是 Linux 下的 Flash 支持跟不上。

完毕。
]]></description>
			<content:encoded><![CDATA[<p>最近利用 <a href="http://www.adobe.com/products/air/">Adobe AIR</a> 做了一个饭否客户端：<a href="http://ifan.realazy.org/">爱饭</a>，并将之<a href="http://code.google.com/p/ifan/">开源</a>。使用 HTML, CSS 和 JavaScript 对着 API 文档照虎画猫，大概三个星期完工，有一些感想和总结。</p>
<ol>
<li>AIR 的开发对 Web 开发者非常友好，基本上不需要额外的程序知识了，甚至可以使用已有的 JS 库，爱饭就使用了 YUI。但是生成的程序有一通病，那就是占用内存高（爱饭在 Windows 下占用 40m 左右），而且不存在优化之说。做严肃的应用 AIR 还是上不了台面。很多时候觉得，打开一个 AIR 程序，其实就是打开了一个浏览器。</li>
<li>absolute 的 CSS 布局方式非常灵活，对窗口缩放这种情况具有非常好的适应性。使用 webkit 引擎的 AIR 对 absolute 完全支持。如果是 IE 这种支持残缺的引擎，那得费非常多的 JS 代码。在 AIR 下写 CSS 有一种莫名的快感。正好 24ways 上发布了一篇关于 absolute 方式布局的文章，免却了我的罗嗦，见：<a href="http://24ways.org/2008/absolute-columns">Absolute Columns</a>。</li>
<li>AIR 对 Linux 的支持还是存在缺失，比如无法给窗口加阴影，看来是 Linux 下的 Flash 支持跟不上。</li>
</ol>
<p>完毕。</p>
]]></content:encoded>
			<wfw:commentRss>http://chen.xianan.name/blog/2009/01/11/ifan-on-air/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>使用 iframe 获取网页片段的一个好处</title>
		<link>http://chen.xianan.name/blog/2008/11/30/benifit-of-fecthing-page-via-iframe/</link>
		<comments>http://chen.xianan.name/blog/2008/11/30/benifit-of-fecthing-page-via-iframe/#comments</comments>
		<pubDate>Sun, 30 Nov 2008 03:30:51 +0000</pubDate>
		<dc:creator>realazy</dc:creator>
				<category><![CDATA[JS / Dom]]></category>
		<category><![CDATA[交互设计]]></category>

		<guid isPermaLink="false">http://realazy.org/blog/?p=186</guid>
		<description><![CDATA[异步操作数据的方式有两种常见的方式：XMLHttpRequest 和 iframe. 孰优孰劣在此我们不争论，只是想举一个例子说明在获取网片片段上，使用 iframe 有一个比 XMLHttpRequest 更易企及的好处。
Ajax 常见的一种使用方法是加载网页片段填充某个区域。假设我们要在网页 foo.com/index 上请求 foo.com/partial。我们假设 partial 就是 HTML，不涉及 JSON 或 XML 格式。在这种情况下：

使用 XMLHttpRequest 直接访问 partial，获取 responseText 后赋予 index 页面上某个元素的 innerHTML 即可完成。partial 必须是一个纯粹的 HTML 片段（基于以上假设）。
在页面上创建一个隐藏的 iframe, 使用 iframe 的 src 请求 partial, partial 可以作为一个完整的页面，里面包含 JavaScript，由 partial 里的 JS 完成替换 index 上页面片段替换。

第二种看起来更繁琐，但能给我们更多控制权。例如，假如用户直接访问 foo.com/partial（这种情况很容易发生，假设您是 unobtrusive 的拥护者，机会更大，例如需要点击网页上的链接更新某部分内容时，用户使用新窗口打开了改链接）, 你希望她看到的是什么内容呢？
在第一种情况中，用户看到的是代码片段，绝大部分下没有任何样式，也没有任何额外提示，导致用户体验的下降。因为只是一个 HTML 片段，你什么事都干不了。
但在第二种情况下，用户看到内容可能也只是 HTML 片段，但这却是一个完整的页面，一个可以执行 [...]]]></description>
			<content:encoded><![CDATA[<p>异步操作数据的方式有两种常见的方式：<code>XMLHttpRequest</code> 和 <code>iframe</code>. 孰优孰劣在此我们不争论，只是想举一个例子说明在获取网片片段上，使用 <code>iframe</code> 有一个比 <code>XMLHttpRequest</code> 更易企及的好处。</p>
<p>Ajax 常见的一种使用方法是加载网页片段填充某个区域。假设我们要在网页 foo.com/index 上请求 foo.com/partial。我们假设 partial 就是 HTML，不涉及 JSON 或 XML 格式。在这种情况下：</p>
<ol>
<li>使用 <code>XMLHttpRequest</code> 直接访问 partial，获取 responseText 后赋予 index 页面上某个元素的 innerHTML 即可完成。partial 必须是一个纯粹的 HTML 片段（基于以上假设）。</li>
<li>在页面上创建一个隐藏的 iframe, 使用 iframe 的 src 请求 partial, partial 可以作为一个完整的页面，里面包含 JavaScript，由 partial 里的 JS 完成替换 index 上页面片段替换。</li>
</ol>
<p>第二种看起来更繁琐，但能给我们更多控制权。例如，假如用户直接访问 foo.com/partial（这种情况很容易发生，假设您是 unobtrusive 的拥护者，机会更大，例如需要点击网页上的链接更新某部分内容时，用户使用新窗口打开了改链接）, 你希望她看到的是什么内容呢？</p>
<p>在第一种情况中，用户看到的是代码片段，绝大部分下没有任何样式，也没有任何额外提示，导致用户体验的下降。因为只是一个 HTML 片段，你什么事都干不了。</p>
<p>但在第二种情况下，用户看到内容可能也只是 HTML 片段，但这却是一个完整的页面，一个可以执行 JS 的完整页面。我们只需检查这个页面的 parent 对象有没有我们预设的值，就可以判断它是不是在 iframe 之内了，然后我们可以让它跳转到正常的页面。</p>
<p>Demo: <a href="http://realazy.org/lab/xhrvsiframe/">http://realazy.org/lab/xhrvsiframe/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://chen.xianan.name/blog/2008/11/30/benifit-of-fecthing-page-via-iframe/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>Firebox 3 后退后按钮 diasabled 状态不恢复的一个解决方案</title>
		<link>http://chen.xianan.name/blog/2008/10/27/a-solution-to-firefox-back-button-disabled/</link>
		<comments>http://chen.xianan.name/blog/2008/10/27/a-solution-to-firefox-back-button-disabled/#comments</comments>
		<pubDate>Mon, 27 Oct 2008 06:34:19 +0000</pubDate>
		<dc:creator>realazy</dc:creator>
				<category><![CDATA[JS / Dom]]></category>

		<guid isPermaLink="false">http://realazy.org/blog/?p=185</guid>
		<description><![CDATA[Firefox 3 有一个很让人讨厌的bug：基于某种目的，在表单提交时 disable 掉提交按钮，通过后退键回到这个页面后，这个提交按钮的状态依旧保持为 disabled 的状态，重新载入（软硬刷新）也无法改变。
google 良久，从 https://developer.mozilla.org/En/Using_Firefox_1.5_caching 中发现一个 window.onpageshow 事件，window.onload 事件无法在后退的页面中出发，但这个可以，所以解决方案就是它了。

window.addEventListener('pageshow', function(e){
    // 重置你不需要 disabled 的按钮
}, false);

更新：网友岁月如歌的解决方案比我的方案简易和正宗多了：给提交按钮加上 autocomplete="off" 的属性。
]]></description>
			<content:encoded><![CDATA[<p>Firefox 3 有一个很让人讨厌的bug：基于某种目的，在表单提交时 disable 掉提交按钮，通过后退键回到这个页面后，这个提交按钮的状态依旧保持为 <code>disabled</code> 的状态，重新载入（软硬刷新）也无法改变。</p>
<p>google 良久，从 <a href="https://developer.mozilla.org/En/Using_Firefox_1.5_caching">https://developer.mozilla.org/En/Using_Firefox_1.5_caching</a> 中发现一个 <code>window.onpageshow</code> 事件，<code>window.onload</code> 事件无法在后退的页面中出发，但这个可以，所以解决方案就是它了。</p>
<pre><code>
window.addEventListener('pageshow', function(e){
    // 重置你不需要 disabled 的按钮
}, false);
</code></pre>
<p><strong>更新：</strong>网友岁月如歌的<a href="http://lifesinger.org/blog/?p=569">解决方案</a>比我的方案简易和正宗多了：给提交按钮加上 <code>autocomplete="off"</code> 的属性。</p>
]]></content:encoded>
			<wfw:commentRss>http://chen.xianan.name/blog/2008/10/27/a-solution-to-firefox-back-button-disabled/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>form 元素内的字段 name 不要跟 form 属性名称一致</title>
		<link>http://chen.xianan.name/blog/2008/10/08/do-not-use-filed-name-same-as-form-attribute-name/</link>
		<comments>http://chen.xianan.name/blog/2008/10/08/do-not-use-filed-name-same-as-form-attribute-name/#comments</comments>
		<pubDate>Wed, 08 Oct 2008 13:35:34 +0000</pubDate>
		<dc:creator>realazy</dc:creator>
				<category><![CDATA[JS / Dom]]></category>

		<guid isPermaLink="false">http://realazy.org/blog/?p=183</guid>
		<description><![CDATA[长话短说，看这个 form 元素：
&#60;form method="post" action="_some_action_uri_" id="_form_id_"&#62;
&#60;input type="hidden" name="method" value="1" /&#62;
&#60;/form&#62;
试想一下，使用 document.getElementById('_form_id_').getAttribute('method') 会出现什么情况。Firefox 3, Safari 3, Opera 9.5 都会得到预期 &#8220;post&#8221;, 但是IE 6 和 7 就没有那么幸运了，得到的是一个 object: 其实就是 &#60;input type="hidden" name="method" value="1" /&#62; 这个元素。
因此，为避免混淆和挽救IE，最好是，as the title.
]]></description>
			<content:encoded><![CDATA[<p>长话短说，看这个 <code>form</code> 元素：</p>
<pre><code>&lt;form method="post" action="_some_action_uri_" id="_form_id_"&gt;
&lt;input type="hidden" name="method" value="1" /&gt;
&lt;/form&gt;</code></pre>
<p>试想一下，使用 <code>document.getElementById('_form_id_').getAttribute('method')</code> 会出现什么情况。Firefox 3, Safari 3, Opera 9.5 都会得到预期 &#8220;post&#8221;, 但是IE 6 和 7 就没有那么幸运了，得到的是一个 object: 其实就是 <code>&lt;input type="hidden" name="method" value="1" /&gt;</code> 这个元素。</p>
<p>因此，为避免混淆和挽救IE，最好是，as the title.</p>
]]></content:encoded>
			<wfw:commentRss>http://chen.xianan.name/blog/2008/10/08/do-not-use-filed-name-same-as-form-attribute-name/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>focus 进 textarea 元素后光标位置的修复</title>
		<link>http://chen.xianan.name/blog/2008/09/10/fix-cursor-position-in-focusing-textare/</link>
		<comments>http://chen.xianan.name/blog/2008/09/10/fix-cursor-position-in-focusing-textare/#comments</comments>
		<pubDate>Wed, 10 Sep 2008 07:21:04 +0000</pubDate>
		<dc:creator>realazy</dc:creator>
				<category><![CDATA[JS / Dom]]></category>

		<guid isPermaLink="false">http://realazy.org/blog/?p=182</guid>
		<description><![CDATA[问题
一个已经有内容的 textarea 元素，在执行该元素的 .focus() 方法后，不同的浏览器有不同表现。我们的预期是能够出现在内容后面，但只有 gecko 浏览器能做到。
修复
注意：这个函数不能直接运行，函数内的 isIE, isOpera 和 isWebkit 需要你的库提供或你编写，这并不难，对吧。
function fixTextareaFocusCursorPosition(elTextarea){
    if (isIE &#124;&#124; isOpera){
        var rng = elTextarea.createTextRange();
        rng.text = elTextarea.value;
        rng.collapse(false);
    } else if [...]]]></description>
			<content:encoded><![CDATA[<h2>问题</h2>
<p>一个已经有内容的 <code>textarea</code> 元素，在执行该元素的 <code>.focus()</code> 方法后，不同的浏览器有不同表现。我们的预期是能够出现在内容后面，但只有 gecko 浏览器能做到。</p>
<h2>修复</h2>
<p>注意：这个函数不能直接运行，函数内的 isIE, isOpera 和 isWebkit 需要你的库提供或你编写，这并不难，对吧。</p>
<pre><code>function fixTextareaFocusCursorPosition(elTextarea){
    if (isIE || isOpera){
        var rng = elTextarea.createTextRange();
        rng.text = elTextarea.value;
        rng.collapse(false);
    } else if (isWebkit) {
        elTextarea.select();
        window.getSelection().collapseToEnd();
    }
}</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://chen.xianan.name/blog/2008/09/10/fix-cursor-position-in-focusing-textare/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>跨浏览器使用剪贴板</title>
		<link>http://chen.xianan.name/blog/2008/09/01/using-clipboard-crossbrowsers/</link>
		<comments>http://chen.xianan.name/blog/2008/09/01/using-clipboard-crossbrowsers/#comments</comments>
		<pubDate>Mon, 01 Sep 2008 08:19:10 +0000</pubDate>
		<dc:creator>realazy</dc:creator>
				<category><![CDATA[JS / Dom]]></category>

		<guid isPermaLink="false">http://realazy.org/blog/?p=181</guid>
		<description><![CDATA[一般情况下，访问或设置剪贴板，IE 只需使用 window.clipboardData 的 getData 或 setData 方法即可。Mozilla 家族的浏览器（如 Firefox）则比较麻烦，不仅开发者需要写一沱代码，用户也需要主动配合（就是需要设置允许访问剪贴板）才可以（参考 Using the Clipboard），以致几不可用。至于 Opera 则根本不提供剪贴板，Safari 可以在 onpaste 等非Dom 事件中访问剪贴板（参考 Using the Pasteboard From JavaScript）。
中国特色的网站上有一个很中国特色的应用就是，在一个输入框 focus 时自动帮你把内容复制到了剪贴板中。老实说访问剪贴板是个不安全的操作，因此即使是 IE, Windows 在后来的升级中都加入是否允许访问剪贴板的提醒。如果能够做到跨浏览器的“邪恶地悄无声息”地实现中国特色的剪贴板应用，确实是个不小的挑战。
遗憾的是老外在 2006 年就帮我们做到了：使用 Flash。参考 Clipboard Copy. 原版没有考虑不安转或禁止 Flash 的情况，我做了一个小改进：
function copy(inElement) {
    var get = function(id){
        return document.getElementById(id);
 [...]]]></description>
			<content:encoded><![CDATA[<p>一般情况下，访问或设置剪贴板，IE 只需使用 <code>window.clipboardData</code> 的 <code>getData</code> 或 <code>setData</code> 方法即可。Mozilla 家族的浏览器（如 Firefox）则比较麻烦，不仅开发者需要写一沱代码，用户也需要主动配合（就是需要设置允许访问剪贴板）才可以（参考 <a href="http://developer.mozilla.org/En/Using_the_Clipboard">Using the Clipboard</a>），以致几不可用。至于 Opera 则根本不提供剪贴板，Safari 可以在 onpaste 等非Dom 事件中访问剪贴板（参考 <a href="http://developer.apple.com/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Tasks/CopyAndPaste.html">Using the Pasteboard From JavaScript</a>）。</p>
<p>中国特色的网站上有一个很中国特色的应用就是，在一个输入框 focus 时自动帮你把内容复制到了剪贴板中。老实说访问剪贴板是个不安全的操作，因此即使是 IE, Windows 在后来的升级中都加入是否允许访问剪贴板的提醒。如果能够做到跨浏览器的“邪恶地悄无声息”地实现中国特色的剪贴板应用，确实是个不小的挑战。</p>
<p>遗憾的是老外在 2006 年就帮我们做到了：使用 Flash。参考 <a href="http://www.jeffothy.com/weblog/clipboard-copy/">Clipboard Copy</a>. 原版没有考虑不安转或禁止 Flash 的情况，我做了一个小改进：</p>
<pre><code>function copy(inElement) {
    var get = function(id){
        return document.getElementById(id);
    },
        elId = &apos;flashcopier&apos;,
        embedId = &apos;flashembed&apos;;

    if(!get(elId)) {
        var divholder = Document.createElement(&apos;div&apos;);
        divholder.setAttribute(&apos;id&apos;, elId);
        document.body.appendChild(divholder);
    }

    var divholder = get(elId);
    divholder.innerHTML = &apos;&lt;embed src="http://static.hainei.com/swf/cp.swf&quot;\
                    FlashVars=&quot;clipboard=&apos;+encodeURIComponent(inElement.value)+&apos;&quot;\
                    width=&quot;0&quot; height=&quot;0&quot; type=&quot;application/x-shockwave-flash&quot;\
                    id=&quot;&apos;+embedId+&apos;&quot;&gt;&lt;/embed&gt;&apos;;

    // 检测是否安装了 Flash
    var flashObj = window[embedId] || document[embedId] || {};
    if (!flashObj.SetVariable){// 没有 flash
        try {
            return window.clipboardData.setData(&quot;Text&quot;, inElement.value);
        }
        catch(ex){
            return false;
        }
    }

    return true;
}</code></pre>
<p>原版是 GPL 的，这个版本也请爱咋咋用……</p>
]]></content:encoded>
			<wfw:commentRss>http://chen.xianan.name/blog/2008/09/01/using-clipboard-crossbrowsers/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>富文本编辑器的基本原理与实践</title>
		<link>http://chen.xianan.name/blog/2008/05/02/rte-basis/</link>
		<comments>http://chen.xianan.name/blog/2008/05/02/rte-basis/#comments</comments>
		<pubDate>Thu, 01 May 2008 21:18:16 +0000</pubDate>
		<dc:creator>realazy</dc:creator>
				<category><![CDATA[JS / Dom]]></category>

		<guid isPermaLink="false">http://realazy.org/blog/2008/05/02/rte-basis/</guid>
		<description><![CDATA[富文本编辑器，Rich Text Editor, 简称 RTE, 它提供类似于 Microsoft Word 的编辑功能，容易被不会编写 HTML 的用户并需要设置各种文本格式的用户所喜爱。它的应用也越来越广泛。最先只有 IE 浏览器支持，其它浏览器相继跟进，在功能的丰富性来说，还是 IE 强些。虽然没有一个统一的标准，但对于最基本的功能，各浏览器提供的 API 基本一致，从而使编写一个跨浏览器的富文本编辑器成为可能。
在很多开发者看来，富文本编辑器的编写是一件很神秘或者复杂的事情。神秘倒没有，复杂的话，确实如此。但是它的基本原理并不复杂，入门也不难。今天我们的主题是讲述基本原理，并逐步演示一个简单富文本编辑器的产生。这是我在 D2 上的一个分享内容，在台上的演讲效果不佳，固写下来，希望能够对感兴趣的读者有所帮助。
富文本编辑器的基本原理
这个原理实在是太简单了！对于支持富文本编辑的浏览器来说，其实就是设置 document 的 designMode 属性为 on 后，再通过执行 document.execCommand('commandName'[, UIFlag[, value]]) 即可。commandName 和 value 可以在 MSDN 上和MDC 上找到，它们就是我们创建各种格式的命令，比方说，我们要加粗字体，执行 document.execCommand('bold', false) 即可。很简单是吧？但是值得注意的是，通常是选中了文本后才执行命令，被选中的文本才被格式化。对于未选中的文本进行这个命令，各浏览器有不同的处理方式，比方 IE 可能是对位于光标中的标签内容进行格式化，而其它浏览器不做任何处理，这超出本文的内容，不细述。同时需要注意的是，UIFlag 这个参数设置为 true 表示 display any user interface triggered by the command (if any), 在我们今天的教程中都是 false, [...]]]></description>
			<content:encoded><![CDATA[<p>富文本编辑器，Rich Text Editor, 简称 RTE, 它提供类似于 Microsoft Word 的编辑功能，容易被不会编写 HTML 的用户并需要设置各种文本格式的用户所喜爱。它的应用也越来越广泛。最先只有 IE 浏览器支持，其它浏览器相继跟进，在功能的丰富性来说，还是 IE 强些。虽然没有一个统一的标准，但对于最基本的功能，各浏览器提供的 API 基本一致，从而使编写一个跨浏览器的富文本编辑器成为可能。</p>
<p>在很多开发者看来，富文本编辑器的编写是一件很神秘或者复杂的事情。神秘倒没有，复杂的话，确实如此。但是它的基本原理并不复杂，入门也不难。今天我们的主题是讲述基本原理，并逐步演示一个简单富文本编辑器的产生。这是我在 <a href="http://www.d2forum.cn/">D2</a> 上的一个分享内容，在台上的演讲效果不佳，固写下来，希望能够对感兴趣的读者有所帮助。</p>
<h2>富文本编辑器的基本原理</h2>
<p>这个原理实在是太简单了！对于支持富文本编辑的浏览器来说，其实就是设置 <code>document</code> 的 <code>designMode</code> 属性为 <code>on</code> 后，再通过执行 <code>document.execCommand('commandName'[, UIFlag[, value]]) </code>即可。<code>commandName</code> 和 <code>value</code> 可以在 <a href="http://msdn.microsoft.com/en-us/library/ms533049(VS.85).aspx">MSDN 上</a>和<a href="http://developer.mozilla.org/en/docs/Rich-Text_Editing_in_Mozilla">MDC 上</a>找到，它们就是我们创建各种格式的命令，比方说，我们要加粗字体，执行 <code>document.execCommand('bold', false)</code> 即可。很简单是吧？但是值得注意的是，通常是选中了文本后才执行命令，被选中的文本才被格式化。对于未选中的文本进行这个命令，各浏览器有不同的处理方式，比方 IE 可能是对位于光标中的标签内容进行格式化，而其它浏览器不做任何处理，这超出本文的内容，不细述。同时需要注意的是，<code>UIFlag</code> 这个参数设置为 <code>true</code> 表示 display any user interface triggered by the command (if any), 在我们今天的教程中都是 <code>false</code>, 而 <code>value</code> 也只在某些 <code>commandName</code> 中才有，具体参考以上刚给出的两个链接。</p>
<p>为了不影响当前 <code>document</code>, 通常的做法是在页面中嵌入一个 <code>iframe</code> 元素，然后对这个 <code>iframe</code> 内的 <code>document</code>（通过 <code>iframe.contentWindow.document</code> 获得）进行操作。</p>
<p>十分简单，是吧？下面我们来动手做一个。</p>
<h2>编写一个简单的富文本编辑器</h2>
<p>这个例子使用了 <a href="http://developer.yahoo.com/yui/">YUI</a>. 即使你对它不是很熟悉也没有关系，我在这里只使用了它的 DOM 和 Event 的一些跨平台基本方法。</p>
<h3>搭架</h3>
<p>在此强调一下很久未曾提及的 unobtrusive. 我们的编辑器是对 <code>textarea</code> 元素的一个增强（enhencement），就是说，即使 JavaScript 被禁用了，用户还可以通过 <code>textarea</code> 编辑内容。</p>
<p>在这个例子中，我们将使用 <code>YAHOO.realazy</code> 的命名空间，在之下实现一个 <code>RTE</code> 的类。我们今天的编辑器很简单，因此构造器(constructor) 的参数也只有 <code>textarea</code> 一个。我们使用一个实例变量来保存工具条的各个项目。实例初始化放到一个叫 <code>render</code> 的方法中。这一步的页面和代码见<a href="http://realazy.org/lab/rte/1.html">第 1 步</a>。</p>
<h3>创建 <code>iframe</code> 并替换 <code>textarea</code></h3>
<p>搭好架子，正如我在前面所说，建立一个 <code>iframe</code>, 编辑器的所有操作都在 <code>iframe</code> 的 <code>document</code> 内执行。并且把 textarea 隐藏起来。从<a href="http://realazy.org/lab/rte/2.html">第 2 步</a>中可以看到，我们已经有了一个 <code>iframe</code>, 但不能输入任何东西，很正常，我们没有打开它的 <code>designMode</code> 嘛。</p>
<h3>开启 <code>designMode</code></h3>
<p>这一步涉及的东西挺多，也是关键。我们会创建获取 <code>iframe</code> 的 <code>document</code> 的方法，并通过程序的方式向 <code>iframe</code> 写入空页而非使用一个外接的 blank.html. 我们使用一个类属性 <code> YAHOO.realazy.RTE.htmlContent</code> 来保存空页的 <code>html</code>. 在准备好一切后，就可以开启 <code>designMode</code> 了。页面和代码详见<a href="http://realazy.org/lab/rte/3.html">第 3 步</a>。看，我们已经可以在 <code>iframe</code> 里输入东西了。</p>
<h3>构建工具条</h3>
<p>我们需要操作的工具条！这样才可以控制 <code>iframe</code> 里的内容，才能称之为编辑器。在此我并不打算实现太多的功能，只是选择字形、字号、加粗、斜体、下划线、居左、居中、居右、超链接和插图作为示例。对于跨平台，<a href="http://www.mozilla.org/editor/midas-spec.html">Mozilla Midas Specification </a>是不错的参考。ok, 请看<a href="http://realazy.org/lab/rte/4.html">第 4 步</a>，我们的工具条出来了，虽然很丑。我同时用 CSS 对 <code>iframe</code> 的宽度做出了一些调整。</p>
<h3>给工具条加上事件</h3>
<p>嗯，工具条出来了，编辑器看起来也“人模狗样”了，你兴奋的点啊点，没什么效果……意料中嘛。我们接着给工具条绑定一些事件，让编辑器内容能够响应工具条。在这一步，我们把 <code>execCommand</code> 再封一层，前面说过，我们用不上 <code>UIFlag</code>，让它永远是 <code>false</code> 好了。好，有代码就有真相，请看<a href="http://realazy.org/lab/rte/5.html">第 5 步</a>。如果是正使用 IE, 请先暂时转移到其它浏览器。看到了吧，工具条生效了！</p>
<h3>解决 IE 的问题</h3>
<p>well, 如果你没有听我的劝告，依然使用 IE, 你会发现除了字型和字号其它的都不能用。为什么呢？你观察一下，有没有发现，其它浏览器选择文本后，再点击工具条上的项目，被选中的文本是否依然选中的？而 IE 呢，在点击工具条时，选中的文本马上失去选中的状态，所以它们就失败了。所以，如果我们能够保证点击工具条文本保持选中状态，就可以解决 IE 的问题了。</p>
<p>Microsoft 给 HTML 标签一个很奇怪的属性 <code>unselectable</code>, 只要设置为 <code>on</code>, 焦点不会转移到点击的元素上，从而保证文本的选中状态。</p>
<p>请看<a href="http://realazy.org/lab/rte/6.html">第 6 步</a>。这也是解决 IE 头痛问题的关键所在。我曾经在这上面费了很大脑筋。</p>
<h2>高级主题展望</h2>
<p>good, 看看我们现在的代码，224 行。相比其它动辄上万行的编辑器，你可能会觉得不可思议。因为我们这个最基本的编辑器，连 <code>selection</code> 都没有用到。很多很酷的效果，比如 Google Doc 里能够动态改变链接文本，使用页内层而非弹出的 <code>prompt</code> 来操作等高级功能，基本上都要用到 <code>TextRange</code>(IE) 或者 <code>Range</code>(W3C). 要命的是这两个东西互补兼容，只是相似而已。入门推荐看PPK 的 <a href="http://www.quirksmode.org/dom/range_intro.html">Introduction to Range</a>.</p>
<p>在此我们就不深入了，等我有时间我会总结一些奇技淫巧（呜呼，前端开发需要的奇技淫巧太多了，这不是好事情）出来。</p>
]]></content:encoded>
			<wfw:commentRss>http://chen.xianan.name/blog/2008/05/02/rte-basis/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>JavaScript Memoization</title>
		<link>http://chen.xianan.name/blog/2008/04/22/javascript-memoization/</link>
		<comments>http://chen.xianan.name/blog/2008/04/22/javascript-memoization/#comments</comments>
		<pubDate>Tue, 22 Apr 2008 15:57:44 +0000</pubDate>
		<dc:creator>realazy</dc:creator>
				<category><![CDATA[JS / Dom]]></category>

		<guid isPermaLink="false">http://realazy.org/blog/2008/04/22/javascript-memoization/</guid>
		<description><![CDATA[Memoization 是一种将函数返回值缓存起来的方法，在 Lisp, Ruby, Perl, Python 等语言中使用非常广泛。随着 Ajax 的兴起，客户端对服务器的请求越来越密集（经典如 autocomplete），如果有一个良好的缓存机制，那么客户端 JavaScript 程序的效率的提升是显而易见的。
Memoization 原理非常简单，就是把函数的每次执行结果都放入一个散列表中，在接下来的执行中，在散列表中查找是否已经有相应执行过的值，如果有，直接返回该值，没有才真正执行函数体的求值部分。很明显，找值，尤其是在散列中找值，比执行函数快多了。现代 JavaScript 的开发也已经大量使用这种技术。
我通过 Google 寻找了好几种 JavaScript Memoization 的实现，都不太如人愿，有的实现不能缓存递归函数，有的需要修改函数的 prototype，于是自己实现一个：
/**
 * JavaScript Momoization
 * @param {string} func name of function / method
 * @param {object} [obj] mothed's object or scope correction object
 *
 * MIT / BSD license
 */

function Memoize(func, obj){
    [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://en.wikipedia.org/wiki/Memoization">Memoization</a> 是一种将函数返回值缓存起来的方法，在 Lisp, Ruby, Perl, Python 等语言中使用非常广泛。随着 Ajax 的兴起，客户端对服务器的请求越来越密集（经典如 autocomplete），如果有一个良好的缓存机制，那么客户端 JavaScript 程序的效率的提升是显而易见的。</p>
<p>Memoization 原理非常简单，就是把函数的每次执行结果都放入一个散列表中，在接下来的执行中，在散列表中查找是否已经有相应执行过的值，如果有，直接返回该值，没有才真正执行函数体的求值部分。很明显，找值，尤其是在散列中找值，比执行函数快多了。现代 JavaScript 的开发也已经大量使用这种技术。</p>
<p>我通过 Google <a href="http://www.google.com/search?hl=en&amp;hs=y9z&amp;q=JavaScript+Memoization">寻找</a>了好几种 JavaScript Memoization 的实现，都不太如人愿，有的实现不能缓存递归函数，有的需要修改函数的 <code>prototype</code>，于是自己实现一个：</p>
<pre><code>/**
 * JavaScript Momoization
 * @param {string} func name of function / method
 * @param {object} [obj] mothed's object or scope correction object
 *
 * MIT / BSD license
 */

function Memoize(func, obj){
    var obj = obj || window,
        func = obj[func],
        cache = {};
    return function(){
        <del>var key = Array.prototype.join.call(arguments, &quot;&quot;);</del>
        var key = Array.prototype.join.call(arguments, &quot;_&quot;)
        if (!(key in cache))
            cache[key] = func.apply(obj, arguments);
        return cache[key];
    }
}</code></pre>
<p>并写了一个测试案例，空口无凭，让大家亲自看看 Memoization 的威力。</p>
<p>见：<a href="http://realazy.org/lab/memoization.html">http://realazy.org/lab/memoization.html</a></p>
<p>另，例子中的 fibonacci 函数有很多更有效率的实现方法，在此我使用最无效率的递归实现，只是为了更直达地演示 memoization.</p>
<p>又，longwosion 留言所提到的 key 唯一性问题，我略作修正，但应该还有更好的办法，欢迎您留言探讨。</p>
]]></content:encoded>
			<wfw:commentRss>http://chen.xianan.name/blog/2008/04/22/javascript-memoization/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>测试 Google App Engine</title>
		<link>http://chen.xianan.name/blog/2008/04/11/google-app-engine-chatroom-demo/</link>
		<comments>http://chen.xianan.name/blog/2008/04/11/google-app-engine-chatroom-demo/#comments</comments>
		<pubDate>Fri, 11 Apr 2008 14:57:09 +0000</pubDate>
		<dc:creator>realazy</dc:creator>
				<category><![CDATA[JS / Dom]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://realazy.org/blog/2008/04/11/google-app-engine-chatroom-demo/</guid>
		<description><![CDATA[一不小心从某 blog 中第一时间发现 Google App Engine 发布，立马注册一个。当天晚上抽空看了看文档，做了做hello world，第二天晚上开始写一个聊天室程序，第三天晚上拿出 Python 技术手册，捣腾到今天才把一个简单的东西弄出来。去年学了一段时间的 Python, 还用 webpy 写了一个不成型的 blog 系统。某段时间认识自己不足，苦读了两个月的 C，后来买了 macbook, 又一头扎进 Objective-C 和 Cocoa, 哈哈哈，总之，一事无成吧。现在 GAE 出来了，突然发现一直寻找的 Python hosting 就这么从天上掉下来了，而且还是馅饼……重新激起 Python 兴趣，却发现又忘得差不多了……
废话太多了……这个测试 demo 叫 chatlazy, 位于 http://chatlazy.appspot.com. 是一个简易聊天室，后台部分，就是 Python 了，具体一点，是 webpy 0.3 (开发版，未发布)。机制十分简单，就是前端使用  JavaScript 隔 5 秒去提取后台的最新消息。有几个小细节还是值得总结一下的：

由于 GAE 的数据 ID 使不能用在 Gql 中的，我只能通过时间戳来比对消息状态。把 datetime 和秒数 ＋ [...]]]></description>
			<content:encoded><![CDATA[<p>一不小心从某 blog 中第一时间发现 Google App Engine 发布，立马注册一个。当天晚上抽空看了看文档，做了做hello world，第二天晚上开始写一个聊天室程序，第三天晚上拿出 <a href="http://www.oreilly.com.cn/book.php?bn=7-5641-0576-3">Python 技术手册</a>，捣腾到今天才把一个简单的东西弄出来。去年学了一段时间的 Python, 还用 <a href="http://webpy.org">webpy</a> 写了一个不成型的 blog 系统。某段时间认识自己不足，苦读了两个月的 C，后来买了 macbook, 又一头扎进 Objective-C 和 Cocoa, 哈哈哈，总之，一事无成吧。现在 GAE 出来了，突然发现一直寻找的 Python hosting 就这么从天上掉下来了，而且还是馅饼……重新激起 Python 兴趣，却发现又忘得差不多了……</p>
<p>废话太多了……这个测试 demo 叫 chatlazy, 位于 <a href="http://chatlazy.appspot.com">http://chatlazy.appspot.com</a>. 是一个简易聊天室，后台部分，就是 Python 了，具体一点，是 webpy 0.3 (开发版，未发布)。机制十分简单，就是前端使用  JavaScript 隔 5 秒去提取后台的最新消息。有几个小细节还是值得总结一下的：</p>
<ol>
<li>由于 GAE 的数据 ID 使不能用在 Gql 中的，我只能通过时间戳来比对消息状态。把 <code>datetime</code> 和秒数 ＋ 毫秒数的互转，还是比较繁琐的。Python 技术手册帮了我很大忙。解决方案大致如此：
<pre><code>str(time.mktime(d.timetuple()))[:-1] + str(d.microsecond)</code></pre>
<p>反过来则是：</p>
<pre><code>p = str(t).split('.')
tp = time.localtime(float(p[0]))
dt = datetime(tp[0], tp[1], tp[2], tp[3], tp[4], tp[5]+1, int(p[1]))</code></pre>
</li>
<li>对于 <code>iterable</code> 的对象, 先要 <code>list</code> 它转成列表，才可以使用 <code>reversed</code> 等相关方法。</li>
<li>需要取最新的 n 条信息，即数据库末尾的 n 条，但是又要顺序，可以先按逆序取 n 条，再反向排序（由此引发上条启示）。</li>
<li>对于任何用户输入的东西都要做过滤，一开始我在用户名那块忽略了，结果马上有人 XSS 了。这应该是基本常识，应铭记于心。</li>
<li>一定要处理异常。</li>
</ol>
<p>由于 GAE 这个天上掉的馅饼，我想我近期的精力会放到 Python 上了，有计划地把 blog 迁徙到 GAE 上，并开发一些有趣地程序。GAE rocks.  老实说，这是搜索、Gmail 后，对我而言可以排到第三的 Google 服务了。</p>
]]></content:encoded>
			<wfw:commentRss>http://chen.xianan.name/blog/2008/04/11/google-app-engine-chatroom-demo/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>认识延迟时间为 0 的 setTimeout</title>
		<link>http://chen.xianan.name/blog/2008/03/29/understand-0-settimeout/</link>
		<comments>http://chen.xianan.name/blog/2008/03/29/understand-0-settimeout/#comments</comments>
		<pubDate>Sat, 29 Mar 2008 13:24:00 +0000</pubDate>
		<dc:creator>realazy</dc:creator>
				<category><![CDATA[JS / Dom]]></category>

		<guid isPermaLink="false">http://realazy.org/blog/2008/03/29/understand-0-settimeout/</guid>
		<description><![CDATA[由 John Resig 的 How JavaScript Timers Work 可以知道，现有的 JavaScript 引擎是单线程处理任务的。它把任务放到队列中，不会同步去执行，必须在完成一个任务后才开始另外一个任务。
让我们看看我之前的文章：JavaScript的9个陷阱及评点，在第 9 点 Focus Pocus 中提到的问题。原作者对这个认识有所偏差，其实不只是 IE 的问题，而是现有 JavaScript 引擎对于线程实现的问题（关于线程，我的概念其实不多，如果不对，希望读者多多指教）。我们通过一个例子来说明，请访问 http://realazy.org/lab/settimeout.html. 我们来看 1 和 2。如果你能看看源代码，会发现我们的任务很简单，就是给文档增加一个 input 文本框，并聚焦和选中。请现在分别点击一下，可以看到，1 并没有能够聚焦和选中，而 2 可以。它们之间的区别在于，在执行
input.focus();
input.select();
时， 2 多了一个延迟时间为 0 的 setTimeout 的外围函数，即：
setTimeout(function(){
	input.focus();
	input.select();
}, 0);
按照 JavaScript: The Definitive Guide 5th 的 14.1 所说：

在实践中，setTimeout 会在其完成当前任何延宕事件的事件处理器的执行，以及完成文档当前状态更新后，告诉浏览器去启用 setTimeout 内注册的函数。

其实，这是一个把需要执行的任务从队列中跳脱的技巧。回到前面的例子，JavaScript 引擎在执行 onkeypress 时，由于没有多线程的同步执行，不可能同时去处理刚创建元素的 focus 和 select 事件，由于这两个事件都不在队列中，在完成 [...]]]></description>
			<content:encoded><![CDATA[<p>由 John Resig 的 <a href="http://ejohn.org/blog/how-javascript-timers-work/">How JavaScript Timers Work</a> 可以知道，现有的 JavaScript 引擎是单线程处理任务的。它把任务放到队列中，不会同步去执行，必须在完成一个任务后才开始另外一个任务。</p>
<p>让我们看看我之前的文章：<a href="http://realazy.org/blog/2007/08/20/nine-javascript-gotchas/">JavaScript的9个陷阱及评点</a>，在第 9 点 Focus Pocus 中提到的问题。原作者对这个认识有所偏差，其实不只是 IE 的问题，而是现有 JavaScript 引擎对于线程实现的问题（关于线程，我的概念其实不多，如果不对，希望读者多多指教）。我们通过一个例子来说明，请访问 <a href="http://realazy.org/lab/settimeout.html">http://realazy.org/lab/settimeout.html</a>. 我们来看 1 和 2。如果你能看看源代码，会发现我们的任务很简单，就是给文档增加一个 <code>input</code> 文本框，并聚焦和选中。请现在分别点击一下，可以看到，1 并没有能够聚焦和选中，而 2 可以。它们之间的区别在于，在执行</p>
<pre><code>input.focus();
input.select();</code></pre>
<p>时， 2 多了一个延迟时间为 0 的 <code>setTimeout</code> 的外围函数，即：</p>
<pre><code>setTimeout(function(){
	input.focus();
	input.select();
}, 0);</code></pre>
<p>按照 JavaScript: The Definitive Guide 5th 的 14.1 所说：</p>
<blockquote>
<p>在实践中，<code>setTimeout</code> 会在其完成当前任何延宕事件的事件处理器的执行，以及完成文档当前状态更新后，告诉浏览器去启用 <code>setTimeout</code> 内注册的函数。</p>
</blockquote>
<p>其实，这是一个把需要执行的任务从队列中跳脱的技巧。回到前面的例子，JavaScript 引擎在执行 <code>onkeypress</code> 时，由于没有多线程的同步执行，不可能同时去处理刚创建元素的 <code>focus</code> 和 <code>select</code> 事件，由于这两个事件都不在队列中，在完成 <code>onkeypress</code> 后，JavaScript 引擎已经丢弃了这两个事件，正如你看到的例子 1 的情况。而在例子 2 中，由于<code>setTimeout</code>可以把任务从某个队列中跳脱成为新队列，因而能够得到期望的结果。</p>
<p>这才是延迟事件为 0 的<code>setTimeout</code>的真正目的。在此，你可以看看例子 3，它的任务是实时更新输入的文本，现在请试试，你会发现预览区域总是落后一拍，比如你输 a, 预览区并没有出现 a, 在紧接输入 b 时， a 才不慌不忙地出现。其实我们是有办法让预览区跟输入框同步地，在此我没有给出答案，因为上面所说的，就是解决思路，try it yourself!</p>
]]></content:encoded>
			<wfw:commentRss>http://chen.xianan.name/blog/2008/03/29/understand-0-settimeout/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>《精通 JavaScript》上市</title>
		<link>http://chen.xianan.name/blog/2008/03/18/pro-js-techniques-chinese-version-published/</link>
		<comments>http://chen.xianan.name/blog/2008/03/18/pro-js-techniques-chinese-version-published/#comments</comments>
		<pubDate>Tue, 18 Mar 2008 13:55:37 +0000</pubDate>
		<dc:creator>realazy</dc:creator>
				<category><![CDATA[JS / Dom]]></category>

		<guid isPermaLink="false">http://realazy.org/blog/2008/03/18/pro-js-techniques-chinese-version-published/</guid>
		<description><![CDATA[去年跟 jjgod 一起翻译的书，《精通 JavaScript》 终于上市了。此书原名为 Pro JavaScript Techniques, 系 jQuery 之父 John Resig 所著。
这是一本没有 &#8220;hello world&#8221; 的书，在未翻译前我已经推荐过。希望窥探 JavaScript 高级应用的读者可以一读。推荐大家从网上购买，这样折扣多些。
如果你有任何想法，可以致信 projsch@gmail.com, 欢迎交流。
p.s. 最近更新不勤，一则工作忙，二则积蓄待发。自学 C 语言几月有余，略有小成。新近在看 Objective-C 和 Cocoa, 希望能开发些客户端程序。数据结构和算法依然在门外，一步一步来吧。God bless you, also me.
]]></description>
			<content:encoded><![CDATA[<p>去年跟 <a href="http://blog.jjgod.org">jjgod</a> 一起翻译的书，<strong><a href="http://realazy.org/jspro">《精通 JavaScript》</a></strong> 终于上市了。此书原名为 <a href="http://jspro.org/">Pro JavaScript Techniques</a>, 系 <a href="http://jquery.com">jQuery</a> 之父 <a href="http://ejohn.org">John Resig</a> 所著。</p>
<p>这是一本没有 &#8220;hello world&#8221; 的书，在未翻译前我已经<a href="http://realazy.org/blog/2007/01/03/pro-javascript-techniques-review/">推荐</a>过。希望窥探 JavaScript 高级应用的读者可以一读。推荐大家从网上购买，这样折扣多些。</p>
<p>如果你有任何想法，可以致信 projsch@gmail.com, 欢迎交流。</p>
<p>p.s. 最近更新不勤，一则工作忙，二则积蓄待发。自学 C 语言几月有余，略有小成。新近在看 Objective-C 和 Cocoa, 希望能开发些客户端程序。数据结构和算法依然在门外，一步一步来吧。God bless you, also me.</p>
]]></content:encoded>
			<wfw:commentRss>http://chen.xianan.name/blog/2008/03/18/pro-js-techniques-chinese-version-published/feed/</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>Bookmarklet</title>
		<link>http://chen.xianan.name/blog/2008/02/25/bookmarklet/</link>
		<comments>http://chen.xianan.name/blog/2008/02/25/bookmarklet/#comments</comments>
		<pubDate>Sun, 24 Feb 2008 16:04:19 +0000</pubDate>
		<dc:creator>realazy</dc:creator>
				<category><![CDATA[JS / Dom]]></category>

		<guid isPermaLink="false">http://realazy.org/blog/2008/02/25/bookmarklet/</guid>
		<description><![CDATA[按照维基的定义，A bookmarklet is an applet, a small computer application, stored as the URL of a bookmark in a web browser or as a hyperlink on a web page. 最近，它在一些新兴的网站中比较流行，比如 facebook, friendfeed. 从技术角度来看，它通常是一段来自提供方的可执行 JavaScript, 用以捕获当前网页的某些元素如标题、图片等以加强当前网页与提供方网站之间的交互。
那么，从技术角度来说，bookmarklet 有什么需要注意的呢？我个人意见如下：
首先，因为它是一段 JavaScript, 所以应该遵循普世的 JavaScript 编程原则。最重要的一点是，不要污染当前网页的命名空间，否则可能会破坏当前网页的 JavaScript. 通常，可以使用闭包来隐藏你所有的变量。同样，如果您的 bookmarklet 的 CSS 可能会入侵当前网页（很遗憾，CSS 没有命名空间，也没有类似闭包的东西，很容易就会冲突），那么请考虑将 bookmarklet 的内容放到 iframe 中去。
其次，防止函数执行后不经意的副作用，一个比较好用的贴士是，使用不返回值始终返回 undefined 的 void, 它可以接受任何参数，因此，把你的闭包放到 void [...]]]></description>
			<content:encoded><![CDATA[<p>按照维基的定义，<q cite="en.wikipedia.org/wiki/Bookmarklet">A bookmarklet is an applet, a small computer application, stored as the URL of a bookmark in a web browser or as a hyperlink on a web page</q>. 最近，它在一些新兴的网站中比较流行，比如 facebook, friendfeed. 从技术角度来看，它通常是一段来自提供方的可执行 JavaScript, 用以捕获当前网页的某些元素如标题、图片等以加强当前网页与提供方网站之间的交互。</p>
<p>那么，从技术角度来说，bookmarklet 有什么需要注意的呢？我个人意见如下：</p>
<p>首先，因为它是一段 JavaScript, 所以应该遵循普世的 JavaScript 编程原则。最重要的一点是，不要污染当前网页的命名空间，否则可能会破坏当前网页的 JavaScript. 通常，可以使用<a href="http://www.jibbering.com/faq/faq_notes/closures.html">闭包</a>来隐藏你所有的变量。同样，如果您的 bookmarklet 的 CSS 可能会入侵当前网页（很遗憾，CSS 没有命名空间，也没有类似闭包的东西，很容易就会冲突），那么请考虑将 bookmarklet 的内容放到 <code>iframe</code> 中去。</p>
<p>其次，防止函数执行后不经意的副作用，一个比较好用的贴士是，使用<del datetime="2008-02-25T03:01:48+00:00">不返回值</del>始终返回 <code>undefined</code> 的 <a href="http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Operators:Special_Operators:void_Operator"><code>void</code></a>, 它<strong>可以接受任何参数</strong>，因此，把你的闭包放到 <code>void</code> 中是个不错的主意：</p>
<pre><code>javascript:void((function(){...})());</code></pre>
<p>最后，有一个比较恼火的问题也需要加以注意。目前世界上最流行的浏览器，IE6, 它对 bookmarklet 所能容忍的长度仅为 <strong>508</strong>! </p>
]]></content:encoded>
			<wfw:commentRss>http://chen.xianan.name/blog/2008/02/25/bookmarklet/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>opera img onload重复执行</title>
		<link>http://chen.xianan.name/blog/2008/01/09/opera-img-onload-problem/</link>
		<comments>http://chen.xianan.name/blog/2008/01/09/opera-img-onload-problem/#comments</comments>
		<pubDate>Wed, 09 Jan 2008 07:51:43 +0000</pubDate>
		<dc:creator>realazy</dc:creator>
				<category><![CDATA[JS / Dom]]></category>

		<guid isPermaLink="false">http://realazy.org/blog/2008/01/09/opera-img-onload-problem/</guid>
		<description><![CDATA[由于某些原因需要把函数直接放到 img 标签上的 onload 属性执行，比如：
For some reasons we have to execute the JavaScript function in the img tag&#8217;s attribute onload, e.g.
&#60;img onload="javascript:jsFunction();" ...
开启 Opera, CPU 狂窜到 100%……
When using Opera browser, the CPU usage is up to 100%&#8230;
原来丫会重复执行 jsFunction……只好加个变量来记录是否已经执行。
Because Opera execute jsFunction repeatedly. The solution is adding an flag variable to track the function be executed [...]]]></description>
			<content:encoded><![CDATA[<p>由于某些原因需要把函数直接放到 <code>img</code> 标签上的 <code>onload</code> 属性执行，比如：</p>
<p>For some reasons we have to execute the JavaScript function in the <code>img</code> tag&#8217;s attribute <code>onload</code>, e.g.</p>
<pre><code>&lt;img onload="javascript:jsFunction();" ...</code></pre>
<p>开启 Opera, CPU 狂窜到 100%……</p>
<p>When using Opera browser, the CPU usage is up to 100%&#8230;</p>
<p>原来丫会重复执行 <code>jsFunction</code>……只好加个变量来记录是否已经执行。</p>
<p>Because Opera execute <code>jsFunction</code> repeatedly. The solution is adding an flag variable to track the function be executed or not.</p>
<p>Google 一下并没有发现这方面的资料，所以记下来，希望能帮助碰到这个问题的人。为了表现我的国际主义精神，特翻译了一下（至于这句，就不翻了……）。</p>
]]></content:encoded>
			<wfw:commentRss>http://chen.xianan.name/blog/2008/01/09/opera-img-onload-problem/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>JavaScript 数组的 uniq 方法</title>
		<link>http://chen.xianan.name/blog/2007/12/07/uniq-method-for-js-array/</link>
		<comments>http://chen.xianan.name/blog/2007/12/07/uniq-method-for-js-array/#comments</comments>
		<pubDate>Fri, 07 Dec 2007 09:10:11 +0000</pubDate>
		<dc:creator>realazy</dc:creator>
				<category><![CDATA[JS / Dom]]></category>

		<guid isPermaLink="false">http://realazy.org/blog/2007/12/07/uniq-method-for-js-array/</guid>
		<description><![CDATA[来自某个nb招聘的题目：
请给Array本地对象增加一个原型方法，它的用途是删除数组条目中重复的条目(可能有多个)，返回值是一个包含被删除的重复条目的新数组。这是我的答案：
新解
Array.prototype.uniq = function(){
    var resultArr = [],
        returnArr = [],
        i = 1,
        origLen = this.length,
        resultLen;
    function include(arr, value){
  [...]]]></description>
			<content:encoded><![CDATA[<p>来自某个nb招聘的题目：</p>
<p>请给Array本地对象增加一个原型方法，它的用途是删除数组条目中重复的条目(可能有多个)，返回值是一个包含被删除的重复条目的新数组。这是我的答案：</p>
<h2>新解</h2>
<pre><code>Array.prototype.uniq = function(){
    var resultArr = [],
        returnArr = [],
        i = 1,
        origLen = this.length,
        resultLen;
    function include(arr, value){
        for (var i=0, n=arr.length; i&lt;n; ++i){
            if (arr[i] === value){
                return true;
            }
        }
        return false;
    }
    resultArr.push(this[0]);
    for (i; i&lt;origLen; ++i){
        if (include(resultArr, this[i])){
            returnArr.push(this[i]);
        } else {
            resultArr.push(this[i]);
        }
    }
    resultLen = resultArr.length;
    this.length = resultLen;
    for (i=0; i&lt;resultLen; ++i){
        this[i] = resultArr[i];
    }
    return returnArr;
}</code></pre>
<p>这种解法在整个过程对原有数组的改变只有两次，效率比其他两种高了2个数量级左右！可<a href="http://realazy.org/lab/uniq.html">在此测试</a>三种解法的性能。</p>
<h2>旧解</h2>
<p>以下至“关于测试案例”之间皆为旧文，若阅读不顺，忽略之。</p>
<pre><code>Array.prototype.uniq_slow = function(){
    var ret = [],
        i = 0,
        j = 0;
    while (undefined !== this[i]){
        j = i + 1;
        while(undefined !== this[j]){
            if (this[i] === this[j]){
                ret.push(this.splice(j, 1)[0]);
            } else {
                ++j;
            }
        }
        ++i;
    }
    return ret;
}</code></pre>
<p>感谢猫仔提示，这道题目很容易让人产生误读。看清了题目后更新了。</p>
<p>为何用 <code>while</code> 而不是 <code>for</code>? 因为这个数组总是在变化，每次循环都得重新计算 <code>length</code>. 按理说，使用 <code>while</code> 效率会更高，尤其数组很大的时候。</p>
<p>欢迎大家交流讨论。</p>
<p>感谢 fdcn 提示，更新之。这里确实是容易犯错。</p>
<p>猜想由于强类型判断导致性能不高（可<a href="http://realazy.org/lab/uniq.html">在此测试</a>），因此此种做法未见有性能的提升（还稍微慢了一些），而且还不能传递类似 <code>[1,,,2,,]</code> 这样的数组。所以还是<a href="http://ued.taobao.com/blog/2007/11/20/job_test_explanation/">淘宝UED上的解法</a>比较科学（当然不是没有改进之处，比如不应该在 <code>for</code> 循环中声明变量）。</p>
<p>其实，这篇blog的意义在探讨如何避免无意义的消耗（比如计算 <code>length</code>）。但是鱼和熊掌不能兼得是自古之理，顾此失彼。当然，办法不是没有，比如数组的 <code>forEach</code>, <code>map</code> 方法等，可惜只有 <code>gecko</code> 浏览器才支持。</p>
<h2>关于测试案例</h2>
<p>数组是随机产生的1-100之间的整数，长度为5000，每个相同的大约重复5次。三个测试数组的元素构成是一致的。</p>
<h2>总结</h2>
<p>对数组的改变开销巨大，如果可能，尽量在不改变原有数组的情况下进行操作，如最终需要改变数组自身，可将结果赋予原有数组来操作。另外，对于 <code>length</code> 的计算，似乎效率并未受其影响。</p>
<p>啥时候我也该进补算法了，唉。软肋啊。</p>
<p><strong>推荐阅读：</strong> 王元涛同学的<a href="http://www.pkblogs.com/todwang/2007/12/javascript-uniq.html"> JavaScript 数组的 uniq 方法</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://chen.xianan.name/blog/2007/12/07/uniq-method-for-js-array/feed/</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>Opera下cloneNode的bug</title>
		<link>http://chen.xianan.name/blog/2007/11/22/opera-clonenode-bug/</link>
		<comments>http://chen.xianan.name/blog/2007/11/22/opera-clonenode-bug/#comments</comments>
		<pubDate>Thu, 22 Nov 2007 15:26:43 +0000</pubDate>
		<dc:creator>realazy</dc:creator>
				<category><![CDATA[JS / Dom]]></category>

		<guid isPermaLink="false">http://realazy.org/blog/2007/11/22/opera-clonenode-bug/</guid>
		<description><![CDATA[Opera, 作为 A-Grade 浏览器，在现在的前端开发中务必支持。它很优秀，很不幸，bug是每个浏览器都不可避免的问题，Opera亦难免。说说我发现的一个关于 cloneNode 的问题。
问题
假设我们有一个 Form 节点（node）的引用，姑且名之为 elForm，现在需要克隆一份，可以这么做：var elFormClone = elForm.cloneNode(true). 
在插入这份克隆到 DOM 树中后，IE, Firefox 均未发现问题。Opera会产生这样的问题：表单内的字段无法引用。比如，假设刚才我们的elForm 有一个 &#60;input name="title" ... /&#62;, 此时你无法通过 elFormClone.title 或者 elFormClone['title'] 获取它。
解决方案
使用 document.createElement 创建 form 元素，然后设置该元素的 innerHTML(感谢 MS 发明了它) 为elForm 的 innerHTML 即可：
var elFormClone = document.createElement('form');
// 设置一些elForm的原属性，有必要的话
...
elFormClone.innerHTML = elForm.innerHTML;
// 处理这个clone, 该咋办就咋办了
...
]]></description>
			<content:encoded><![CDATA[<p>Opera, 作为 <a href="http://developer.yahoo.com/yui/articles/gbs/#gbschart">A-Grade</a> 浏览器，在现在的前端开发中务必支持。它很优秀，很不幸，bug是每个浏览器都不可避免的问题，Opera亦难免。说说我发现的一个关于 <code>cloneNode</code> 的问题。</p>
<h2>问题</h2>
<p>假设我们有一个 Form 节点（node）的引用，姑且名之为 <code>elForm</code>，现在需要克隆一份，可以这么做：<code>var elFormClone = elForm.cloneNode(true)</code>. </p>
<p>在插入这份克隆到 DOM 树中后，IE, Firefox 均未发现问题。Opera会产生这样的问题：表单内的字段无法引用。比如，假设刚才我们的<code>elForm</code> 有一个 <code>&lt;input name="title" ... /&gt;</code>, 此时你无法通过 <code>elFormClone.title</code> 或者 <code>elFormClone['title']</code> 获取它。</p>
<h2>解决方案</h2>
<p>使用 <code>document.createElement</code> 创建 form 元素，然后设置该元素的 <code>innerHTML</code>(感谢 MS 发明了它) 为<code>elForm</code> 的 <code>innerHTML</code> 即可：</p>
<pre><code>var elFormClone = document.createElement('form');
// 设置一些elForm的原属性，有必要的话
...
elFormClone.innerHTML = elForm.innerHTML;
// 处理这个clone, 该咋办就咋办了
...</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://chen.xianan.name/blog/2007/11/22/opera-clonenode-bug/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
