1 /** 2 * @fileOverview non-refresh upload file with form by iframe 3 * @author yiminghe@gmail.com 4 */ 5 KISSY.add("ajax/IframeTransport", function (S, DOM, Event, io) { 6 7 var doc = S.Env.host.document, 8 OK_CODE = 200, 9 ERROR_CODE = 500, 10 BREATH_INTERVAL = 30; 11 12 // iframe 内的内容就是 body.innerText 13 io.setupConfig({ 14 converters:{ 15 // iframe 到其他类型的转化和 text 一样 16 iframe:io.getConfig().converters.text, 17 text:{ 18 // fake type, just mirror 19 iframe:function (text) { 20 return text; 21 } 22 }, 23 xml:{ 24 // fake type, just mirror 25 iframe:function (xml) { 26 return xml; 27 } 28 } 29 } 30 }); 31 32 function createIframe(xhr) { 33 var id = S.guid("ajax-iframe"), 34 iframe, 35 src = DOM.getEmptyIframeSrc(); 36 37 iframe = xhr.iframe = DOM.create("<iframe " + 38 // ie6 need this when cross domain 39 (src ? (" src=\"" + src + "\" ") : "") + 40 " id='" + id + "'" + 41 // need name for target of form 42 " name='" + id + "'" + 43 " style='position:absolute;left:-9999px;top:-9999px;'/>"); 44 45 DOM.prepend(iframe, doc.body || doc.documentElement); 46 return iframe; 47 } 48 49 function addDataToForm(data, form, serializeArray) { 50 data = S.unparam(data); 51 var ret = [], d, isArray, vs, i, e; 52 for (d in data) { 53 isArray = S.isArray(data[d]); 54 vs = S.makeArray(data[d]); 55 // 数组和原生一样对待,创建多个同名输入域 56 for (i = 0; i < vs.length; i++) { 57 e = doc.createElement("input"); 58 e.type = 'hidden'; 59 e.name = d + (isArray && serializeArray ? "[]" : ""); 60 e.value = vs[i]; 61 DOM.append(e, form); 62 ret.push(e); 63 } 64 } 65 return ret; 66 } 67 68 function removeFieldsFromData(fields) { 69 DOM.remove(fields); 70 } 71 72 function IframeTransport(xhrObject) { 73 this.xhrObject = xhrObject; 74 } 75 76 S.augment(IframeTransport, { 77 send:function () { 78 79 var self = this, 80 xhrObject = self.xhrObject, 81 c = xhrObject.config, 82 fields, 83 iframe, 84 form = DOM.get(c.form); 85 86 self.attrs = { 87 target:DOM.attr(form, "target") || "", 88 action:DOM.attr(form, "action") || "", 89 // enctype 区分 iframe 与 serialize 90 //encoding:DOM.attr(form, "encoding"), 91 //enctype:DOM.attr(form, "enctype"), 92 method:DOM.attr(form, "method") 93 }; 94 self.form = form; 95 96 iframe = createIframe(xhrObject); 97 98 // set target to iframe to avoid main page refresh 99 DOM.attr(form, { 100 target:iframe.id, 101 action:c.url, 102 method:"post" 103 //enctype:'multipart/form-data', 104 //encoding:'multipart/form-data' 105 }); 106 107 if (c.data) { 108 fields = addDataToForm(c.data, form, c.serializeArray); 109 } 110 111 self.fields = fields; 112 // ie6 need a setTimeout to avoid handling load triggered if set iframe src 113 setTimeout(function () { 114 Event.on(iframe, "load error", self._callback, self); 115 form.submit(); 116 }, 10); 117 118 }, 119 120 _callback:function (event/*, abort*/) { 121 var self = this, 122 form = self.form, 123 xhrObject = self.xhrObject, 124 eventType = event.type, 125 iframeDoc, 126 iframe = xhrObject.iframe; 127 128 // 防止重复调用 , 成功后 abort 129 if (!iframe) { 130 return; 131 } 132 133 DOM.attr(form, self.attrs); 134 135 removeFieldsFromData(this.fields); 136 137 Event.detach(iframe); 138 139 setTimeout(function () { 140 // firefox will keep loading if not set timeout 141 DOM.remove(iframe); 142 }, BREATH_INTERVAL); 143 144 // nullify to prevent memory leak? 145 xhrObject.iframe = null; 146 147 if (eventType == "load") { 148 iframeDoc = iframe.contentWindow.document; 149 // ie<9 150 if (iframeDoc && iframeDoc.body) { 151 xhrObject.responseText = S.trim(DOM.text(iframeDoc.body)); 152 // ie still can retrieve xml 's responseText 153 if (S.startsWith(xhrObject.responseText, "<?xml")) { 154 xhrObject.responseText = undefined; 155 } 156 } 157 // ie<9 158 // http://help.dottoro.com/ljbcjfot.php 159 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms766512(v=vs.85).aspx 160 /* 161 In Internet Explorer, XML documents can also be embedded into HTML documents with the xml HTML elements. 162 To get an XMLDocument object that represents the embedded XML data island, 163 use the XMLDocument property of the xml element. 164 Note that the support for the XMLDocument property has been removed in Internet Explorer 9. 165 */ 166 if (iframeDoc && iframeDoc['XMLDocument']) { 167 xhrObject.responseXML = iframeDoc['XMLDocument']; 168 } 169 // ie9 firefox chrome 170 else { 171 xhrObject.responseXML = iframeDoc; 172 } 173 174 xhrObject._xhrReady(OK_CODE, "success"); 175 } else if (eventType == 'error') { 176 xhrObject._xhrReady(ERROR_CODE, "error"); 177 } 178 }, 179 180 abort:function () { 181 this._callback({}); 182 } 183 }); 184 185 io.setupTransport("iframe", IframeTransport); 186 187 return io; 188 189 }, { 190 requires:["dom", "event", "./base"] 191 });