Ruby's Louvre

每天学习一点点算法

导航

mass Framework ajax模块

由于ajax模块要涉及到后台的配合才能看到后台,因此我先给出后台代码,如果会rails的人,可以复制下来搭建相应的运行环境。

控制器部分


class HomeController < ApplicationController
   skip_before_filter :verify_authenticity_token  

  def index
    #如果XMLHttpRequest请求
    if request.xhr?
      respond_to do |format|
        format.json do 
          p "format.json"
          render :json => {
            "aaa"=>"ruby",
            "bbb"=>"louvre",
            "ccc"=>{
              "ddd"=>Time.now,
              "eee"=>"司徒正美"
            }
          }
        end
        format.html do 
          render 'home/html_test.erb'
        end
        format.text do
          p "format.text"
          render :text=> "输出纯文本消息"
        end
        format.js do
          p "format.js"
          render :js => "alert('Hello Rails');"
        end        
        format.xml do
          p "format.xml"
          #http://ap.rubyonrails.org/classes/Builder/XmlMarkup.html
          render :template => 'home/test.rxml', :layout => false
        end
      end
    end
  end
  
  def upload
    render :text => "OK"
  end

end

视图部分:

html_test.erb

<table class="blue_table">
  <colgroup><col class="grey" width="30%">
  <col class="yellow">
  </colgroup><thead>
    <tr>
      <th colspan="2">javascript相关的小研究心得</th>
    </tr>
  </thead>
  <tbody>
     <tr>
      <td><a href="2009/11/06/1597523.html">获取函数名</a></td>
      <td><a href="2011/01/05/1926226.html">iframe高度自适应</a></td>
   </tr>
      <tr>
      <td><a href="2010/01/20/1652646.html">类型判定</a></td>
      <td><a href="2010/05/25/1742173.html">jsonp跨域</a></td>
   </tr>
   <tr>
      <td><a href="2010/05/18/1738034.html">修复IE6 base bug</a></td>
      <td><a href="2010/04/06/1705817.html">getBasePath函数</a></td>
   </tr>
    <tr>
      <td><a href="2010/04/15/1712780.html">domReady</a></td>
      <td><a href="2009/10/14/1583362.html">判定浏览器</a></td>
    </tr>
    <tr>
      <td><a href="2009/09/24/1572977.html">获取随机颜色</a></td>
      <td><a href="2009/10/14/1583523.html">contains函数</a></td>
    </tr>
    <tr>
      <td><a href="2009/10/30/1593094.html">惰性函数</a></td>
      <td><a href="2009/11/09/1598761.html">currying函数</a></td>
    </tr>
    <tr>
      <td><a href="2009/11/08/1598383.html">字符串的乘法</a></td>
      <td><a href="2009/10/31/1593484.html">javascript 动态解析脚本</a></td>
    </tr>
    <tr>
      <td><a href="2009/11/13/1602122.html">动态this与动态绑定</a></td>
      <td><a href="2009/11/10/1599978.html">forEach函数</a></td>
    </tr>
    <tr>
      <td><a href="2009/07/17/1525637.html">移除DOM节点</a></td>
      <td><a href="2009/07/24/1529640.html">getElementsByClassName</a></td>
    </tr>
    <tr>
      <td><a href="2009/07/24/1530020.html">跨浏览器的事件写法</a></td>
      <td><a href="2009/07/24/1530074.html">javascript的闭包</a></td>
    </tr>
    <tr>
      <td><a href="2009/08/01/1536710.html">iframe元素用法总结</a></td>
      <td><a href="2009/08/08/1541578.html">javascript AOP实现</a></td>
    </tr>
    <tr>
      <td><a href="2009/08/19/1550088.html">JS类写法的性能研究</a></td>
      <td><a href="2009/08/20/1550526.html">javascript 键盘事件总结</a></td>
    </tr>
    <tr>
      <td><a href="2009/08/21/1551270.html">javascript变量的作用域</a></td>
      <td><a href="2009/10/07/1578629.html">动态加载图片与脚本</a></td>
    </tr>
    <tr>
      <td><a href="2009/08/09/1542174.html">javascript事件代理</a></td>
      <td><a href="2009/08/26/1554204.html">javascript的事件加载</a></td>
    </tr>
  <tr>
      <td><a href="2010/01/06/1640148.html">高效地获取XMLhttp对象</a></td>
      <td><a href="2009/08/24/1552862.html">javascript的鼠标事件</a></td>
    </tr>
    <tr>
      <td><a href="2009/07/14/1523104.html">动态添加样式表规则</a> <a href="2009/08/30/1556869.html">2</a></td>
      <td><a href="2010/02/11/1667364.html">自动执行函数</a></td>
    </tr>
    <tr>
      <td><a href="2009/09/05/1559883.html">精确获取样式属性</a> <a href="2009/09/08/1562212.html">2</a></td>
      <td><a href="2009/09/08/1562444.html">精确获取页面元素的位置</a></td>
    </tr>
    <tr>
      <td><a href="2010/02/11/1667364.html">自动执行函数</a></td>
      <td><a href="2009/07/24/1530020.html">事件兼容</a></td>
    </tr>
   <tr>
      <td><a href="2009/09/16/1566699.html">缓动效果</a> <a href="2009/09/17/1567607.html">2</a></td>
      <td><a href="2009/10/01/1577219.html">无缝滚动</a> <a href="2009/10/03/1577735.html">2</a></td>
    </tr>
    <tr>
      <td><a href="2009/09/30/1576699.html">javascript图片轮换</a> <a href="2009/10/06/1578289.html">2</a></td>
      <td>
        <a href="2009/10/09/1578966.html">javascript线性渐变</a> 
        <a href="2009/10/10/1580061.html">2</a> 
        <a href="2009/10/14/1582876.html">3</a> 
    </td>
    </tr>
  </tbody>
