<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 技術(shù)儲(chǔ)備............

      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      77 隨筆 :: 17 文章 :: 116 評(píng)論 :: 0 Trackbacks

    ?

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

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

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

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

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

    /*
    ?*?這個(gè)方法很有趣,它封裝一個(gè)javascript函數(shù)對(duì)象,返回一個(gè)新函數(shù)對(duì)象,新函數(shù)對(duì)象的主體和原對(duì)象相同,
    ?*?但是bind()方法參數(shù)將被用作當(dāng)前對(duì)象的對(duì)象。
    ?*?也就是說新函數(shù)中的?this?引用被改變?yōu)閰?shù)提供的對(duì)象。
    ?*?比如:
    ?*?????<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>
    ?*?那么,調(diào)用aaa.showValue?將返回"aaa",?但調(diào)用aaa.showValue2?將返回"bbb"。
    ?*
    ?*?apply?是ie5.5后才出現(xiàn)的新方法(Netscape好像很早就支持了)。
    ?*?該方法更多的資料參考MSDN?http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthApply.asp
    ?*?閱讀其后的代碼就會(huì)發(fā)現(xiàn),bind?被應(yīng)用的很廣泛,該方法和?Object.prototype.extend?一樣是?Prototype?的核心。
    ?*?還有一個(gè)?call?方法,應(yīng)用起來和?apply?類似。可以一起研究下。
    ?
    */
    Function.prototype.bind?
    = ? function (object)?{
    ??
    var ?__method? = ? this ;
    ??
    return ? function ()?{
    ????__method.apply(object,?arguments);
    ??}
    }

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

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

    /*
    ?*?典型?Ruby?風(fēng)格的函數(shù),將參數(shù)中的方法逐個(gè)調(diào)用,返回第一個(gè)成功執(zhí)行的方法的返回值
    ?
    */
    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;
    ??}
    }

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

    /*
    ?*?一個(gè)設(shè)計(jì)精巧的定時(shí)執(zhí)行器
    ?*?首先由?Class.create()?創(chuàng)建一個(gè)?PeriodicalExecuter?類型,
    ?*?然后用對(duì)象直接量的語(yǔ)法形式設(shè)置原型。
    ?*
    ?*?需要特別說明的是?rgisterCallback?方法,它調(diào)用上面定義的函數(shù)原型方法bind,?并傳遞自己為參數(shù)。
    ?*?之所以這樣做,是因?yàn)?setTimeout?默認(rèn)總以?window?對(duì)象為當(dāng)前對(duì)象,也就是說,如果?registerCallback?方法定義如下的話:
    ?*?????registerCallback:?function()?{
    ?*?????????setTimeout(this.onTimerEvent,?this.frequency?*?1000);
    ?*?????}
    ?*?那么,this.onTimeoutEvent?方法執(zhí)行失敗,因?yàn)樗鼰o法訪問?this.currentlyExecuting?屬性。
    ?*?而使用了bind以后,該方法才能正確的找到this,也就是PeriodicalExecuter的當(dāng)前實(shí)例。
    ?
    */
    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 ;
    ??????}
    ????}
    ??}
    }

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

    /*
    ?*?這個(gè)函數(shù)就?Ruby?了。我覺得它的作用主要有兩個(gè)
    ?*?1.??大概是?document.getElementById(id)?的最簡(jiǎn)化調(diào)用。
    ?*?比如:$("aaa")?將返回?aaa?對(duì)象
    ?*?2.??得到對(duì)象數(shù)組
    ?*?比如:?$("aaa","bbb")?返回一個(gè)包括id為"aaa"和"bbb"兩個(gè)input控件對(duì)象的數(shù)組。
    ?
    */
    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;
    ??}
    }

    /*
    ?*?擴(kuò)展?javascript?內(nèi)置的?String?對(duì)象
    ?
    */
    String.prototype.extend({

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

    /*
    ?*這個(gè)方法很常見,通常的實(shí)現(xiàn)都是用正則表達(dá)式替換特殊字符為html規(guī)范定義的命名實(shí)體或者十進(jìn)制編碼,比如:
    ?*?string.replace(/&/g,?"&amp;").replace(/</g,?"&lt;").replace(/>/g,?"&gt;");
    ?*?而這里的實(shí)現(xiàn)借用瀏覽器自身的內(nèi)部替換,確實(shí)巧妙。
    ?
    */
    ??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?對(duì)象,?靜態(tài)方法?getTransport?方法返回一個(gè)?XMLHttp?對(duì)象
    ?
    */
    var ?Ajax? = ?{
    ??getTransport:?
    function ()?{
    ????
    return ?Try.these(
    ??????
    function ()?{ return ? new ?ActiveXObject('Msxml2.XMLHTTP')},
    ??????
    function ()?{ return ? new ?ActiveXObject('Microsoft.XMLHTTP')},
    ??????
    function ()?{ return ? new ?XMLHttpRequest()}
    ????)?
    || ? false ;
    ??}
    }

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

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

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

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

     
    /*
    ?*新增加?request?方法封裝?xmlhttp 的調(diào)用過程。
    ?
    */
    ??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?方法的調(diào)用有些奇技淫巧的意味
    ?*?從上下文中我們可以分析出?this.options.requestHeaders?是調(diào)用者自定義的http?header數(shù)組。
    ?*?requestHeaders?也是一個(gè)數(shù)組,將一個(gè)數(shù)組中的元素逐個(gè)添加到另一個(gè)元素中,直接調(diào)用
    ?*?requestHeaders.push(this.options.requestHeaders)
    ?*?是不行的,因?yàn)樵撜{(diào)用導(dǎo)致?this.options.requestHeaders?整個(gè)數(shù)組作為一個(gè)元素添加到?requestHeaders中。
    ?*?javascript的Array對(duì)象還提供一個(gè)concat?的方法表面上滿足要求,但是concat實(shí)際上是創(chuàng)建一個(gè)新數(shù)組,將兩個(gè)數(shù)組的元素添加到新數(shù)組中。
    ?*?所以,下面的代碼也可以替換為
    ?*?requestHeaders?=?requestHeaders.concat(this.options.requestHeaders);
    ?*?很顯然,作者不喜歡這樣的代碼方式
    ?*?而?apply?方法的語(yǔ)法?apply([thisObj[,argArray]])?本身就要求第二個(gè)參數(shù)是一個(gè)數(shù)組或者arguments對(duì)象。
    ?*?所以巧妙的實(shí)現(xiàn)了?concat?函數(shù)的作用。
    ?*?令人拍案叫絕啊!
    ?
    */
    ????
    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?狀態(tài),就調(diào)用回調(diào)函數(shù)
    ?
    */
    ????
    if ?(readyState? != ? 1 )
    ??????
    this .respondToReadyState( this .transport.readyState);
    ??},

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

    /*
    ?*?新增的回調(diào)函數(shù)處理,調(diào)用者還可以在options中定義?on200,?onSuccess?這樣的回調(diào)函數(shù)
    ?*?在?readyState?為完成狀態(tài)的時(shí)候調(diào)用
    ?
    */
    ????
    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?用于綁定一個(gè)html元素與?XmlHttp調(diào)用的返回值。類似與?buffalo?的?bind。
    ?*?如果?options?中有?insertion(見后)?對(duì)象的話,?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?對(duì)象,xmlhttp的返回值被賦給該對(duì)象的?innerHTML?屬性。
    ?*?相比新版本,containers?根據(jù)container參數(shù)定義?success?和?failure?引用,如果它們被定義的話,根據(jù)xmlhttp調(diào)用是否成功來選擇
    ?*?更新對(duì)象,假想調(diào)用可能如下:
    ?*?var?c?=?{success:?$("successDiv"),?failure:?$("failureDiv")};
    ?*?new?Ajax.Updater(c,?url,?options);
    ?*?那么調(diào)用成功則?successDiv?顯示成功信息或者數(shù)據(jù),反之?failureDiv?顯示錯(cuò)誤信息
    ?
    */
    ????
    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 );
    ????}

    /*
    ?*?如果調(diào)用者在傳入的options參數(shù)中定義?evalScripts=true,同時(shí)xmlhttp返回值的html中包含<script>標(biāo)簽的話,執(zhí)行該腳本
    ?
    */
    ????
    if ?( this .options.evalScripts? && ?scripts)?{
    /*
    ?*?注意前二十行左右還有一個(gè)?match?的聲明
    ?*?var?match????=?new?RegExp(Ajax.Updater.ScriptFragment,?'img');
    ?*?和此處的區(qū)別就是,正則表達(dá)式匹配標(biāo)記多一個(gè)?"g"。
    ?*?多個(gè)g,?所以?scripts?是一個(gè)數(shù)組,數(shù)組中每個(gè)元素是一段?<script></script>?文本。
    ?*?沒有g(shù),?scripts[i].match(match)[1]?匹配的就是?<script>標(biāo)記中的?script?代碼。
    ?*?關(guān)于正則表達(dá)式,請(qǐng)參考javascript的相關(guān)資料。
    ?
    */
    ??????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?可能是一個(gè)時(shí)間調(diào)整因素
    ???? 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);
    ??}
    });

    /*
    ?*?根據(jù)?class?attribute?的名字得到對(duì)象數(shù)組,支持?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?就象一個(gè)?java?的工具類,主要用來?隱藏/顯示/銷除?對(duì)象,以及獲取對(duì)象的簡(jiǎn)單屬性。
    ?*
    ?
    */
    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?
    = ?'';
    ????}
    ??},

    /*
    ?*從父節(jié)點(diǎn)中移除
    ?
    */
    ??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 ;
    ??},

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

    /*
    ?*為對(duì)象移除?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?做了一個(gè)符號(hào)連接,大概是兼容性的考慮
    ?
    */
    var ?Toggle? = ? new ?Object();
    Toggle.display?
    = ?Element.toggle;

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

    /*
    ?*?動(dòng)態(tài)插入內(nèi)容的實(shí)現(xiàn),MS的Jscript實(shí)現(xiàn)中對(duì)象有一個(gè)?insertAdjacentHTML?方法
    ?*?(http:?//msdn.microsoft.com/workshop/author/dhtml/reference/methods/insertadjacenthtml.asp)
    ?*?這里算是一個(gè)對(duì)象形式的封裝。
    ?
    */
    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?方法,則實(shí)行,這里相當(dāng)與定義了一個(gè)抽象的?initializeRange?方法
    ?
    */
    ??????
    if ?( this .initializeRange)? this .initializeRange();
    ??????
    this .fragment? = ? this .range.createContextualFragment( this .content);

    /*
    ?*?insertContent?也是一個(gè)抽象方法,子類必須實(shí)現(xiàn)
    ?
    */
    ??????
    this .insertContent();
    ????}
    ??}
    }

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

    /*
    ?*將內(nèi)容插入到指定節(jié)點(diǎn)的前面,?與指定節(jié)點(diǎn)同級(jí)
    */
    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);
    ??}
    });

    /*
    ?*將內(nèi)容插入到指定節(jié)點(diǎn)的第一個(gè)子節(jié)點(diǎn)前,于是內(nèi)容變?yōu)樵摴?jié)點(diǎn)的第一個(gè)子節(jié)點(diǎn)
    */
    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);
    ??}
    });

    /*
    ?*將內(nèi)容插入到指定節(jié)點(diǎn)的最后,于是內(nèi)容變?yōu)樵摴?jié)點(diǎn)的最后一個(gè)子節(jié)點(diǎn)
    */
    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);
    ??}
    });

    /*
    ?*將內(nèi)容插入到指定節(jié)點(diǎn)的后面,?與指定節(jié)點(diǎn)同級(jí)
    */
    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);
    ??}
    });

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

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

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

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

    /*
    ?*?表單工具類
    ?
    */
    var ?Form? = ?{
    /*
    ?*將表單元素序列化后的值(其實(shí)就是?name=value?形式的名值配對(duì))組合成?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(' & ');
    ??},
    ?
    /*
    ?*得到表單的所有元素對(duì)象
    ?
    */
    ??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;
    ??},
    ?
    /*
    ?*根據(jù)?type?和?name?過濾得到表單中符合的?<input>?對(duì)象
    ?
    */
    ??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;
    ??},

    /*
    ?*將指定表單的元素置于不可用狀態(tài)
    ?
    */ ?
    ??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 ';
    ????}
    ??},

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

    /*
    ?*使表單的第一個(gè)非?hidden?類型而且處于可用狀態(tài)的元素獲得焦點(diǎn)
    ?
    */
    ??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?
    = ?{
    /*
    ?*返回表單元素的值先序列化,?其實(shí)就是?name=value?形式的名值配對(duì)
    ?
    */
    ??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?的所謂序列化其實(shí)就是將表單的名字和值組合成一個(gè)數(shù)組
    ?
    */
    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?的下拉列表,返回的數(shù)組的第二個(gè)元素,是一個(gè)值數(shù)組
    ?
    */
    ??????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?會(huì)經(jīng)常用到,所以做了一個(gè)快捷引用
    ?*?取得某個(gè)表單控件的值,可以簡(jiǎn)化調(diào)用為?$F("username"),真是方便啊
    ?
    */
    var ?$F? = ?Form.Element.getValue;

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

    /*
    ?*?Abstract.TimedObserver?也沒有用?Class.create()?來創(chuàng)建,和Ajax.Base?意圖應(yīng)該一樣
    ?*?Abstract.TimedObserver?顧名思義,是套用Observer設(shè)計(jì)模式來跟蹤指定表單元素,
    ?*?當(dāng)表單元素的值發(fā)生變化的時(shí)候,就執(zhí)行回調(diào)函數(shù)
    ?*
    ?*?我想 Observer?與注冊(cè)onchange事件相似,不同點(diǎn)在于?onchange?事件是在元素失去焦點(diǎn)的時(shí)候才激發(fā)。
    ?*?同樣的與?onpropertychange?事件也相似,不過它只關(guān)注表單元素的值的變化,而且提供timeout的控制。
    ?*
    ?*?除此之外,Observer?的好處大概就在與更面向?qū)ο螅硗饪梢詣?dòng)態(tài)的更換回調(diào)函數(shù),這就比注冊(cè)事件要靈活一些。
    ?*?Observer?應(yīng)該可以勝任動(dòng)態(tài)數(shù)據(jù)校驗(yàn),或者多個(gè)關(guān)聯(lián)下拉選項(xiàng)列表的連動(dòng)等等
    ?*
    ?
    */
    Abstract.TimedObserver?
    = ? function ()?{}

    /*
    ?*?這個(gè)設(shè)計(jì)和?PeriodicalExecuter?一樣,bind?方法是實(shí)現(xiàn)的核心
    ?
    */
    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?監(jiān)視指定表單域的值是否變化
    ?
    */
    Form.Element.Observer?
    = ?Class.create();
    Form.Element.Observer.prototype?
    = ?( new ?Abstract.TimedObserver()).extend({
    ??getValue:?
    function ()?{
    ????
    return ?Form.Element.getValue( this .element);
    ??}
    });

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

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

    /*
    ?*?EventObserver?相比上面的?TimedObserver,是更具主動(dòng)性的一種監(jiān)測(cè)
    ?*?它直接為表單控件(根據(jù)?type?的不同)?注冊(cè)相應(yīng)的事件處理,?只要發(fā)現(xiàn)某個(gè)控件值發(fā)生改變,就執(zhí)行回調(diào)函數(shù)
    ?
    */
    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?類型的控件注冊(cè)?onclick?事件處理
    ?
    */
    ????????
    case ?'checkbox':?
    ????????
    case ?'radio':
    ??????????element.target?
    = ? this ;
    ??????????element.prev_onclick?
    = ?element.onclick? || ?Prototype.emptyFunction;
    /*
    ?*?相信這里有改進(jìn)的空間,應(yīng)該使用其后的?Event對(duì)象提供的注冊(cè)管理功能來統(tǒng)一注冊(cè)
    ?
    */
    ??????????element.onclick?
    = ? function ()?{
    ????????????
    this .prev_onclick();
    ????????????
    this .target.onElementEvent();
    ??????????}
    ??????????
    break ;

    /*
    ?*?其他類型的控件注冊(cè)?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 ;
    ??????}
    ????}???
    ??}
    }

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

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

    /*
    ?*?封裝事件處理的靜態(tài)工具對(duì)象
    ?
    */
    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事件時(shí)鼠標(biāo)以頁(yè)面為基準(zhǔn)的x坐標(biāo)值,?考慮到了滾動(dòng)條導(dǎo)致的位移差
    ?
    */
    ??pointerX:?
    function (event)?{
    ????
    return ?event.pageX? || ?(event.clientX? +
    ??????(document.documentElement.scrollLeft?
    || ?document.body.scrollLeft));
    ??},

    /*
    ?*click事件時(shí)鼠標(biāo)以頁(yè)面為基準(zhǔn)的y坐標(biāo)值,?考慮到了滾動(dòng)條導(dǎo)致的位移差
    ?
    */
    ??pointerY:?
    function (event)?{
    ????
    return ?event.pageY? || ?(event.clientY? +
    ??????(document.documentElement.scrollTop?
    || ?document.body.scrollTop));
    ??},

    /*
    ?*停止冒泡(參見?http://www.quirksmode.org/js/events_order.html)?和阻止瀏覽器執(zhí)行與事件相關(guān)的默認(rèn)動(dòng)作
    ?*?比如
    ?*?<a?>google</a>
    ?*?那么點(diǎn)擊該連接,頁(yè)面并不會(huì)執(zhí)行轉(zhuǎn)向
    ?
    */
    ??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
    /*

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

    /*
    ?*其后的代碼封裝了事件的注冊(cè)和反注冊(cè),避免ie的內(nèi)存泄露的bug
    ?*?參見??http://javascript.weblogsinc.com/entry/1234000267034921/
    ?
    */
    ??observers:?
    false ,
    ?
    /*
    ?*this.observers?的數(shù)據(jù)格式是一個(gè)二維數(shù)組,二維的數(shù)組分別四個(gè)元素分別是
    ?*?[注冊(cè)事件對(duì)象,事件名,事件處理函數(shù),事件處理模式布爾值]
    ?
    */
    ??_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?對(duì)象設(shè)置?request?header?的代碼異曲同工
    ?
    */
    ??????Event.stopObserving.apply(
    this ,?Event.observers[i]);
    ??????Event.observers[i][
    0 ]? = ? null ;
    ????}
    ????Event.observers?
    = ? false ;
    ??},

    /*
    ?*注冊(cè)對(duì)象的事件處理,并記錄到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);
    ??},

    /*
    ?*取消對(duì)象已注冊(cè)的事件處理
    ?
    */
    ??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? */
    /*
    ?*頁(yè)面onload?的時(shí)候取消所有事件注冊(cè),避免ie內(nèi)存泄漏的bug
    */
    Event.observe(window,?'unload',?Event.unloadCache,?
    false );

    /*
    ?*?Position?對(duì)象也是常用的工具類,提供了獲取元素在頁(yè)面上位置的函數(shù),Drag&Drop的效果一定常會(huì)用到
    ?*?具體的應(yīng)用參考?script.aculo.us?基于prototype?的實(shí)現(xiàn),尤其是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 ;
    ??},

    /*
    ?*當(dāng)對(duì)象所處的頁(yè)面有滾動(dòng)條是,計(jì)算位移
    ?
    */
    ??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];
    ??},

    /*
    ?*計(jì)算出對(duì)象在頁(yè)面上的位置
    ?
    */
    ??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
    /*

    ?*判斷一個(gè)坐標(biāo)是否在指定元素的空間范圍中
    ?*?比如你想判斷鼠標(biāo)點(diǎn)擊點(diǎn)的坐標(biāo)是否在某個(gè)層或窗口
    ?
    */
    ??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
    /*

    ?*調(diào)用該方法時(shí),確保首先調(diào)用了within方法
    ?*?如果x,y坐標(biāo)位于element的空間范圍中,那么返回一個(gè)小于1的標(biāo)示位置的值,比如0.5標(biāo)示該坐標(biāo)位于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;
    ??},

    /*
    ?*復(fù)制源對(duì)象的空間數(shù)據(jù)到目的對(duì)象。
    ?*?常用的地方:拖綴一個(gè)層到新地方時(shí),常常動(dòng)態(tài)構(gòu)造和該層同樣大小的虛層。
    ?
    */
    ??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 技術(shù)資源 閱讀(290) 評(píng)論(0)  編輯  收藏

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲AV人人澡人人爽人人夜夜| 日韩视频在线观看免费| 日韩一区二区免费视频| 国产99在线|亚洲| 精品久久久久久久久免费影院| 亚洲精品网站在线观看你懂的| 99热这里有免费国产精品| 色拍自拍亚洲综合图区| 亚洲成人免费网站| 亚洲人成网站在线观看播放青青| 日本亚洲视频在线| 中文字幕一区二区三区免费视频| 伊人久久大香线蕉亚洲五月天 | 国产精品永久免费10000| 亚洲春色在线观看| 99久久国产热无码精品免费| 亚洲制服丝袜第一页| 成年性生交大片免费看| 亚洲va中文字幕| 免费v片在线观看无遮挡| 国产一卡2卡3卡4卡无卡免费视频| 亚洲AV无码专区在线厂| 在线免费视频一区二区| 亚洲日韩在线中文字幕综合 | 免费人成网站7777视频| 又粗又长又爽又长黄免费视频| 亚洲视频在线一区二区| 大地资源网高清在线观看免费| 亚洲成人免费在线| 国产精品视频免费观看| 亚洲欧美日韩综合久久久久| 国产午夜免费福利红片| 久久最新免费视频| 亚洲第一中文字幕| 黄页网站免费观看| 精品国产日韩亚洲一区在线| 亚洲欧洲自拍拍偷精品 美利坚| 两个人看www免费视频| 亚洲资源在线视频| 成人毛片免费观看| 黄色免费网址大全|