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 技術資源 閱讀(291) 評論(0)  編輯  收藏

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


          網站導航:
           
          主站蜘蛛池模板: 永丰县| 普兰县| 江门市| 泰安市| 铁岭县| 庆城县| 凌海市| 万盛区| 固原市| 土默特右旗| 新昌县| 黑山县| 莱西市| 东海县| 阜平县| 二连浩特市| 延津县| 兴宁市| 景德镇市| 泗洪县| 新巴尔虎右旗| 青阳县| 尼勒克县| 晴隆县| 上杭县| 博乐市| 江门市| 嘉义市| 上犹县| 扎囊县| 蒙阴县| 扶风县| 漳平市| 平远县| 嵩明县| 永寿县| 廊坊市| 西乌珠穆沁旗| 石首市| 繁昌县| 芜湖县|