nicEdit 中文版April 1, 2008

Typecho 的项目已经启动。小组需要个功能强大而且小巧,并且容易 Hack 的 Javascript 编辑器。我首先想到的是 FCKEditor 以及 TinyMCE 。

FCKEditor 功能虽然强大、插件众多,但代码量和占用的客户端的资源也是巨大的。 TinyMCE 相对小巧,功能方面也并不弱,不过其使用协议还是很多不明确的地方。

sluck 以及 joyqi 兄弟的推荐下,尝试使用一款名为 nicEdit 的编辑器,基本上表示满意。

功能方面,nicEdit 已经满足了基本编辑器的需求。而我关注的代码方面,它也是非常精简的。整个编辑器就是声明了个大的 nicEdit 的类(非常的环保),扩展起来非常的容易。

推荐对 Javascript 有兴趣,并且想了解编辑器原理的朋友可以看下它的代码,收获会良多。最后,在看其代码的同时,顺便汉化了下,汉化以后的包可以在 这里下载

同时,也可以先看下我 Blog 上面扔的 DEMO

http://lab.gracecode.com/historic/demo/nicEdit/

不要忘记跨域 iframe 的载入情况April 1, 2008

在编写某个 跨域的 Ajax 调用 功能时,出现了个匪夷所思的问题,就是无法载入 iframe 中的连接器(YAHOO.util.Connect),代码和操作无任何的问题。

在麻烦了 圆心 同志 N 遍以后,发现原来是 iframe 没有完全载入,框架中的代码没有运行的缘故。(在这里再次感谢下他,Orz)

这的确是个非常普遍的问题,由于网速的缘故,往往父页面载入完成,而 iframe 中的内容还正在读取。这个时候,父页面调用子页面中的对象时,就会发生问题。

我想到了个变通的办法,就是「等待」子页面载入完成以后,再去尝试运行。如果子页面还没有载入相应的对象,那么就「再等待」一段时间再去尝试。

可能表述上有所欠缺,我们还是看具体的代码。

为了理解,首先说明已经在 HTML 中已经包含了此 iframe,并子页面中也包含了 YUI 的框架代码及相应的控件。

<iframe src="http://.../proxy.htm" id="proxy"></iframe>

下面是相应的 Javascript 代码

var proxy = $('proxy').contentWindow;
Controler.disable = true;  // 获取数据此段期间,禁止用户输入
if (typeof proxy.YAHOO == 'undefined') {
    // 等待一段时间再去尝试,Function 为父类的名称
    setTimeout(function() {Function.get(URL)}, 100); 
    return;
}

// 已经得到子页面对象,获取数据
proxy.YAHOO.util.Connect.asyncRequest('GET', URL, {
    success: function(req) {
        alert(req.responseText);
        Controler.disable = false; // 恢复用户输入
    },

    failure: function() {
        return false;
    }
});

不过这个代码还有很多的问题,目前所能预见到的,就是客户端的资源占用问题。可想而知,如果反复的请求数据对于浏览器来说,资源花销将是非常大的。

大家如果有更好的办法,不妨说说。

YUI 读码日记之 YAHOO.util.Dom - Part.4March 8, 2008

YAHOO.util.Dom 中的 getXY 函数让开发者充分体验到不同浏览器的 Hack 的乐趣。 IE8 即将破壳而出,但愿下面的函数不会又多个 if 判断。getXY 函数使用 匿名函数执行返回 函数(听起来有点拗口,可以参考 圆心 Blog 上的 一篇文章 )。

var getXY = function() {
    // 判断是否是 IE
    if (document.documentElement.getBoundingClientRect) {
        // 注1
        return function(el) {
            var box = el.getBoundingClientRect();

            var rootNode = el.ownerDocument;
            return [box.left + 
          Y.Dom.getDocumentScrollLeft(rootNode), box.top +
                    Y.Dom.getDocumentScrollTop(rootNode)];
        };
    } else {
        return function(el) {
            var pos = [el.offsetLeft, el.offsetTop];
            var parentNode = el.offsetParent;

            // 判断是否在 Safari 下,节点是否为 absolute ,
            // 并且父元素是否为 body
            // 注2.
            var accountForBody = (isSafari &&
                    Y.Dom.getStyle(el, 'position') == 'absolute' &&
                    el.offsetParent == el.ownerDocument.body);

            // 如果父元素不是自身
            if (parentNode != el) {
                while (parentNode) {
                    pos[0] += parentNode.offsetLeft;
                    pos[1] += parentNode.offsetTop;
                    if (!accountForBody && isSafari && 
                            Y.Dom.getStyle(parentNode,'position') 
                                                  == 'absolute' ) { 
                        accountForBody = true;
                    }
                    parentNode = parentNode.offsetParent;
                }
            }

            // 还是针对 Safari 的
            if (accountForBody) { //safari doubles in this case
                pos[0] -= el.ownerDocument.body.offsetLeft;
                pos[1] -= el.ownerDocument.body.offsetTop;
            } 
            parentNode = el.parentNode;

            // account for any scrolled ancestors
            while ( parentNode.tagName && 
                         !patterns.ROOT_TAG.test(parentNode.tagName) ) 
            {
               // work around opera inline/table scrollLeft/Top bug
               // 注3.
               if (Y.Dom.getStyle(parentNode, 'display')
                                  .search(/^inline|table-row.*$/i)) { 
                    pos[0] -= parentNode.scrollLeft;
                    pos[1] -= parentNode.scrollTop;
                }
                
                parentNode = parentNode.parentNode; 
            }

            return pos;
        };
    }
}() // NOTE: Executing for loadtime branching
  1. 注. 有关 IE 的 getBoundingClientRect 方法,可以 参考这里
  2. 注. Safari 的 BUG,详细情况 参见这里
  3. 注. 参见老外的原话( 出处 ):
"- Remove parent scroll UNLESS that parent is inline or a table 
to work around Opera inline/table scrollLeft/Top bug"
Fixed in Opera 9.5. (also, Opera 9.5 supports getBoundingClientRect 
and getClientRects.)

最后,有关更多 DOM 的兼容性,可以参看 PPK 的总结怎么又是他 )。

Yahoo 统计