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