<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    JAVA & XML & JAVASCRIPT & AJAX & CSS

    Web 2.0 技術儲備............

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      77 隨筆 :: 17 文章 :: 116 評論 :: 0 Trackbacks

    ?

    /*
    ?*?定義一個全局對象,?屬性?Version?在發布的時候會替換為當前版本號
    ?
    */
    var ?Prototype? = ?{
    ??Version:?'
    1.3 . 1 ',
    ??
    // ?一個空方法,其后的代碼常會用到,先前的版本該方法被定義于?Ajax?類中。
    ??emptyFunction:? function ()?{}
    }

    /*
    ?*?創建一種類型,注意其屬性?create?是一個方法,返回一個構造函數。
    ?*?一般使用如下?
    ?*?????var?X?=?Class.create();??返回一個類型,類似于?java?的一個Class實例。
    ?*?要使用?X?類型,需繼續用?new?X()來獲取一個實例,如同?java?的?Class.newInstance()方法。
    ?*
    ?*?返回的構造函數會執行名為?initialize?的方法,?initialize?是?Ruby?對象的構造器方法名字。
    ?*?此時initialize方法還沒有定義,其后的代碼中創建新類型時會建立相應的同名方法。
    ?*
    ?*?如果一定要從java上去理解。你可以理解為用Class.create()創建一個繼承java.lang.Class類的類。
    ?*?當然java不允許這樣做,因為Class類是final的
    ?*
    ?
    */
    var ?Class? = ?{
    ??create:?
    function ()?{
    ????
    return ? function ()?{
    ??????
    this .initialize.apply( this ,?arguments);
    ????}
    ??}
    }

    /*
    ?*?創建一個對象,從變量名來思考,本意也許是定義一個抽象類,以后創建新對象都?extend?它。
    ?*?但從其后代碼的應用來看,?Abstract?更多是為了保持命名空間清晰的考慮。
    ?*?也就是說,我們可以給?Abstract?這個對象實例添加新的對象定義。
    ?*
    ?*?從java去理解,就是動態給一個對象創建內部類。
    ?
    */
    var ?Abstract? = ? new ?Object();

    Object.extend?
    = ? function (destination,?source)?{
    ??
    for ?(property? in ?source)?{
    ????destination[property]?
    = ?source[property];
    ??}
    ??
    return ?destination;
    }

    /*
    ?*?獲取參數對象的所有屬性和方法,有點象多重繼承。但是這種繼承是動態獲得的。
    ?*?如:
    ?*?????var?a?=?new?ObjectA(),?b?=?new?ObjectB();
    ?*?????var?c?=?a.extend(b);
    ?*?此時?c?對象同時擁有?a?和?b?對象的屬性和方法。但是與多重繼承不同的是,c?instanceof?ObjectB?將返回false。
    ?*
    ?*?舊版本的該方法定義如下:
    ?*?Object.prototype.extend?=?function(object)?{
    ?*?????for?(property?in?object)?{
    ?*?????????this[property]?=?object[property];
    ?*?????}
    ?*?????return?this;
    ?*?}
    ?*
    ?*?新的形式新定義了一個靜態方法?Object.extend,這樣做的目的大概是為了使代碼更為清晰
    ?
    */
    Object.prototype.extend?
    = ? function (object)?{
    ??
    return ?Object.extend.apply( this ,?[ this ,?object]);
    }

    /*
    ?*?這個方法很有趣,它封裝一個javascript函數對象,返回一個新函數對象,新函數對象的主體和原對象相同,
    ?*?但是bind()方法參數將被用作當前對象的對象。
    ?*?也就是說新函數中的?this?引用被改變為參數提供的對象。
    ?*?比如:
    ?*?????<input?type="text"?id="aaa"?value="aaa">
    ?*?????<input?type="text"?id="bbb"?value="bbb">
    ?*?????..
    ?*?????<script>
    ?*?????????var?aaa?=?document.getElementById("aaa");
    ?*?????????var?bbb?=?document.getElementById("bbb");
    ?*?????????aaa.showValue?=?function()?{alert(this.value);}
    ?*?????????aaa.showValue2?=?aaa.showValue.bind(bbb);
    ?*?????</script>
    ?*?那么,調用aaa.showValue?將返回"aaa",?但調用aaa.showValue2?將返回"bbb"。
    ?*
    ?*?apply?是ie5.5后才出現的新方法(Netscape好像很早就支持了)。
    ?*?該方法更多的資料參考MSDN?http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthApply.asp
    ?*?閱讀其后的代碼就會發現,bind?被應用的很廣泛,該方法和?Object.prototype.extend?一樣是?Prototype?的核心。
    ?*?還有一個?call?方法,應用起來和?apply?類似。可以一起研究下。
    ?
    */
    Function.prototype.bind?
    = ? function (object)?{
    ??
    var ?__method? = ? this ;
    ??
    return ? function ()?{
    ????__method.apply(object,?arguments);
    ??}
    }

    /*
    ?*?和bind一樣,不過這個方法一般用做html控件對象的事件處理。所以要傳遞event對象
    ?*?注意這時候,用到了?Function.call。它與?Function.apply?的不同好像僅僅是對參數形式的定義。
    ?*?如同?java?兩個過載的方法。
    ?
    */
    Function.prototype.bindAsEventListener?
    = ? function (object)?{
    ??
    var ?__method? = ? this ;
    ??
    return ? function (event)?{
    ????__method.call(object,?event?
    || ?window.event);
    ??}
    }

    /*
    ?*?將整數形式RGB顏色值轉換為HEX形式
    ?
    */
    Number.prototype.toColorPart?
    = ? function ()?{
    ??
    var ?digits? = ? this .toString( 16 );
    ??
    if ?( this ? < ? 16 )? return ?' 0 '? + ?digits;
    ??
    return ?digits;
    }

    /*
    ?*?典型?Ruby?風格的函數,將參數中的方法逐個調用,返回第一個成功執行的方法的返回值
    ?
    */
    var ?Try? = ?{
    ??these:?
    function ()?{
    ????
    var ?returnValue;

    ????
    for ?( var ?i? = ? 0 ;?i? < ?arguments.length;?i ++ )?{
    ??????
    var ?lambda? = ?arguments[i];
    ??????
    try ?{
    ????????returnValue?
    = ?lambda();
    ????????
    break ;
    ??????}?
    catch ?(e)?{}
    ????}

    ????
    return ?returnValue;
    ??}
    }

    /* ======================================================= */

    /*
    ?*?一個設計精巧的定時執行器
    ?*?首先由?Class.create()?創建一個?PeriodicalExecuter?類型,
    ?*?然后用對象直接量的語法形式設置原型。
    ?*
    ?*?需要特別說明的是?rgisterCallback?方法,它調用上面定義的函數原型方法bind,?并傳遞自己為參數。
    ?*?之所以這樣做,是因為?setTimeout?默認總以?window?對象為當前對象,也就是說,如果?registerCallback?方法定義如下的話:
    ?*?????registerCallback:?function()?{
    ?*?????????setTimeout(this.onTimerEvent,?this.frequency?*?1000);
    ?*?????}
    ?*?那么,this.onTimeoutEvent?方法執行失敗,因為它無法訪問?this.currentlyExecuting?屬性。
    ?*?而使用了bind以后,該方法才能正確的找到this,也就是PeriodicalExecuter的當前實例。
    ?
    */
    var ?PeriodicalExecuter? = ?Class.create();
    PeriodicalExecuter.prototype?
    = ?{
    ??initialize:?
    function (callback,?frequency)?{
    ????
    this .callback? = ?callback;
    ????
    this .frequency? = ?frequency;
    ????
    this .currentlyExecuting? = ? false ;

    ????
    this .registerCallback();
    ??},

    ??registerCallback:?
    function ()?{
    ????setInterval(
    this .onTimerEvent.bind( this ),? this .frequency? * ? 1000 );
    ??},

    ??onTimerEvent:?
    function ()?{
    ????
    if ?( ! this .currentlyExecuting)?{
    ??????
    try ?{
    ????????
    this .currentlyExecuting? = ? true ;
    ????????
    this .callback();
    ??????}?
    finally ?{
    ????????
    this .currentlyExecuting? = ? false ;
    ??????}
    ????}
    ??}
    }

    /* ======================================================= */

    /*
    ?*?這個函數就?Ruby?了。我覺得它的作用主要有兩個
    ?*?1.??大概是?document.getElementById(id)?的最簡化調用。
    ?*?比如:$("aaa")?將返回?aaa?對象
    ?*?2.??得到對象數組
    ?*?比如:?$("aaa","bbb")?返回一個包括id為"aaa"和"bbb"兩個input控件對象的數組。
    ?
    */
    function ?$()?{
    ??
    var ?elements? = ? new ?Array();

    ??
    for ?( var ?i? = ? 0 ;?i? < ?arguments.length;?i ++ )?{
    ????
    var ?element? = ?arguments[i];
    ????
    if ?( typeof ?element? == ?'string')
    ??????element?
    = ?document.getElementById(element);

    ????
    if ?(arguments.length? == ? 1 )
    ??????
    return ?element;

    ????elements.push(element);
    ??}

    ??
    return ?elements;
    }

    /*
    ?*?為兼容舊版本的瀏覽器增加?Array?的?push?方法。
    ?
    */
    if ?( ! Array.prototype.push)?{
    ??Array.prototype.push?
    = ? function ()?{
    ??????
    var ?startLength? = ? this .length;
    ??????
    for ?( var ?i? = ? 0 ;?i? < ?arguments.length;?i ++ )
    ??????
    this [startLength? + ?i]? = ?arguments[i];
    ?????
    return ? this .length;
    ??}
    }

    /*
    ?*?為兼容舊版本的瀏覽器增加?Function?的?apply?方法。
    ?
    */
    if ?( ! Function.prototype.apply)?{
    ??
    // ?Based?on?code?from?http://www.youngpup.net/
    ??Function.prototype.apply? = ? function (object,?parameters)?{
    ????
    var ?parameterStrings? = ? new ?Array();
    ????
    if ?( ! object)?????object? = ?window;
    ????
    if ?( ! parameters)?parameters? = ? new ?Array();
    ???
    ????
    for ?( var ?i? = ? 0 ;?i? < ?parameters.length;?i ++ )
    ??????parameterStrings[i]?
    = ?'parameters['? + ?i? + ?']';
    ???
    ????object.__apply__?
    = ? this ;
    ????
    var ?result? = ?eval('object.__apply__('? +
    ??????parameterStrings.join(',?')?
    + ?')');
    ????object.__apply__?
    = ? null ;
    ???
    ????
    return ?result;
    ??}
    }

    /*
    ?*?擴展?javascript?內置的?String?對象
    ?
    */
    String.prototype.extend({

    /*
    ?*去掉字符串中的<html>標簽
    ?
    */
    ??stripTags:?
    function ()?{
    ????
    return ? this .replace( /< \ /? [ ^> ] +>/ gi,?'');
    ??},

    /*
    ?*這個方法很常見,通常的實現都是用正則表達式替換特殊字符為html規范定義的命名實體或者十進制編碼,比如:
    ?*?string.replace(/&/g,?"&amp;").replace(/</g,?"&lt;").replace(/>/g,?"&gt;");
    ?*?而這里的實現借用瀏覽器自身的內部替換,確實巧妙。
    ?
    */
    ??escapeHTML:?
    function ()?{
    ????
    var ?div? = ?document.createElement('div');
    ????
    var ?text? = ?document.createTextNode( this );
    ????div.appendChild(text);
    ????
    return ?div.innerHTML;
    ??},
    ?
    /*
    ?*同上
    ?
    */
    ??unescapeHTML:?
    function ()?{
    ????
    var ?div? = ?document.createElement('div');
    ????div.innerHTML?
    = ? this .stripTags();
    ????
    return ?div.childNodes[ 0 ].nodeValue;
    ??}
    });

    /*
    ?*?定義?Ajax?對象,?靜態方法?getTransport?方法返回一個?XMLHttp?對象
    ?
    */
    var ?Ajax? = ?{
    ??getTransport:?
    function ()?{
    ????
    return ?Try.these(
    ??????
    function ()?{ return ? new ?ActiveXObject('Msxml2.XMLHTTP')},
    ??????
    function ()?{ return ? new ?ActiveXObject('Microsoft.XMLHTTP')},
    ??????
    function ()?{ return ? new ?XMLHttpRequest()}
    ????)?
    || ? false ;
    ??}
    }

    /*
    ?*?我以為此時的Ajax對象起到命名空間的作用。
    ?*?Ajax.Base?聲明為一個基礎對象類型
    ?*?注意?Ajax.Base?并沒有使用?Class.create()?的方式來創建,我想是因為作者并不希望?Ajax.Base?被庫使用者實例化。
    ?*?作者在其他對象類型的聲明中,將會繼承于它。
    ?*?就好像?java?中的私有抽象類
    ?
    */
    Ajax.Base?
    = ? function ()?{};
    Ajax.Base.prototype?
    = ?{
    /*
    ?*extend?(見上)?的用法真是讓人耳目一新
    ?*?options?首先設置默認屬性,然后再?extend?參數對象,那么參數對象中也有同名的屬性,那么就覆蓋默認屬性值。
    ?*?想想如果我寫這樣的實現,應該類似如下:
    ?????setOptions:?function(options)?{
    ??????this.options.methed?=?options.methed??options.methed?:?'post';
    ??????.
    ?????}
    ?????我想很多時候,java?限制了?js?的創意。
    ?
    */
    ??setOptions:?
    function (options)?{
    ????
    this .options? = ?{
    ??????method:???????'post',
    ??????asynchronous:?
    true ,
    ??????parameters:???''
    ????}.extend(options?
    || ?{});
    ??},
    ?
    /*
    ?*如果 xmlhttp?調用返回正確的HTTP狀態值,函數返回ture, 反之false。
    ?*?xmlhttp 的?readyState?屬性不足以準確判斷?xmlhttp 遠程調用成功,該方法是readyState判斷的一個前提條件
    ?
    */
    ??responseIsSuccess:?
    function ()?{
    ????
    return ? this .transport.status? == ?undefined
    ????????
    || ? this .transport.status? == ? 0
    ????????
    || ?( this .transport.status? >= ? 200 ? && ? this .transport.status? < ? 300 );
    ??},
    ?
    /*
    ?*如果 xmlhttp?調用返回錯誤的HTTP狀態值,函數返回ture, 反之false。
    ?
    */
    ??responseIsFailure:?
    function ()?{
    ????
    return ? ! this .responseIsSuccess();
    ??}
    }

    /*
    ?*?Ajax.Request?封裝?XmlHttp
    ?
    */
    Ajax.Request?
    = ?Class.create();

    /*
    ?*?定義四種事件(狀態),?參考http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/readystate_1.asp
    ?
    */
    Ajax.Request.Events?
    =
    ??['Uninitialized',?'Loading',?'Loaded',?'Interactive',?'Complete'];

    /*
    ?* 相比先前的版本,對于 xmlhttp?的調用和返回值處理分離得更為清晰
    ?
    */
    Ajax.Request.prototype?
    = ?( new ?Ajax.Base()).extend({
    ??initialize:?
    function (url,?options)?{
    ????
    this .transport? = ?Ajax.getTransport();
    ????
    this .setOptions(options);
    ????
    this .request(url);
    ??},

     
    /*
    ?*新增加?request?方法封裝?xmlhttp 的調用過程。
    ?
    */
    ??request:?
    function (url)?{
    ????
    var ?parameters? = ? this .options.parameters? || ?'';
    ????
    if ?(parameters.length? > ? 0 )?parameters? += ?' & _ = ';

    ????
    try ?{
    ??????
    if ?( this .options.method? == ?'get')
    ????????url?
    += ?' ? '? + ?parameters;

    ??????
    this .transport.open( this .options.method,?url,
    ????????
    this .options.asynchronous);

    ??????
    if ?( this .options.asynchronous)?{
    ????????
    this .transport.onreadystatechange? = ? this .onStateChange.bind( this );
    ????????setTimeout((
    function ()?{ this .respondToReadyState( 1 )}).bind( this ),? 10 );
    ??????}

    ??????
    this .setRequestHeaders();

    ??????
    var ?body? = ? this .options.postBody? ? ? this .options.postBody?:?parameters;
    ??????
    this .transport.send( this .options.method? == ?'post'? ? ?body?:? null );

    ????}?
    catch ?(e)?{
    ????}
    ??},

    /*
    ?*新增加的?setRequestHeaders?方法允許添加自定義的http?header
    ?
    */
    ??setRequestHeaders:?
    function ()?{
    ????
    var ?requestHeaders? =
    ??????['X
    - Requested - With',?'XMLHttpRequest',
    ???????'X
    - Prototype - Version',?Prototype.Version];

    ????
    if ?( this .options.method? == ?'post')?{
    ??????requestHeaders.push('Content
    - type',
    ????????'application
    / x - www - form - urlencoded');

    /* ?Force?"Connection:?close"?for?Mozilla?browsers?to?work?around
    ?*?a?bug?where?XMLHttpReqeuest?sends?an?incorrect?Content-length
    ?*?header.?See?Mozilla?Bugzilla?#246651.
    ?
    */
    ??????
    if ?( this .transport.overrideMimeType)
    ????????requestHeaders.push('Connection',?'close');
    ????}

    /*
    ?*?其后的?apply?方法的調用有些奇技淫巧的意味
    ?*?從上下文中我們可以分析出?this.options.requestHeaders?是調用者自定義的http?header數組。
    ?*?requestHeaders?也是一個數組,將一個數組中的元素逐個添加到另一個元素中,直接調用
    ?*?requestHeaders.push(this.options.requestHeaders)
    ?*?是不行的,因為該調用導致?this.options.requestHeaders?整個數組作為一個元素添加到?requestHeaders中。
    ?*?javascript的Array對象還提供一個concat?的方法表面上滿足要求,但是concat實際上是創建一個新數組,將兩個數組的元素添加到新數組中。
    ?*?所以,下面的代碼也可以替換為
    ?*?requestHeaders?=?requestHeaders.concat(this.options.requestHeaders);
    ?*?很顯然,作者不喜歡這樣的代碼方式
    ?*?而?apply?方法的語法?apply([thisObj[,argArray]])?本身就要求第二個參數是一個數組或者arguments對象。
    ?*?所以巧妙的實現了?concat?函數的作用。
    ?*?令人拍案叫絕啊!
    ?
    */
    ????
    if ?( this .options.requestHeaders)
    ??????requestHeaders.push.apply(requestHeaders,?
    this .options.requestHeaders);

    ????
    for ?( var ?i? = ? 0 ;?i? < ?requestHeaders.length;?i? += ? 2 )
    ??????
    this .transport.setRequestHeader(requestHeaders[i],?requestHeaders[i + 1 ]);
    ??},

    ?
    ??onStateChange:?
    function ()?{
    ????
    var ?readyState? = ? this .transport.readyState;
    /*
    ?*?如果不是?Loading?狀態,就調用回調函數
    ?
    */
    ????
    if ?(readyState? != ? 1 )
    ??????
    this .respondToReadyState( this .transport.readyState);
    ??},

    /*
    ?*回調函數定義在?this.options?屬性中,比如:
    ??????var?option?=?{
    ?????????onLoaded?:?function(req)?{};
    ?????????
    ??????}
    ??????new?Ajax.Request(url,?option);
    ?
    */
    ??respondToReadyState:?
    function (readyState)?{
    ????
    var ?event? = ?Ajax.Request.Events[readyState];

    /*
    ?*?新增的回調函數處理,調用者還可以在options中定義?on200,?onSuccess?這樣的回調函數
    ?*?在?readyState?為完成狀態的時候調用
    ?
    */
    ????
    if ?(event? == ?'Complete')
    ??????(
    this .options['on'? + ? this .transport.status]
    ???????
    || ? this .options['on'? + ?( this .responseIsSuccess()? ? ?'Success'?:?'Failure')]
    ???????
    || ?Prototype.emptyFunction)( this .transport);

    ????(
    this .options['on'? + ?event]? || ?Prototype.emptyFunction)( this .transport);

    /* ?Avoid?memory?leak?in?MSIE:?clean?up?the?oncomplete?event?handler? */
    ????
    if ?(event? == ?'Complete')
    ??????
    this .transport.onreadystatechange? = ?Prototype.emptyFunction;
    ??}
    });

    /*
    ?*?Ajax.Updater?用于綁定一個html元素與?XmlHttp調用的返回值。類似與?buffalo?的?bind。
    ?*?如果?options?中有?insertion(見后)?對象的話,?insertion?能提供更多的插入控制。
    ?
    */
    Ajax.Updater?
    = ?Class.create();
    Ajax.Updater.ScriptFragment?
    = ?'( ? : < script. *?> )((\n | .) *? )( ? : < \ / script > )';

    Ajax.Updater.prototype.extend(Ajax.Request.prototype).extend({
    ??initialize:?
    function (container,?url,?options)?{

    /*
    ?*?containers?就是被綁定的?html?對象,xmlhttp的返回值被賦給該對象的?innerHTML?屬性。
    ?*?相比新版本,containers?根據container參數定義?success?和?failure?引用,如果它們被定義的話,根據xmlhttp調用是否成功來選擇
    ?*?更新對象,假想調用可能如下:
    ?*?var?c?=?{success:?$("successDiv"),?failure:?$("failureDiv")};
    ?*?new?Ajax.Updater(c,?url,?options);
    ?*?那么調用成功則?successDiv?顯示成功信息或者數據,反之?failureDiv?顯示錯誤信息
    ?
    */
    ????
    this .containers? = ?{
    ??????success:?container.success?
    ? ?$(container.success)?:?$(container),
    ??????failure:?container.failure?
    ? ?$(container.failure)?:
    ????????(container.success?
    ? ? null ?:?$(container))
    ????}

    ????
    this .transport? = ?Ajax.getTransport();
    ????
    this .setOptions(options);

    ????
    var ?onComplete? = ? this .options.onComplete? || ?Prototype.emptyFunction;
    ????
    this .options.onComplete? = ?( function ()?{
    ??????
    this .updateContent();
    ??????onComplete(
    this .transport);
    ????}).bind(
    this );

    ????
    this .request(url);
    ??},

    ??updateContent:?
    function ()?{
    ????
    var ?receiver? = ? this .responseIsSuccess()? ?
    ??????
    this .containers.success?:? this .containers.failure;

    ????
    var ?match???? = ? new ?RegExp(Ajax.Updater.ScriptFragment,?'img');
    ????
    var ?response? = ? this .transport.responseText.replace(match,?'');
    ????
    var ?scripts?? = ? this .transport.responseText.match(match);

    ????
    if ?(receiver)?{
    ??????
    if ?( this .options.insertion)?{
    ????????
    new ? this .options.insertion(receiver,?response);
    ??????}?
    else ?{
    ????????receiver.innerHTML?
    = ?response;
    ??????}
    ????}

    ????
    if ?( this .responseIsSuccess())?{
    ??????
    if ?( this .onComplete)
    ????????setTimeout((
    function ()?{ this .onComplete(
    ??????????
    this .transport)}).bind( this ),? 10 );
    ????}

    /*
    ?*?如果調用者在傳入的options參數中定義?evalScripts=true,同時xmlhttp返回值的html中包含<script>標簽的話,執行該腳本
    ?
    */
    ????
    if ?( this .options.evalScripts? && ?scripts)?{
    /*
    ?*?注意前二十行左右還有一個?match?的聲明
    ?*?var?match????=?new?RegExp(Ajax.Updater.ScriptFragment,?'img');
    ?*?和此處的區別就是,正則表達式匹配標記多一個?"g"。
    ?*?多個g,?所以?scripts?是一個數組,數組中每個元素是一段?<script></script>?文本。
    ?*?沒有g,?scripts[i].match(match)[1]?匹配的就是?<script>標記中的?script?代碼。
    ?*?關于正則表達式,請參考javascript的相關資料。
    ?
    */
    ??????match?
    = ? new ?RegExp(Ajax.Updater.ScriptFragment,?'im');
    ??????setTimeout((
    function ()?{
    ????????
    for ?( var ?i? = ? 0 ;?i? < ?scripts.length;?i ++ )
    ??????????eval(scripts[i].match(match)[
    1 ]);
    ??????}).bind(
    this ),? 10 );
    ????}
    ??}
    });

    /*
    ?*?定期更新器
    ?
    */
    Ajax.PeriodicalUpdater?
    = ?Class.create();
    Ajax.PeriodicalUpdater.prototype?
    = ?( new ?Ajax.Base()).extend({
    ??initialize:?
    function (container,?url,?options)?{
    ????
    this .setOptions(options);
    ????
    this .onComplete? = ? this .options.onComplete;

    ????
    this .frequency? = ?( this .options.frequency? || ? 2 );
    ???
    // ?decay?可能是一個時間調整因素
    ???? this .decay? = ? 1 ;

    ????
    this .updater? = ?{};
    ????
    this .container? = ?container;
    ????
    this .url? = ?url;

    ????
    this .start();
    ??},

    ??start:?
    function ()?{
    ????
    this .options.onComplete? = ? this .updateComplete.bind( this );
    ????
    this .onTimerEvent();
    ??},

    ??stop:?
    function ()?{
    ????
    this .updater.onComplete? = ?undefined;
    ????clearTimeout(
    this .timer);
    ????(
    this .onComplete? || ?Ajax.emptyFunction).apply( this ,?arguments);
    ??},

    ??updateComplete:?
    function (request)?{
    ????
    if ?( this .options.decay)?{
    ??????
    this .decay? = ?(request.responseText? == ? this .lastText? ?
    ????????
    this .decay? * ? this .options.decay?:? 1 );

    ??????
    this .lastText? = ?request.responseText;
    ????}
    ????
    this .timer? = ?setTimeout( this .onTimerEvent.bind( this ),
    ??????
    this .decay? * ? this .frequency? * ? 1000 );
    ??},

    ??onTimerEvent:?
    function ()?{
    ????
    this .updater? = ? new ?Ajax.Updater( this .container,? this .url,? this .options);
    ??}
    });

    /*
    ?*?根據?class?attribute?的名字得到對象數組,支持?multiple?class
    ?*
    ?
    */
    document.getElementsByClassName?
    = ? function (className)?{
    ??
    var ?children? = ?document.getElementsByTagName(' * ')? || ?document.all;
    ??
    var ?elements? = ? new ?Array();
    ?
    ??
    for ?( var ?i? = ? 0 ;?i? < ?children.length;?i ++ )?{
    ????
    var ?child? = ?children[i];
    ????
    var ?classNames? = ?child.className.split('?');
    ????
    for ?( var ?j? = ? 0 ;?j? < ?classNames.length;?j ++ )?{
    ??????
    if ?(classNames[j]? == ?className)?{
    ????????elements.push(child);
    ????????
    break ;
    ??????}
    ????}
    ??}
    ?
    ??
    return ?elements;
    }

    /* ======================================================= */

    /*
    ?*?Element?就象一個?java?的工具類,主要用來?隱藏/顯示/銷除?對象,以及獲取對象的簡單屬性。
    ?*
    ?
    */
    if ?( ! window.Element)?{
    ??
    var ?Element? = ? new ?Object();
    }

    Object.extend(Element,?{
    /*
    ?*切換?顯示/隱藏
    ?
    */
    ??toggle:?
    function ()?{
    ????
    for ?( var ?i? = ? 0 ;?i? < ?arguments.length;?i ++ )?{
    ??????
    var ?element? = ?$(arguments[i]);
    ??????element.style.display?
    =
    ????????(element.style.display?
    == ?'none'? ? ?''?:?'none');
    ????}
    ??},

    ??hide:?
    function ()?{
    ????
    for ?( var ?i? = ? 0 ;?i? < ?arguments.length;?i ++ )?{
    ??????
    var ?element? = ?$(arguments[i]);
    ??????element.style.display?
    = ?'none';
    ????}
    ??},

    ??show:?
    function ()?{
    ????
    for ?( var ?i? = ? 0 ;?i? < ?arguments.length;?i ++ )?{
    ??????
    var ?element? = ?$(arguments[i]);
    ??????element.style.display?
    = ?'';
    ????}
    ??},

    /*
    ?*從父節點中移除
    ?
    */
    ??remove:?
    function (element)?{
    ????element?
    = ?$(element);
    ????element.parentNode.removeChild(element);
    ??},
    ???
    ??getHeight:?
    function (element)?{
    ????element?
    = ?$(element);
    ????
    return ?element.offsetHeight;
    ??},

    /*
    ?*是否擁有?class?屬性值
    ?
    */
    ??hasClassName:?
    function (element,?className)?{
    ????element?
    = ?$(element);
    ????
    if ?( ! element)
    ??????
    return ;
    ????
    var ?a? = ?element.className.split('?');
    ????
    for ?( var ?i? = ? 0 ;?i? < ?a.length;?i ++ )?{
    ??????
    if ?(a[i]? == ?className)
    ????????
    return ? true ;
    ????}
    ????
    return ? false ;
    ??},

    /*
    ?*為對象添加?class?屬性值
    ?
    */
    ??addClassName:?
    function (element,?className)?{
    ????element?
    = ?$(element);
    ????Element.removeClassName(element,?className);
    ????element.className?
    += ?'?'? + ?className;
    ??},

    /*
    ?*為對象移除?class?屬性值
    ?
    */
    ??removeClassName:?
    function (element,?className)?{
    ????element?
    = ?$(element);
    ????
    if ?( ! element)
    ??????
    return ;
    ????
    var ?newClassName? = ?'';
    ????
    var ?a? = ?element.className.split('?');
    ????
    for ?( var ?i? = ? 0 ;?i? < ?a.length;?i ++ )?{
    ??????
    if ?(a[i]? != ?className)?{
    ????????
    if ?(i? > ? 0 )
    ??????????newClassName?
    += ?'?';
    ????????newClassName?
    += ?a[i];
    ??????}
    ????}
    ????element.className?
    = ?newClassName;
    ??},
    ?
    ??
    // ?removes?whitespace-only?text?node?children
    ??cleanWhitespace:? function (element)?{
    ????
    var ?element? = ?$(element);
    ????
    for ?( var ?i? = ? 0 ;?i? < ?element.childNodes.length;?i ++ )?{
    ??????
    var ?node? = ?element.childNodes[i];
    ??????
    if ?(node.nodeType? == ? 3 ? && ? !/ \S / .test(node.nodeValue))
    ????????Element.remove(node);
    ????}
    ??}
    });

    /*
    ?*?為?Element.toggle?做了一個符號連接,大概是兼容性的考慮
    ?
    */
    var ?Toggle? = ? new ?Object();
    Toggle.display?
    = ?Element.toggle;

    /* ======================================================= */

    /*
    ?*?動態插入內容的實現,MS的Jscript實現中對象有一個?insertAdjacentHTML?方法
    ?*?(http:?//msdn.microsoft.com/workshop/author/dhtml/reference/methods/insertadjacenthtml.asp)
    ?*?這里算是一個對象形式的封裝。
    ?
    */
    Abstract.Insertion?
    = ? function (adjacency)?{
    ??
    this .adjacency? = ?adjacency;
    }

    Abstract.Insertion.prototype?
    = ?{
    ??initialize:?
    function (element,?content)?{
    ????
    this .element? = ?$(element);
    ????
    this .content? = ?content;
    ???
    ????
    if ?( this .adjacency? && ? this .element.insertAdjacentHTML)?{
    ??????
    this .element.insertAdjacentHTML( this .adjacency,? this .content);
    ????}?
    else ?{
    /*
    ?*?gecko?不支持?insertAdjacentHTML?方法,但可以用如下代碼代替
    ?
    */
    ??????
    this .range? = ? this .element.ownerDocument.createRange();
    /*
    ?*?如果定義了?initializeRange?方法,則實行,這里相當與定義了一個抽象的?initializeRange?方法
    ?
    */
    ??????
    if ?( this .initializeRange)? this .initializeRange();
    ??????
    this .fragment? = ? this .range.createContextualFragment( this .content);

    /*
    ?*?insertContent?也是一個抽象方法,子類必須實現
    ?
    */
    ??????
    this .insertContent();
    ????}
    ??}
    }

    /*
    ?*?prototype?加深了我的體會,就是寫js?如何去遵循 Don’t?Repeat?Yourself?(DRY)?原則
    ?*?上文中?Abstract.Insertion?算是一個抽象類,定義了名為 initializeRange?的一個抽象方法
    ?*?var?Insertion?=?new?Object() 建立一個命名空間
    ?*?Insertion.Before|Top|Bottom|After?就象是四個java中的四個靜態內部類,而它們分別繼承于Abstract.Insertion,并實現了initializeRange方法。
    ?
    */
    var ?Insertion? = ? new ?Object();

    /*
    ?*將內容插入到指定節點的前面,?與指定節點同級
    */
    Insertion.Before?
    = ?Class.create();
    Insertion.Before.prototype?
    = ?( new ?Abstract.Insertion('beforeBegin')).extend({
    ??initializeRange:?
    function ()?{
    ????
    this .range.setStartBefore( this .element);
    ??},
    ?
    ??insertContent:?
    function ()?{
    ????
    this .element.parentNode.insertBefore( this .fragment,? this .element);
    ??}
    });

    /*
    ?*將內容插入到指定節點的第一個子節點前,于是內容變為該節點的第一個子節點
    */
    Insertion.Top?
    = ?Class.create();
    Insertion.Top.prototype?
    = ?( new ?Abstract.Insertion('afterBegin')).extend({
    ??initializeRange:?
    function ()?{
    ????
    this .range.selectNodeContents( this .element);
    ????
    this .range.collapse( true );
    ??},
    ?
    ??insertContent:?
    function ()?{?
    ????
    this .element.insertBefore( this .fragment,? this .element.firstChild);
    ??}
    });

    /*
    ?*將內容插入到指定節點的最后,于是內容變為該節點的最后一個子節點
    */
    Insertion.Bottom?
    = ?Class.create();
    Insertion.Bottom.prototype?
    = ?( new ?Abstract.Insertion('beforeEnd')).extend({
    ??initializeRange:?
    function ()?{
    ????
    this .range.selectNodeContents( this .element);
    ????
    this .range.collapse( this .element);
    ??},
    ?
    ??insertContent:?
    function ()?{
    ????
    this .element.appendChild( this .fragment);
    ??}
    });

    /*
    ?*將內容插入到指定節點的后面,?與指定節點同級
    */
    Insertion.After?
    = ?Class.create();
    Insertion.After.prototype?
    = ?( new ?Abstract.Insertion('afterEnd')).extend({
    ??initializeRange:?
    function ()?{
    ????
    this .range.setStartAfter( this .element);
    ??},
    ?
    ??insertContent:?
    function ()?{
    ????
    this .element.parentNode.insertBefore( this .fragment,
    ??????
    this .element.nextSibling);
    ??}
    });

    /*
    ?*?針對?頁面元素對象(一般都是表單控件)的工具類,提供一些簡單靜態方法
    ?*?這些方法顯然常用在表單處理中
    ?*?注意?Field?這種聲明方式類似于?java?聲明一個靜態的?singleton?工具類
    ?*?等同于?:
    ?*???var?Field?=?new?Object();
    ?*???Field.extend({});
    ?*
    ?*?后文中的?Form,?Event,?Position?對象聲明方式如出一轍
    ?
    */
    var ?Field? = ?{

    /*
    ?*清除參數引用的對象的值
    ?
    */
    ??clear:?
    function ()?{
    ????
    for ?( var ?i? = ? 0 ;?i? < ?arguments.length;?i ++ )
    ??????$(arguments[i]).value?
    = ?'';
    ??},

    /*
    ?*使參數引用對象獲取焦點
    ?
    */
    ??focus:?
    function (element)?{
    ????$(element).focus();
    ??},
    ?
    /*
    ?*判斷參數引用對象是否有非空值,如為空值,返回false,?反之true
    ?
    */
    ??present:?
    function ()?{
    ????
    for ?( var ?i? = ? 0 ;?i? < ?arguments.length;?i ++ )
    ??????
    if ?($(arguments[i]).value? == ?'')? return ? false ;
    ????
    return ? true ;
    ??},
    ?
    /*
    ?*使選中參數引用對象
    ?
    */
    ??select:?
    function (element)?{
    ????$(element).select();
    ??},
    ???
    /*
    ?*使參數引用對象處于可編輯狀態
    ?
    */
    ??activate:?
    function (element)?{
    ????$(element).focus();
    ????$(element).select();
    ??}
    }

    /* ======================================================= */

    /*
    ?*?表單工具類
    ?
    */
    var ?Form? = ?{
    /*
    ?*將表單元素序列化后的值(其實就是?name=value?形式的名值配對)組合成?QueryString?的形式
    ?
    */
    ??serialize:?
    function (form)?{
    ????
    var ?elements? = ?Form.getElements($(form));
    ????
    var ?queryComponents? = ? new ?Array();
    ???
    ????
    for ?( var ?i? = ? 0 ;?i? < ?elements.length;?i ++ )?{
    ??????
    var ?queryComponent? = ?Form.Element.serialize(elements[i]);
    ??????
    if ?(queryComponent)
    ????????queryComponents.push(queryComponent);
    ????}
    ???
    ????
    return ?queryComponents.join(' & ');
    ??},
    ?
    /*
    ?*得到表單的所有元素對象
    ?
    */
    ??getElements:?
    function (form)?{
    ????
    var ?form? = ?$(form);
    ????
    var ?elements? = ? new ?Array();

    ????
    for ?(tagName? in ?Form.Element.Serializers)?{
    ??????
    var ?tagElements? = ?form.getElementsByTagName(tagName);
    ??????
    for ?( var ?j? = ? 0 ;?j? < ?tagElements.length;?j ++ )
    ????????elements.push(tagElements[j]);
    ????}
    ????
    return ?elements;
    ??},
    ?
    /*
    ?*根據?type?和?name?過濾得到表單中符合的?<input>?對象
    ?
    */
    ??getInputs:?
    function (form,?typeName,?name)?{
    ????
    var ?form? = ?$(form);
    ????
    var ?inputs? = ?form.getElementsByTagName('input');
    ???
    ????
    if ?( ! typeName? && ? ! name)
    ??????
    return ?inputs;
    ?????
    ????
    var ?matchingInputs? = ? new ?Array();
    ????
    for ?( var ?i? = ? 0 ;?i? < ?inputs.length;?i ++ )?{
    ??????
    var ?input? = ?inputs[i];
    ??????
    if ?((typeName? && ?input.type? != ?typeName)? ||
    ??????????(name?
    && ?input.name? != ?name))
    ????????
    continue ;
    ??????matchingInputs.push(input);
    ????}

    ????
    return ?matchingInputs;
    ??},

    /*
    ?*將指定表單的元素置于不可用狀態
    ?
    */ ?
    ??disable:?
    function (form)?{
    ????
    var ?elements? = ?Form.getElements(form);
    ????
    for ?( var ?i? = ? 0 ;?i? < ?elements.length;?i ++ )?{
    ??????
    var ?element? = ?elements[i];
    ??????element.blur();
    ??????element.disabled?
    = ?' true ';
    ????}
    ??},

    /*
    ?*將指定表單的元素置于可用狀態
    ?
    */
    ??enable:?
    function (form)?{
    ????
    var ?elements? = ?Form.getElements(form);
    ????
    for ?( var ?i? = ? 0 ;?i? < ?elements.length;?i ++ )?{
    ??????
    var ?element? = ?elements[i];
    ??????element.disabled?
    = ?'';
    ????}
    ??},

    /*
    ?*使表單的第一個非?hidden?類型而且處于可用狀態的元素獲得焦點
    ?
    */
    ??focusFirstElement:?
    function (form)?{
    ????
    var ?form? = ?$(form);
    ????
    var ?elements? = ?Form.getElements(form);
    ????
    for ?( var ?i? = ? 0 ;?i? < ?elements.length;?i ++ )?{
    ??????
    var ?element? = ?elements[i];
    ??????
    if ?(element.type? != ?'hidden'? && ? ! element.disabled)?{
    ????????Field.activate(element);
    ????????
    break ;
    ??????}
    ????}
    ??},

    ??
    /*
    ?*?重置表單
    ?
    */
    ??reset:?
    function (form)?{
    ????$(form).reset();
    ??}
    }

    /*
    ?*?表單元素工具類
    ?
    */
    Form.Element?
    = ?{
    /*
    ?*返回表單元素的值先序列化,?其實就是?name=value?形式的名值配對
    ?
    */
    ??serialize:?
    function (element)?{
    ????
    var ?element? = ?$(element);
    ????
    var ?method? = ?element.tagName.toLowerCase();
    ????
    var ?parameter? = ?Form.Element.Serializers[method](element);
    ???
    ????
    if ?(parameter)
    ??????
    return ?encodeURIComponent(parameter[ 0 ])? + ?' = '? +
    ????????encodeURIComponent(parameter[
    1 ]);???????????????????
    ??},
    ?
    /*
    ?*?返回表單元素的值
    ?
    */
    ??getValue:?
    function (element)?{
    ????
    var ?element? = ?$(element);
    ????
    var ?method? = ?element.tagName.toLowerCase();
    ????
    var ?parameter? = ?Form.Element.Serializers[method](element);
    ???
    ????
    if ?(parameter)
    ??????
    return ?parameter[ 1 ];
    ??}
    }

    /*
    ?*?prototype?的所謂序列化其實就是將表單的名字和值組合成一個數組
    ?
    */
    Form.Element.Serializers?
    = ?{
    ??input:?
    function (element)?{
    ????
    switch ?(element.type.toLowerCase())?{
    ??????
    case ?'submit':
    ??????
    case ?'hidden':
    ??????
    case ?'password':
    ??????
    case ?'text':
    ????????
    return ?Form.Element.Serializers.textarea(element);
    ??????
    case ?'checkbox':?
    ??????
    case ?'radio':
    ????????
    return ?Form.Element.Serializers.inputSelector(element);
    ????}
    ????
    return ? false ;
    ??},

    /*
    ?*單/多選框?由此方法處理序列化
    ?
    */
    ??inputSelector:?
    function (element)?{
    ????
    if ?(element.checked)
    ??????
    return ?[element.name,?element.value];
    ??},

    /*
    ?*textarea?由此方法處理序列化
    ?
    */
    ??textarea:?
    function (element)?{
    ????
    return ?[element.name,?element.value];
    ??},

    /*
    ?*select?下拉列表由此方法處理序列化
    ?
    */
    ??select:?
    function (element)?{
    ????
    var ?value? = ?'';
    ????
    if ?(element.type? == ?'select - one')?{
    ??????
    var ?index? = ?element.selectedIndex;
    ??????
    if ?(index? >= ? 0 )
    ????????value?
    = ?element.options[index].value? || ?element.options[index].text;
    ????}?
    else ?{
    /*
    ?*?支持?select-mulitple?的下拉列表,返回的數組的第二個元素,是一個值數組
    ?
    */
    ??????value?
    = ? new ?Array();
    ??????
    for ?( var ?i? = ? 0 ;?i? < ?element.length;?i ++ )?{
    ????????
    var ?opt? = ?element.options[i];
    ????????
    if ?(opt.selected)
    ??????????value.push(opt.value?
    || ?opt.text);
    ??????}
    ????}
    ????
    return ?[element.name,?value];
    ??}
    }

    /* ======================================================= */
    /*
    ?*?Form.Element.getValue?會經常用到,所以做了一個快捷引用
    ?*?取得某個表單控件的值,可以簡化調用為?$F("username"),真是方便啊
    ?
    */
    var ?$F? = ?Form.Element.getValue;

    /* ======================================================= */

    /*
    ?*?Abstract.TimedObserver?也沒有用?Class.create()?來創建,和Ajax.Base?意圖應該一樣
    ?*?Abstract.TimedObserver?顧名思義,是套用Observer設計模式來跟蹤指定表單元素,
    ?*?當表單元素的值發生變化的時候,就執行回調函數
    ?*
    ?*?我想 Observer?與注冊onchange事件相似,不同點在于?onchange?事件是在元素失去焦點的時候才激發。
    ?*?同樣的與?onpropertychange?事件也相似,不過它只關注表單元素的值的變化,而且提供timeout的控制。
    ?*
    ?*?除此之外,Observer?的好處大概就在與更面向對象,另外可以動態的更換回調函數,這就比注冊事件要靈活一些。
    ?*?Observer?應該可以勝任動態數據校驗,或者多個關聯下拉選項列表的連動等等
    ?*
    ?
    */
    Abstract.TimedObserver?
    = ? function ()?{}

    /*
    ?*?這個設計和?PeriodicalExecuter?一樣,bind?方法是實現的核心
    ?
    */
    Abstract.TimedObserver.prototype?
    = ?{
    ??initialize:?
    function (element,?frequency,?callback)?{
    ????
    this .frequency? = ?frequency;
    ????
    this .element??? = ?$(element);
    ????
    this .callback?? = ?callback;
    ???
    ????
    this .lastValue? = ? this .getValue();
    ????
    this .registerCallback();
    ??},

    ?
    ??registerCallback:?
    function ()?{
    ????setInterval(
    this .onTimerEvent.bind( this ),? this .frequency? * ? 1000 );
    ??},
    ?
    ??onTimerEvent:?
    function ()?{
    ????
    var ?value? = ? this .getValue();
    ????
    if ?( this .lastValue? != ?value)?{
    ??????
    this .callback( this .element,?value);
    ??????
    this .lastValue? = ?value;
    ????}
    ??}
    }

    /*
    ?*?Form.Element.Observer?監視指定表單域的值是否變化
    ?
    */
    Form.Element.Observer?
    = ?Class.create();
    Form.Element.Observer.prototype?
    = ?( new ?Abstract.TimedObserver()).extend({
    ??getValue:?
    function ()?{
    ????
    return ?Form.Element.getValue( this .element);
    ??}
    });

    /*
    ?*?Form.Element.Observer?監視指定表單所有控件的值是否有變化
    ?
    */
    Form.Observer?
    = ?Class.create();
    Form.Observer.prototype?
    = ?( new ?Abstract.TimedObserver()).extend({
    ??getValue:?
    function ()?{
    ????
    return ?Form.serialize( this .element);
    ??}
    });

    /* ======================================================= */

    /*
    ?*?EventObserver?相比上面的?TimedObserver,是更具主動性的一種監測
    ?*?它直接為表單控件(根據?type?的不同)?注冊相應的事件處理,?只要發現某個控件值發生改變,就執行回調函數
    ?
    */
    Abstract.EventObserver?
    = ? function ()?{}
    Abstract.EventObserver.prototype?
    = ?{
    ??initialize:?
    function (element,?callback)?{
    ????
    this .element?? = ?$(element);
    ????
    this .callback? = ?callback;
    ???
    ????
    this .lastValue? = ? this .getValue();
    ????
    if ?( this .element.tagName.toLowerCase()? == ?'form')
    ??????
    this .registerFormCallbacks();
    ????
    else
    ??????
    this .registerCallback( this .element);
    ??},
    ?
    ??onElementEvent:?
    function ()?{
    ????
    var ?value? = ? this .getValue();
    ????
    if ?( this .lastValue? != ?value)?{
    ??????
    this .callback( this .element,?value);
    ??????
    this .lastValue? = ?value;
    ????}
    ??},
    ?
    ??registerFormCallbacks:?
    function ()?{
    ????
    var ?elements? = ?Form.getElements( this .element);
    ????
    for ?( var ?i? = ? 0 ;?i? < ?elements.length;?i ++ )
    ??????
    this .registerCallback(elements[i]);
    ??},
    ?
    ??registerCallback:?
    function (element)?{
    ????
    if ?(element.type)?{
    ??????
    switch ?(element.type.toLowerCase())?{
    /*
    ?*?checkbox?和?radio?類型的控件注冊?onclick?事件處理
    ?
    */
    ????????
    case ?'checkbox':?
    ????????
    case ?'radio':
    ??????????element.target?
    = ? this ;
    ??????????element.prev_onclick?
    = ?element.onclick? || ?Prototype.emptyFunction;
    /*
    ?*?相信這里有改進的空間,應該使用其后的?Event對象提供的注冊管理功能來統一注冊
    ?
    */
    ??????????element.onclick?
    = ? function ()?{
    ????????????
    this .prev_onclick();
    ????????????
    this .target.onElementEvent();
    ??????????}
    ??????????
    break ;

    /*
    ?*?其他類型的控件注冊?onchange?事件處理
    ?
    */
    ????????
    case ?'password':
    ????????
    case ?'text':
    ????????
    case ?'textarea':
    ????????
    case ?'select - one':
    ????????
    case ?'select - multiple':
    ??????????element.target?
    = ? this ;
    ??????????element.prev_onchange?
    = ?element.onchange? || ?Prototype.emptyFunction;
    ??????????element.onchange?
    = ? function ()?{
    ????????????
    this .prev_onchange();
    ????????????
    this .target.onElementEvent();
    ??????????}
    ??????????
    break ;
    ??????}
    ????}???
    ??}
    }

    /*
    ?*?監視指定表單控件
    ?
    */
    Form.Element.EventObserver?
    = ?Class.create();
    Form.Element.EventObserver.prototype?
    = ?( new ?Abstract.EventObserver()).extend({
    ??getValue:?
    function ()?{
    ????
    return ?Form.Element.getValue( this .element);
    ??}
    });

    /*
    ?*?監視指定表單所有控件
    ?
    */
    Form.EventObserver?
    = ?Class.create();
    Form.EventObserver.prototype?
    = ?( new ?Abstract.EventObserver()).extend({
    ??getValue:?
    function ()?{
    ????
    return ?Form.serialize( this .element);
    ??}
    });

    /*
    ?*?封裝事件處理的靜態工具對象
    ?
    */
    if ?( ! window.Event)?{
    ??
    var ?Event? = ? new ?Object();
    }

    Object.extend(Event,?{
    ??KEY_BACKSPACE:?
    8 ,
    ??KEY_TAB:???????
    9 ,
    ??KEY_RETURN:???
    13 ,
    ??KEY_ESC:??????
    27 ,
    ??KEY_LEFT:?????
    37 ,
    ??KEY_UP:???????
    38 ,
    ??KEY_RIGHT:????
    39 ,
    ??KEY_DOWN:?????
    40 ,
    ??KEY_DELETE:???
    46 ,

    ??element:?
    function (event)?{
    ????
    return ?event.target? || ?event.srcElement;
    ??},

    ??isLeftClick:?
    function (event)?{
    ????
    return ?(((event.which)? && ?(event.which? == ? 1 ))? ||
    ????????????((event.button)?
    && ?(event.button? == ? 1 )));
    ??},

    /*
    ?*click事件時鼠標以頁面為基準的x坐標值,?考慮到了滾動條導致的位移差
    ?
    */
    ??pointerX:?
    function (event)?{
    ????
    return ?event.pageX? || ?(event.clientX? +
    ??????(document.documentElement.scrollLeft?
    || ?document.body.scrollLeft));
    ??},

    /*
    ?*click事件時鼠標以頁面為基準的y坐標值,?考慮到了滾動條導致的位移差
    ?
    */
    ??pointerY:?
    function (event)?{
    ????
    return ?event.pageY? || ?(event.clientY? +
    ??????(document.documentElement.scrollTop?
    || ?document.body.scrollTop));
    ??},

    /*
    ?*停止冒泡(參見?http://www.quirksmode.org/js/events_order.html)?和阻止瀏覽器執行與事件相關的默認動作
    ?*?比如
    ?*?<a?>google</a>
    ?*?那么點擊該連接,頁面并不會執行轉向
    ?
    */
    ??stop:?
    function (event)?{
    ????
    if ?(event.preventDefault)?{
    ??????event.preventDefault();
    ??????event.stopPropagation();
    ????}?
    else ?{
    ??????event.returnValue?
    = ? false ;
    ????}
    ??},

    ??
    // ?find?the?first?node?with?the?given?tagName,?starting?from?the
    ?? // ?node?the?event?was?triggered?on;?traverses?the?DOM?upwards
    /*

    ?*找到事件元素的父級元素中,最接近事件元素且等同于指定標簽名的父元素。
    ?*?如果到達頂級元素(HTML),那么就返回頂級元素
    ?
    */
    ??findElement:?
    function (event,?tagName)?{
    ????
    var ?element? = ?Event.element(event);
    ????
    while ?(element.parentNode? && ?( ! element.tagName? ||
    ????????(element.tagName.toUpperCase()?
    != ?tagName.toUpperCase())))
    ??????element?
    = ?element.parentNode;
    ????
    return ?element;
    ??},

    /*
    ?*其后的代碼封裝了事件的注冊和反注冊,避免ie的內存泄露的bug
    ?*?參見??http://javascript.weblogsinc.com/entry/1234000267034921/
    ?
    */
    ??observers:?
    false ,
    ?
    /*
    ?*this.observers?的數據格式是一個二維數組,二維的數組分別四個元素分別是
    ?*?[注冊事件對象,事件名,事件處理函數,事件處理模式布爾值]
    ?
    */
    ??_observeAndCache:?
    function (element,?name,?observer,?useCapture)?{
    ????
    if ?( ! this .observers)? this .observers? = ?[];
    ????
    if ?(element.addEventListener)?{
    ??????
    this .observers.push([element,?name,?observer,?useCapture]);
    ??????element.addEventListener(name,?observer,?useCapture);
    ????}?
    else ? if ?(element.attachEvent)?{
    ??????
    this .observers.push([element,?name,?observer,?useCapture]);
    ??????element.attachEvent('on'?
    + ?name,?observer);
    ????}
    ??},
    ?
    ??unloadCache:?
    function ()?{
    ????
    if ?( ! Event.observers)? return ;
    ????
    for ?( var ?i? = ? 0 ;?i? < ?Event.observers.length;?i ++ )?{
    /*
    ?*?這里與?Ajax.Request?對象設置?request?header?的代碼異曲同工
    ?
    */
    ??????Event.stopObserving.apply(
    this ,?Event.observers[i]);
    ??????Event.observers[i][
    0 ]? = ? null ;
    ????}
    ????Event.observers?
    = ? false ;
    ??},

    /*
    ?*注冊對象的事件處理,并記錄到cache中
    ?
    */
    ??observe:?
    function (element,?name,?observer,?useCapture)?{
    ????
    var ?element? = ?$(element);
    ????useCapture?
    = ?useCapture? || ? false ;
    ???
    ????
    if ?(name? == ?'keypress'? &&
    ????????((navigator.appVersion.indexOf('AppleWebKit')?
    > ? 0 )
    ????????
    || ?element.attachEvent))
    ??????name?
    = ?'keydown';
    ???
    ????
    this ._observeAndCache(element,?name,?observer,?useCapture);
    ??},

    /*
    ?*取消對象已注冊的事件處理
    ?
    */
    ??stopObserving:?
    function (element,?name,?observer,?useCapture)?{
    ????
    var ?element? = ?$(element);
    ????useCapture?
    = ?useCapture? || ? false ;
    ???
    ????
    if ?(name? == ?'keypress'? &&
    ????????((navigator.appVersion.indexOf('AppleWebKit')?
    > ? 0 )
    ????????
    || ?element.detachEvent))
    ??????name?
    = ?'keydown';
    ???
    ????
    if ?(element.removeEventListener)?{
    ??????element.removeEventListener(name,?observer,?useCapture);
    ????}?
    else ? if ?(element.detachEvent)?{
    ??????element.detachEvent('on'?
    + ?name,?observer);
    ????}
    ??}
    });

    /* ?prevent?memory?leaks?in?IE? */
    /*
    ?*頁面onload?的時候取消所有事件注冊,避免ie內存泄漏的bug
    */
    Event.observe(window,?'unload',?Event.unloadCache,?
    false );

    /*
    ?*?Position?對象也是常用的工具類,提供了獲取元素在頁面上位置的函數,Drag&Drop的效果一定常會用到
    ?*?具體的應用參考?script.aculo.us?基于prototype?的實現,尤其是dragdrop.js。
    ?
    */
    var ?Position? = ?{

    ??
    // ?set?to?true?if?needed,?warning:?firefox?performance?problems
    ?? // ?NOT?neeeded?for?page?scrolling,?only?if?draggable?contained?in
    ?? // ?scrollable?elements
    ??includeScrollOffsets:? false ,

    ??
    // ?must?be?called?before?calling?withinIncludingScrolloffset,?every?time?the
    ?? // ?page?is?scrolled
    ??prepare:? function ()?{
    ????
    this .deltaX? = ??window.pageXOffset
    ????????????????
    || ?document.documentElement.scrollLeft
    ????????????????
    || ?document.body.scrollLeft
    ????????????????
    || ? 0 ;
    ????
    this .deltaY? = ??window.pageYOffset

    ????????????????
    || ?document.documentElement.scrollTop
    ????????????????
    || ?document.body.scrollTop
    ????????????????
    || ? 0 ;
    ??},

    /*
    ?*當對象所處的頁面有滾動條是,計算位移
    ?
    */
    ??realOffset:?
    function (element)?{
    ????
    var ?valueT? = ? 0 ,?valueL? = ? 0 ;
    ????
    do ?{
    ??????valueT?
    += ?element.scrollTop?? || ? 0 ;
    ??????valueL?
    += ?element.scrollLeft? || ? 0 ;
    ??????element?
    = ?element.parentNode;
    ????}?
    while ?(element);
    ????
    return ?[valueL,?valueT];
    ??},

    /*
    ?*計算出對象在頁面上的位置
    ?
    */
    ??cumulativeOffset:?
    function (element)?{
    ????
    var ?valueT? = ? 0 ,?valueL? = ? 0 ;
    ????
    do ?{
    ??????valueT?
    += ?element.offsetTop?? || ? 0 ;
    ??????valueL?
    += ?element.offsetLeft? || ? 0 ;
    ??????element?
    = ?element.offsetParent;
    ????}?
    while ?(element);
    ????
    return ?[valueL,?valueT];
    ??},

    ??
    // ?caches?x/y?coordinate?pair?to?use?with?overlap
    /*

    ?*判斷一個坐標是否在指定元素的空間范圍中
    ?*?比如你想判斷鼠標點擊點的坐標是否在某個層或窗口
    ?
    */
    ??within:?
    function (element,?x,?y)?{
    ????
    if ?( this .includeScrollOffsets)
    ??????
    return ? this .withinIncludingScrolloffsets(element,?x,?y);
    ????
    this .xcomp? = ?x;
    ????
    this .ycomp? = ?y;
    ????
    this .offset? = ? this .cumulativeOffset(element);

    ????
    return ?(y? >= ? this .offset[ 1 ]? &&
    ????????????y?
    < ?? this .offset[ 1 ]? + ?element.offsetHeight? &&
    ????????????x?
    >= ? this .offset[ 0 ]? &&
    ????????????x?
    < ?? this .offset[ 0 ]? + ?element.offsetWidth);
    ??},

    ??withinIncludingScrolloffsets:?
    function (element,?x,?y)?{
    ????
    var ?offsetcache? = ? this .realOffset(element);

    ????
    this .xcomp? = ?x? + ?offsetcache[ 0 ]? - ? this .deltaX;
    ????
    this .ycomp? = ?y? + ?offsetcache[ 1 ]? - ? this .deltaY;
    ????
    this .offset? = ? this .cumulativeOffset(element);

    ????
    return ?( this .ycomp? >= ? this .offset[ 1 ]? &&
    ????????????
    this .ycomp? < ?? this .offset[ 1 ]? + ?element.offsetHeight? &&
    ????????????
    this .xcomp? >= ? this .offset[ 0 ]? &&
    ????????????
    this .xcomp? < ?? this .offset[ 0 ]? + ?element.offsetWidth);
    ??},

    ??
    // ?within?must?be?called?directly?before
    /*

    ?*調用該方法時,確保首先調用了within方法
    ?*?如果x,y坐標位于element的空間范圍中,那么返回一個小于1的標示位置的值,比如0.5標示該坐標位于element空間的中線上
    ?
    */
    ??overlap:?
    function (mode,?element)?{?
    ????
    if ?( ! mode)? return ? 0 ;?
    ????
    if ?(mode? == ?'vertical')
    ??????
    return ?(( this .offset[ 1 ]? + ?element.offsetHeight)? - ? this .ycomp)? /
    ????????element.offsetHeight;
    ????
    if ?(mode? == ?'horizontal')
    ??????
    return ?(( this .offset[ 0 ]? + ?element.offsetWidth)? - ? this .xcomp)? /
    ????????element.offsetWidth;
    ??},

    /*
    ?*復制源對象的空間數據到目的對象。
    ?*?常用的地方:拖綴一個層到新地方時,常常動態構造和該層同樣大小的虛層。
    ?
    */
    ??clone:?
    function (source,?target)?{
    ????source?
    = ?$(source);
    ????target?
    = ?$(target);
    ????target.style.position?
    = ?'absolute';
    ????
    var ?offsets? = ? this .cumulativeOffset(source);
    ????target.style.top????
    = ?offsets[ 1 ]? + ?'px';
    ????target.style.left???
    = ?offsets[ 0 ]? + ?'px';
    ????target.style.width??
    = ?source.offsetWidth? + ?'px';
    ????target.style.height?
    = ?source.offsetHeight? + ?'px';
    ??}
    }
    posted on 2006-12-01 14:21 Web 2.0 技術資源 閱讀(290) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 久久亚洲高清观看| 免费看大美女大黄大色| 国产精品99精品久久免费| 亚欧乱色国产精品免费视频| 美女被暴羞羞免费视频| 色婷婷亚洲一区二区三区| 免费99精品国产自在现线| 一级毛片免费毛片一级毛片免费 | 国产亚洲一区二区手机在线观看| 国产精品亚洲高清一区二区| 亚洲视频在线一区二区| 伊人久久亚洲综合| 亚洲成A∨人片在线观看不卡| 亚洲精品国精品久久99热一| 亚洲av日韩av无码黑人| 亚洲欧洲第一a在线观看| 亚洲网站在线免费观看| 亚洲国产成人久久三区| 亚洲精品一二三区| 亚洲av成人一区二区三区观看在线| 亚洲国产精品无码久久| 美国免费高清一级毛片| 国产区在线免费观看| 久久成人免费大片| 特级做A爰片毛片免费69| 啦啦啦在线免费视频| 免费大片黄手机在线观看| 在线观看亚洲成人| 精品亚洲麻豆1区2区3区| 精品国产成人亚洲午夜福利| 黄色免费网站在线看| 精品免费视在线观看| 青青青国产在线观看免费网站| 全免费一级午夜毛片| 爱情岛论坛网亚洲品质自拍| 亚洲精品国产成人专区| 成人亚洲国产va天堂| 国产精品一区二区三区免费| 污视频在线观看免费| 色吊丝最新永久免费观看网站| 亚洲欧洲日本在线|