1 /** 2 * @fileOverview web.js 3 * @author lifesinger@gmail.com,yiminghe@gmail.com 4 * @description this code can only run at browser environment 5 */ 6 (function (S, undefined) { 7 8 var win = S.Env.host, 9 10 doc = win['document'], 11 12 docElem = doc.documentElement, 13 14 location = win.location, 15 16 navigator = win.navigator, 17 18 EMPTY = '', 19 20 readyDefer = new S.Defer(), 21 22 readyPromise = readyDefer.promise, 23 24 // The number of poll times. 25 POLL_RETRYS = 500, 26 27 // The poll interval in milliseconds. 28 POLL_INTERVAL = 40, 29 30 // #id or id 31 RE_IDSTR = /^#?([\w-]+)$/, 32 33 RE_NOT_WHITE = /\S/; 34 35 S.mix(S, 36 /** 37 * @lends KISSY 38 */ 39 { 40 41 42 /** 43 * A crude way of determining if an object is a window 44 */ 45 isWindow:function (o) { 46 return S.type(o) === 'object' 47 && 'setInterval' in o 48 && 'document' in o 49 && o.document.nodeType == 9; 50 }, 51 52 53 /** 54 * get xml representation of data 55 * @param {String} data 56 */ 57 parseXML:function (data) { 58 // already a xml 59 if (data.documentElement) { 60 return data; 61 } 62 var xml; 63 try { 64 // Standard 65 if (win['DOMParser']) { 66 xml = new DOMParser().parseFromString(data, "text/xml"); 67 } else { // IE 68 xml = new ActiveXObject("Microsoft.XMLDOM"); 69 xml.async = "false"; 70 xml.loadXML(data); 71 } 72 } catch (e) { 73 S.log("parseXML error : "); 74 S.log(e); 75 xml = undefined; 76 } 77 if (!xml || !xml.documentElement || xml.getElementsByTagName("parsererror").length) { 78 S.error("Invalid XML: " + data); 79 } 80 return xml; 81 }, 82 83 /** 84 * Evalulates a script in a global context. 85 */ 86 globalEval:function (data) { 87 if (data && RE_NOT_WHITE.test(data)) { 88 // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context 89 ( win.execScript || function (data) { 90 win[ "eval" ].call(win, data); 91 } )(data); 92 } 93 }, 94 95 /** 96 * Specify a function to execute when the DOM is fully loaded. 97 * @param fn {Function} A function to execute after the DOM is ready 98 * <code> 99 * KISSY.ready(function(S){ }); 100 * </code> 101 * @return {KISSY} 102 */ 103 ready:function (fn) { 104 105 readyPromise.then(fn); 106 107 return this; 108 }, 109 110 /** 111 * Executes the supplied callback when the item with the supplied id is found. 112 * @param id <String> The id of the element, or an array of ids to look for. 113 * @param fn <Function> What to execute when the element is found. 114 */ 115 available:function (id, fn) { 116 id = (id + EMPTY).match(RE_IDSTR)[1]; 117 if (!id || !S.isFunction(fn)) { 118 return; 119 } 120 121 var retryCount = 1, 122 node, 123 timer = S.later(function () { 124 if ((node = doc.getElementById(id)) && (fn(node) || 1) || 125 ++retryCount > POLL_RETRYS) { 126 timer.cancel(); 127 } 128 }, POLL_INTERVAL, true); 129 } 130 }); 131 132 133 /** 134 * Binds ready events. 135 */ 136 function _bindReady() { 137 var doScroll = docElem.doScroll, 138 eventType = doScroll ? 'onreadystatechange' : 'DOMContentLoaded', 139 COMPLETE = 'complete', 140 fire = function () { 141 readyDefer.resolve(S) 142 }; 143 144 // Catch cases where ready() is called after the 145 // browser event has already occurred. 146 if (doc.readyState === COMPLETE) { 147 return fire(); 148 } 149 150 // w3c mode 151 if (doc.addEventListener) { 152 function domReady() { 153 doc.removeEventListener(eventType, domReady, false); 154 fire(); 155 } 156 157 doc.addEventListener(eventType, domReady, false); 158 159 // A fallback to window.onload, that will always work 160 win.addEventListener('load', fire, false); 161 } 162 // IE event model is used 163 else { 164 function stateChange() { 165 if (doc.readyState === COMPLETE) { 166 doc.detachEvent(eventType, stateChange); 167 fire(); 168 } 169 } 170 171 // ensure firing before onload (but completed after all inner iframes is loaded) 172 // maybe late but safe also for iframes 173 doc.attachEvent(eventType, stateChange); 174 175 // A fallback to window.onload, that will always work. 176 win.attachEvent('onload', fire); 177 178 // If IE and not a frame 179 // continually check to see if the document is ready 180 var notframe; 181 182 try { 183 notframe = (win['frameElement'] === null); 184 } catch (e) { 185 S.log("get frameElement error : "); 186 S.log(e); 187 notframe = false; 188 } 189 190 // can not use in iframe,parent window is dom ready so doScoll is ready too 191 if (doScroll && notframe) { 192 function readyScroll() { 193 try { 194 // Ref: http://javascript.nwbox.com/IEContentLoaded/ 195 doScroll('left'); 196 fire(); 197 } catch (ex) { 198 //S.log("detect document ready : " + ex); 199 setTimeout(readyScroll, POLL_INTERVAL); 200 } 201 } 202 203 readyScroll(); 204 } 205 } 206 return 0; 207 } 208 209 // If url contains '?ks-debug', debug mode will turn on automatically. 210 if (location && (location.search || EMPTY).indexOf('ks-debug') !== -1) { 211 S.Config.debug = true; 212 } 213 214 /** 215 * bind on start 216 * in case when you bind but the DOMContentLoaded has triggered 217 * then you has to wait onload 218 * worst case no callback at all 219 */ 220 _bindReady(); 221 222 if (navigator && navigator.userAgent.match(/MSIE/)) { 223 try { 224 doc.execCommand("BackgroundImageCache", false, true); 225 } catch (e) { 226 } 227 } 228 229 })(KISSY, undefined); 230