﻿// JScript 文件
/*
prototype 框架 Ajax封装对象
一> Ajax.Request类
    定义:  var myAjax = new Ajax.Request("Url",{optons-参数})
    Url-- 要访问的地址
    options 参数列表,---  匿名对像 , 也可以在外部定义以参数形式赋给Ajax.Request对像
    {
       method:"get/post",                        //传值方式
       parameters:"name1=value&name2=value2...", //请求参数多个用'&'相连
       onComplete:show                           //请求完成后,访问的方法(回调函数,此函数有一参数,用'参数'.responseText得到反回值)
       asynchronous:true/false                   //异步或是同步 --  此项多余,强制 "异步"
     }

二> Ajax.Updater   --- 将 返回的 Html 代码 直接填充 document容器
    定义: var myAjax = new Ajax.Updater('容器',Url,{method:'get/post',parameters:'pars'})
    容器 : 接受 Html代码的窗口 如:div ,span,td....

    扩展:
    var myAjax = new Ajax.Updater
                (
                  {success:'success容器',onFailure:'Error:容器'},
                   Url,
                  {method:'get/post',parameters:pars,evalScripts:true(执行返回Html中的脚本),insertion:Insertion.Top(内容插入到容器顶端)}
                 );
   成功,结果填充 success容器,失败,填充 Error容器
*/
/**
 * 定义 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;
  },
  
  emptyFunction: function() {}
}

/**//**
 * 我以为此时的Ajax对象起到命名空间的作用。
 * Ajax.Base 声明为一个基础对象类型
 * 注意 Ajax.Base 并没有使用 Class.create() 的方式来创建，我想是因为作者并不希望 Ajax.Base 被库使用者实例化。
 * 作者在其他对象类型的声明中，将会继承于它。
 * 就好像 java 中的私有抽象类
 */
Ajax.Base = function() {};
Ajax.Base.prototype = {
  /**//**
   * extend (见prototype.js中的定义) 的用法真是让人耳目一新
   * 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 || {});
  }
}

/**//**
 * 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'];

/**//**
 * 
 */
Ajax.Request.prototype = (new Ajax.Base()).extend({
  initialize: function(url, options) {
    this.transport = Ajax.getTransport();
    this.setOptions(options);
  
    try {
      if (this.options.method == 'get')
        url += '?' + this.options.parameters + '&_=';
    
   /**//**
    * 此处好像强制使用了异步方式，而不是依照 this.options.asynchronous 的值
    */
      this.transport.open(this.options.method, url, true);
      
   /**//**
    * 这里提供了 XmlHttp 传输过程中每个步骤的回调函数
    */
      if (this.options.asynchronous) {
        this.transport.onreadystatechange = this.onStateChange.bind(this);
        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
      }
              
      this.transport.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
      this.transport.setRequestHeader('X-Prototype-Version', Prototype.Version);

      if (this.options.method == 'post') {
        this.transport.setRequestHeader('Connection', 'close');
        this.transport.setRequestHeader('Content-type',
          'application/x-www-form-urlencoded');
      }
      
      this.transport.send(this.options.method == 'post' ? 
        this.options.parameters + '&_=' : null);
                      
    } catch (e) {
    }    
  },
      
  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];
    (this.options['on' + event] || Ajax.emptyFunction)(this.transport);
  }
});

/**//**
 * Ajax.Updater 用于绑定一个html元素与 XmlHttp调用的返回值。类似与 buffalo 的 bind。
 * 如果 options 中有 insertion(from dom.js) 对象的话, insertion 能提供更多的插入控制。
 */
Ajax.Updater = Class.create();
Ajax.Updater.prototype = (new Ajax.Base()).extend({
  initialize: function(container, url, options) {
    this.container = $(container);
    this.setOptions(options);
  
    if (this.options.asynchronous) {
      this.onComplete = this.options.onComplete;
      this.options.onComplete = this.updateContent.bind(this);
    }
    
    this.request = new Ajax.Request(url, this.options);
    
    if (!this.options.asynchronous)
      this.updateContent();
  },
  
  updateContent: function() {
    if (this.options.insertion) {
      new this.options.insertion(this.container,
        this.request.transport.responseText);
    } else {
      this.container.innerHTML = this.request.transport.responseText;
    }

    if (this.onComplete) {
      setTimeout((function() {this.onComplete(this.request)}).bind(this), 10);
    }
  }
});