</table>

test.rxml


xml = Builder::XmlMarkup.new
xml.instruct!                   # 
xml.html {                      # 
  xml.head {                    #   
    xml.title("History")        #     History
  }                            #   
  xml.body {                    #   
    xml.comment! "HI"           #     
    xml.h1("Header")            #     

Header

xml.p("paragraph") #

paragraph

} # }

路由配置

  map.resources  :homes, :member => {:upload => :post }
  map.home '' ,:controller => 'home',:action => 'index'

ajax模块源码:

//数据请求模块
(function(global,DOC){
    var dom = global[DOC.URL.replace(/(#.+|\W)/g,'')];
    dom.define("ajax","node,emitter", function(){
        dom.log("已加载ajax模块");
        var r20 = /%20/g,
        rCRLF = /\r?\n/g,
        encode = global.encodeURIComponent,
        rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
        rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
        rnoContent = /^(?:GET|HEAD)$/,
        rquery = /\?/,
        rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
        // Document location
        ajaxLocation
        // #8138, IE may throw an exception when accessing
        // a field from window.location if document.domain has been set
        try {
            ajaxLocation = global.location.href;
        } catch( e ) {
            // Use the href attribute of an A element
            // since IE will modify it given document.location
            ajaxLocation = DOC.createElement( "a" );
            ajaxLocation.href = "";
            ajaxLocation = ajaxLocation.href;
        }

        // Segment location into parts
        var ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [],
        transports = { },//传送器
        converters ={//转换器
            text: function(dummyXHR,text,xml){
                return text != undefined ? text : ("xml" in xml ?  xml.xml: new XMLSerializer().serializeToString(xml));
            },
            xml : function(dummyXHR,text,xml){
                return xml != undefined ? xml : dom.parseXML(text);
            },
            html : function(dummyXHR,text,xml){
                return  dom.parseHTML(text);
            },
            json : function(dummyXHR,text,xml){
                return  dom.parseJSON(text);
            },
            script: function(dummyXHR,text,xml){
                dom.globalEval(text);
            }
        },
        accepts  = {
            xml: "application/xml, text/xml",
            html: "text/html",
            text: "text/plain",
            json: "application/json, text/javascript",
            script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript",
            "*": "*/*"
        },
        defaultOptions = {
            type:"GET",
            contentType: "application/x-www-form-urlencoded; charset=UTF-8",
            async:true,
            dataType:"text",
            jsonp: "callback"
        };

        function normalizeOptions(o) {
            // deep mix
            o = dom.Object.merge.call( {},defaultOptions, o);
            //判定是否跨域
            if (o.crossDomain == null) {
                var parts = rurl.exec(o.url.toLowerCase());
                o.crossDomain = !!( parts &&
                    ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
                        ( parts[ 3 ] || ( parts[ 1 ] === "http:" ?  80 : 443 ) )
                        !=
                        ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ?  80 : 443 ) ) )
                    );
            }
            //转换data为一个字符串
            if ( o.data && o.data !== "string") {
                o.data = dom.param( o.data );
            }
            //type必须为大写
            o.type = o.type.toUpperCase();
            o.hasContent = !rnoContent.test(o.type);

            if (!o.hasContent) {//如果为GET请求,则参数依附于url上
                if (o.data) {
                    o.url += (rquery.test(o.url) ? "&" : "?" ) + o.data;
                }
                if (o.cache === false) {
                    o.url += (rquery.test(o.url) ? "&" : "?" ) + "_time=" + Date.now();
                }
            }
            return o;
        }

        "get post".replace(dom.rword,function(method){
            dom[ method ] = function( url, data, callback, type ) {
                // shift arguments if data argument was omitted
                if ( dom.isFunction( data ) ) {
                    type = type || callback;
                    callback = data;
                    data = undefined;
                }
                return dom.ajax({
                    type: method,
                    url: url,
                    data: data,
                    success: callback,
                    dataType: type
                });
            };

        });

        dom.mix(dom,{
            getScript: function( url, callback ) {
                return dom.get( url, null, callback, "script" );
            },

            getJSON: function( url, data, callback ) {
                return dom.get( url, data, callback, "json" );
            },
            upload: function(url, form, data, callback, dataType) {
                if (dom.isFunction(data)) {
                    dataType = callback;
                    callback = data;
                    data = undefined;
                }
                return dom.ajax({
                    url:url,
                    type:'post',
                    dataType:dataType,
                    form:form,
                    data:data,
                    success:callback
                });
            },
            serialize : function(form) {
                return dom.param(dom.serializeArray(form));
            },
            serializeArray : function(form){
                // 不直接转换form.elements,防止以下情况:   <form > <input name="elements"/><input name="test"/></form>
                var elements = dom.slice(form||[]), ret = []
                elements.forEach(function(elem){
                    if( elem.name && !elem.disabled && ( "checked" in elem ? elem.checked : 1 )){
                        var val = dom( elem ).val();
                        if(Array.isArray(val)){
                            val.forEach(function(value){
                                ret.push({
                                    name: elem.name,
                                    value: value.replace( rCRLF, "\r\n" )
                                });
                            });
                        }else if(typeof val == "string"){
                            ret.push({
                                name: elem.name,
                                value: val.replace( rCRLF, "\r\n" )
                            });
                        }
                    }
                });
                return ret;
            },
            param : function( object ) {//objectToQuery
                var ret = [];
                function add( key, value ){
                    ret[ ret.length ] = encode(key) + '=' + encode(value);
                }
                if ( Array.isArray(object) ) {
                    for ( var i = 0, length = object.length; i < length; i++ ) {
                        add( object[i].name, object[i].value );
                    }
                } else {
                    function buildParams(obj, prefix) {
                        if ( Array.isArray(obj) ) {
                            for ( var i = 0, length = obj.length; i < length; i++ ) {
                                buildParams( obj[i], prefix );
                            }
                        } else if( dom.isPlainObject(obj) ) {
                            for ( var j in obj ) {
                                var postfix = ((j.indexOf("[]") > 0) ? "[]" : ""); // move the brackets to the end (if applicable)
                                buildParams(obj[j], (prefix ? (prefix+"["+j.replace("[]", "")+"]"+postfix) : j) );
                            }
                        } else {
                            add( prefix, dom.isFunction(obj) ? obj() : obj );
                        }
                    }
                    buildParams(obj);
                }
                return ret.join("&").replace(r20, "+");
            }
        });

        var ajax = dom.ajax = function(object) {
            if (!object.url) {
                return undefined;
            }
            var options = normalizeOptions(object),//规整化参数对象
            //创建一个伪XMLHttpRequest,能处理complete,success,error等多投事件
            dummyXHR = new dom.jXHR(options),
            dataType = options.dataType;

            if(options.form && options.form.nodeType ==1){
                dataType = "iframe";
            }else if(dataType == "jsonp"){
                if(options.crossDomain){
                    ajax.fire("start", dummyXHR, options.url,options.jsonp);//用于jsonp请求
                    dataType = "script"
                }else{
                    dataType = dummyXHR.options.dataType = "json";
                }
            }
            var transportContructor = transports[dataType] || transports._default,
            transport = new transportContructor();
            transport.dummyXHR = dummyXHR;
            dummyXHR.transport = transport;
            if (options.contentType) {
                dummyXHR.setRequestHeader("Content-Type", options.contentType);
            }

            //添加dataType所需要的Accept首部
            dummyXHR.setRequestHeader( "Accept", accepts[dataType] ? accepts[ dataType ] +  ", */*; q=0.01"  : accepts[ "*" ] );
            for (var i in options.headers) {
                dummyXHR.setRequestHeader(i, options.headers[ i ]);
            }

            "Complete Success Error".replace(dom.rword, function(name){
                var method = name.toLowerCase();
                dummyXHR[method] = dummyXHR["on"+name];
                if(typeof options[method] === "function"){
                    dummyXHR[method](options[method]);
                    delete dummyXHR.options[method];
                    delete options[method];
                }
            });
            dummyXHR.readyState = 1;
            // Timeout
            if (options.async && options.timeout > 0) {
                dummyXHR.timeoutID = setTimeout(function() {
                    dummyXHR.abort("timeout");
                }, options.timeout);
            }

            try {
                dummyXHR.state = 1;//已发送
                transport.send();
            } catch (e) {
                if (dummyXHR.status < 2) {
                    dummyXHR.callback(-1, e);
                } else {
                    dom.log(e);
                }
            }

            return dummyXHR;
        }

        dom.mix(ajax, dom.emitter);
        ajax.isLocal = rlocalProtocol.test(ajaxLocParts[1]);
        /**
         * jXHR类,用于模拟原生XMLHttpRequest的所有行为
         */
        dom.jXHR = dom.factory({
            include:dom.emitter,
            init:function(option){
                dom.mix(this, {
                    responseData:null,
                    timeoutID:null,
                    responseText:null,
                    responseXML:null,
                    responseHeadersString:"",
                    responseHeaders:null,
                    requestHeaders:{},
                    readyState:0,
                    //internal state
                    state:0,
                    statusText:null,
                    status:0,
                    transport:null
                });

                this.defineEvents("complete success error");
                this.setOptions(option);
            },

            fire: function(type){
                var target = this, table = dom.data( target,"@events") ,args = dom.slice(arguments,1);
                if(!table) return;
                var queue = table[type];
                if (  queue ) {
                    for ( var i = 0, bag; bag = queue[i++]; ) {
                        bag.callback.apply( target, args );
                    }
                }
            },

            setRequestHeader: function(name, value) {
                this.requestHeaders[ name ] = value;
                return this;
            },

            getAllResponseHeaders: function() {
                return this.state === 2 ? this.responseHeadersString : null;
            },
            getResponseHeader: function(key,/*internal*/ match) {
                if (this.state === 2) {
                    if (!this.responseHeaders) {
                        this.responseHeaders = {};
                        while (( match = rheaders.exec(this.responseHeadersString) )) {
                            this.responseHeaders[ match[1] ] = match[ 2 ];
                        }
                    }
                    match = this.responseHeaders[ key];
                }
                return match === undefined ? null : match;
            },
            // 重写 content-type 首部
            overrideMimeType: function(type) {
                if (!this.state) {
                    this.mimeType = type;
                }
                return this;
            },

            // 中止请求
            abort: function(statusText) {
                statusText = statusText || "abort";
                if (this.transport) {
                    this.transport._callback(0, 1);
                }
                this.callback(0, statusText);
                return this;
            },
            /**
             * 用于触发success,error,complete等回调
             * http://www.cnblogs.com/rubylouvre/archive/2011/05/18/2049989.html
             * @param {Number} status 状态码
             * @param {String} statusText 对应的扼要描述
             */
            callback:function(status, statusText) {
                // 只能执行一次,防止重复执行
                // 例如完成后,调用 abort
                // 到这要么成功,调用success, 要么失败,调用 error, 最终都会调用 complete
                if (this.state == 2) {//2:已执行回调
                    return;
                }
                this.state = 2;
                this.readyState = 4;
                var isSuccess;
                if (status >= 200 && status < 300 || status == 304) {
                    if (status == 304) {
                        statusText = "notmodified";
                        isSuccess = true;
                    } else {
                        var text = this.responseText, xml = this.responseXML,dataType = this.options.dataType;
                        try{
                            dom.log(text)
                            this.responseData = converters[dataType](this, text, xml);
                            statusText = "success";
                            isSuccess = true;
                            dom.log("dummyXHR.callback success");
                        } catch(e) {
                            dom.log("dummyXHR.callback parsererror")
                            statusText = "parsererror : " + e;
                        }
                    }

                }
                else {
                    if (status < 0) {
                        status = 0;
                    }
                }

                this.status = status;
                this.statusText = statusText;
                if (this.timeoutID) {
                    clearTimeout(this.timeoutID);
                }
                if (isSuccess) {
                    this.fire("success",this.responseData,statusText);
                } else {
                    this.fire("error",this.responseData,statusText);
                }
                this.fire("complete",this.responseData,statusText);
                this.transport = undefined;
            }
        });

        //http://www.cnblogs.com/rubylouvre/archive/2010/04/20/1716486.html
        //【XMLHttpRequest】传送器,专门用于上传
        var s = ["XMLHttpRequest",
        "ActiveXObject('Msxml2.XMLHTTP.6.0')",
        "ActiveXObject('Msxml2.XMLHTTP.3.0')",
        "ActiveXObject('Msxml2.XMLHTTP')",
        "ActiveXObject('Microsoft.XMLHTTP')"];
        if( !-[1,] && global.ScriptEngineMinorVersion() === 7 && location.protocol === "file:"){
            s.shift();
        }
        for(var i = 0 ,axo;axo = s[i++];){
            try{
                if(eval("new "+ axo)){
                    dom.xhr = new Function( "return new "+axo);
                    break;
                }
            }catch(e){}
        }
        if (dom.xhr) {
            var nativeXHR = new dom.xhr(), allowCrossDomain = false;
            if ("withCredentials" in nativeXHR) {
                allowCrossDomain = true;
            }
            //添加通用XMLHttpRequest传送器
            transports._default =  dom.factory({
                //发送请求
                send:function() {
                    var self = this,
                    dummyXHR = self.dummyXHR,
                    options = dummyXHR.options;
                    dom.log("XhrTransport.sending.....");
                    if (options.crossDomain && !allowCrossDomain) {
                        dom.error("do not allow crossdomain xhr !");
                        return;
                    }

                    var nativeXHR = new dom.xhr(), i;
                    self.xhr = nativeXHR;
                    if (options.username) {
                        nativeXHR.open(options.type, options.url, options.async, options.username, options.password)
                    } else {
                        nativeXHR.open(options.type, options.url, options.async);
                    }
                    // Override mime type if supported
                    if (dummyXHR.mimeType && nativeXHR.overrideMimeType) {
                        nativeXHR.overrideMimeType(dummyXHR.mimeType);
                    }
                    // 用于进入request.xhr?分支
                    if (!options.crossDomain && !dummyXHR.requestHeaders["X-Requested-With"]) {
                        dummyXHR.requestHeaders[ "X-Requested-With" ] = "XMLHttpRequest";
                    }
                    try {
                        for (i in dummyXHR.requestHeaders) {
                            nativeXHR.setRequestHeader(i, dummyXHR.requestHeaders[ i ]);
                        }
                    } catch(e) {
                        dom.log(" nativeXHR setRequestHeader occur error ");
                    }

                    nativeXHR.send(options.hasContent && options.data || null);
                    //在同步模式中,IE6,7可能会直接从缓存中读取数据而不会发出请求,因此我们需要手动发出请求
                    if (!options.async || nativeXHR.readyState == 4) {
                        self._callback();
                    } else {
                        nativeXHR.onreadystatechange = function() {
                            self._callback();
                        }
                    }
                },

                //用于获取原始的responseXMLresponseText 修正status statusText
                //第二个参数为1时中止清求
                _callback:function(event, isAbort) {
                    // Firefox throws exceptions when accessing properties
                    // of an xhr when a network error occured
                    // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
                    try {
                        var self = this,nativeXHR = self.xhr, dummyXHR = self.dummyXHR;
                        if (isAbort || nativeXHR.readyState == 4) {
                            nativeXHR.onreadystatechange = dom.noop;
                            if (isAbort) {
                                // 完成以后 abort 不要调用
                                if (nativeXHR.readyState !== 4) {
                                    //IE的XMLHttpRequest.abort实现于 MSXML 3.0+
                                    //http://blogs.msdn.com/b/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx
                                    try{
                                        nativeXHR.abort &&  nativeXHR.abort();
                                    }catch(e){};
                                }
                            } else {
                                var status = nativeXHR.status;
                                dummyXHR.responseHeadersString = nativeXHR.getAllResponseHeaders();
                                var xml = nativeXHR.responseXML;
                                // Construct response list
                                if (xml && xml.documentElement /* #4958 */) {
                                    dummyXHR.responseXML = xml;
                                }
                                dummyXHR.responseText = nativeXHR.responseText;
                                //火狐在跨城请求时访问statusText值会抛出异常
                                try {
                                    var statusText = nativeXHR.statusText;
                                } catch(e) {
                                    statusText = "";
                                }
                                //用于处理特殊情况,如果是一个本地请求,只要我们能获取数据就假当它是成功的
                                if (!status && ajax.isLocal && !dummyXHR.options.crossDomain) {
                                    status = dummyXHR.responseText ? 200 : 404;
                                //IE有时会把204当作为1223
                                //returning a 204 from a PUT request - IE seems to be handling the 204 from a DELETE request okay.
                                } else if (status === 1223) {
                                    status = 204;
                                }
                                dummyXHR.callback(status, statusText);
                            }
                        }
                    } catch (firefoxAccessException) {
                        dom.log(firefoxAccessException)
                        nativeXHR.onreadystatechange = dom.noop;
                        if (!isAbort) {
                            dummyXHR.callback(-1, firefoxAccessException);
                        }
                    }
                }
            });

        }
        //【script节点】传送器,只用于跨域的情况
        transports.script = dom.factory({
            send:function() {
                var self = this,
                dummyXHR = self.dummyXHR,
                options = dummyXHR.options,
                head = dom.HEAD,
                script = self.script = DOC.createElement("script");
                script.async = "async";
                dom.log("ScriptTransport.sending.....");
                if (options.charset) {
                    script.charset = options.charset
                }
                //当script的资源非JS文件时,发生的错误不可捕获
                script.onerror = script.onload = script.onreadystatechange = function(e) {
                    e = e || global.event;
                    self._callback((e.type || "error").toLowerCase());
                };
                script.src = options.url
                head.insertBefore(script, head.firstChild);
            },

            _callback:function(event, isAbort) {
                var node = this.script,
                dummyXHR = this.dummyXHR;
                if (isAbort || dom.rreadystate.test(node.readyState)  || event == "error"  ) {
                    node.onerror = node.onload = node.onreadystatechange = null;
                    var parent = node.parentNode;
                    if(parent && parent.nodeType === 1){
                        parent.removeChild(node);
                        this.script = undefined;
                    }
                    //如果没有中止请求并没有报错
                    if (!isAbort && event != "error") {
                        dummyXHR.callback(200, "success");
                    }
                    // 非 ie<9 可以判断出来
                    else if (event == "error") {
                        dummyXHR.callback(500, "scripterror");
                    }
                }
            }
        });

        //http://www.decimage.com/web/javascript-cross-domain-solution-with-jsonp.html
        //JSONP请求,借用【script节点】传送器
        converters["script json"] = function(dummyXHR){
            return dom["jsonp"+ dummyXHR.uniqueID ]();
        }
        ajax.bind("start", function(e, dummyXHR, url, jsonp) {
            dom.log("jsonp start...");
            var jsonpCallback = "jsonp"+dummyXHR.uniqueID;
            dummyXHR.options.url = url  + (rquery.test(url) ? "&" : "?" ) + jsonp + "=" + DOC.URL.replace(/(#.+|\W)/g,'')+"."+jsonpCallback;
            dummyXHR.options.dataType = "script json";
            //将后台返回的json保存在惰性函数中
            global.dom[jsonpCallback]= function(json) {
                global.dom[jsonpCallback] = function(){
                    return json;
                };
            };
        });

        function createIframe(dummyXHR, transport) {
            var id = "iframe-upload-"+dummyXHR.uniqueID;
            var iframe = dom.parseHTML("<iframe " +
                " id='" + id + "'" +
                " name='" + id + "'" +
                " style='display:none'/>").firstChild;
            iframe.transport = transport;
            return   (DOC.body || DOC.documentElement).insertBefore(iframe,null);
        }

        function addDataToForm(data, form) {
            var input = DOC.createElement("input"), ret = [];
            input.type = 'hidden';
            dom.serializeArray(data).forEach(function(obj){
                var elem =  input.cloneNode(true);
                elem.name = obj.name;
                elem.value = obj.value;
                form.appendChild(elem);
                ret.push(elem);
            });
            return ret;
        }
        //【iframe】传送器,专门用于上传
        //http://www.profilepicture.co.uk/tutorials/ajax-file-upload-xmlhttprequest-level-2/ 上传
        transports.iframe = dom.factory({
            send:function() {
                var self = this,
                dummyXHR = self.dummyXHR,
                options = dummyXHR.options,
                form = options.form
                //form.enctype的值
                //1:application/x-www-form-urlencoded	在发送前编码所有字符(默认)
                //2:multipart/form-data	不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
                //3:text/plain	空格转换为 "+" 加号,但不对特殊字符编码。
                this.backups = {
                    target:form.target || "",
                    action:form.action || "",
                    enctype:form.enctype,
                    method:form.method
                };

                var iframe = createIframe(dummyXHR, this);
                //必须指定method与enctype,要不在FF报错
                //“表单包含了一个文件输入元素,但是其中缺少 method=POST 以及 enctype=multipart/form-data,所以文件将不会被发送。”
                // 设置target到隐藏iframe,避免整页刷新
                form.target =  "iframe-upload-"+dummyXHR.uniqueID;
                form.action =  options.url;
                form.method =  "POST";
                form.enctype = "multipart/form-data";
                this.fields = options.data ? addDataToForm(options.data, form) : [];
                this.form = form;//一个表单元素
                dom.log("iframe transport...");
                dom(iframe).bind("load",this._callback).bind("error",this._callback);
                form.submit();
            },

            _callback:function(event  ) {
                var iframe = this,
                transport =  iframe.transport;
                // 防止重复调用 , 成功后 abort
                if (!transport) {
                    return;
                }
                dom.log("transports.iframe _callback")
                var form = transport.form,
                eventType = event.type,
                dummyXHR = transport.dummyXHR;
                iframe.transport = undefined;
                if (eventType == "load") {
                    var doc = iframe.contentDocument ? iframe.contentDocument : window.frames[iframe.id].document;
                    var iframeDoc = iframe.contentWindow.document;
                    if (doc.XMLDocument) {
                        dummyXHR.responseXML = doc.XMLDocument;
                    } else if (doc.body){
                        // response is html document or plain text
                        dummyXHR.responseText = doc.body.innerHTML;
                        dummyXHR.responseXML = iframeDoc;
                        //当,MIME为"text/plain",浏览器会把文本放到一个PRE标签中
                        if (doc.body.firstChild && doc.body.firstChild.nodeName.toUpperCase() == 'PRE') {
                            dummyXHR.responseText  = doc.body.firstChild.firstChild.nodeValue;
                        }
                    }else {
                        // response is a xml document
                        dummyXHR.responseXML = doc;
                    }
                    dummyXHR.callback(200, "success");
                } else if (eventType == 'error') {
                    dummyXHR.callback(500, "error");
                }
                for(var i in transport.backups){
                    form[i] = transport.backups[i];
                }
                //还原form的属性
                transport.fields.forEach(function(elem){
                    elem.parentNode.removeChild(elem);
                });
                dom(iframe).unbind("load",transport._callback).unbind("error",transport._callback);
                iframe.clearAttributes &&  iframe.clearAttributes();
                setTimeout(function() {
                    // Fix busy state in FF3
                    iframe.parentNode.removeChild(iframe);
                    dom.log("iframe.parentNode.removeChild(iframe)")
                }, 0);

            }
        });

    });

})(this,this.document);
//2011.8.31
//将会传送器的abort方法上传到dom.jXHR.abort去处理
//修复serializeArray的bug
//对XMLHttpRequest.abort进行try...catch

JSONP请求示例

        dom.ajax({
          url:"http://del.icio.us/feeds/json/fans/stomita",
          type:"get",
          success:function(responseData){
            dom.log(responseData+"  success");
          },
          dataType:"jsonp"
        });

api基本与jQuery兼容,如get,post,getScript,getJSON,ajax等等,还多出一个upload用于iframe上传。

一个上传示例:


      dom.require("ready,ajax,event",function(){
        dom("#i33").click(function(e){
          dom.log("click")
          dom.upload("/home/upload",dom("#aaa")[0],function(text){
            alert(text)
          });
        })
      });

对应的页面:

    <form id="aaa" >
      <input type="file" id="file" name="file" style="width:450"/>
      <input type="submit" value="上传文件" id="i33"/>
      <span id="msg"></span>
      <br/>
      <font color="red">支持JPG,JPEG,GIF,BMP,SWF,RMVB,RM,AVI文件的上传</font>
    </form>

posted on 2011-08-29 14:17  司徒正美  阅读(1371)  评论(0编辑  收藏  举报