1 /**
  2  * @fileOverview getScript support for css and js callback after load
  3  * @author yiminghe@gmail.com,lifesinger@gmail.com
  4  */
  5 (function (S) {
  6     if (typeof require !== 'undefined') {
  7         return;
  8     }
  9     var MILLISECONDS_OF_SECOND = 1000,
 10         doc = S.Env.host.document,
 11         utils = S.Loader.Utils,
 12         jsCallbacks = {},
 13         cssCallbacks = {};
 14 
 15     S.mix(S, {
 16 
 17         /**
 18          * load  a css file from server using http get,
 19          * after css file load ,execute success callback.
 20          * note: no support for timeout and error
 21          * @param url css file url
 22          * @param success callback
 23          * @param charset
 24          * @private
 25          */
 26         getStyle:function (url, success, charset) {
 27 
 28             var config = success;
 29 
 30             if (S.isPlainObject(config)) {
 31                 success = config.success;
 32                 charset = config.charset;
 33             }
 34             var src = utils.absoluteFilePath(url),
 35                 callbacks = cssCallbacks[src] = cssCallbacks[src] || [];
 36 
 37             callbacks.push(success);
 38 
 39             if (callbacks.length > 1) {
 40                 // S.log(" queue css : " + callbacks.length);
 41                 return callbacks.node;
 42             }
 43 
 44             var head = utils.docHead(),
 45                 node = doc.createElement('link');
 46 
 47             callbacks.node = node;
 48 
 49             node.href = url;
 50             node.rel = 'stylesheet';
 51 
 52             if (charset) {
 53                 node.charset = charset;
 54             }
 55             utils.styleOnLoad(node, function () {
 56                 var callbacks = cssCallbacks[src];
 57                 S.each(callbacks, function (callback) {
 58                     if (callback) {
 59                         callback.call(node);
 60                     }
 61                 });
 62                 delete cssCallbacks[src];
 63             });
 64             // css order matters!
 65             head.appendChild(node);
 66             return node;
 67 
 68         },
 69         /**
 70          * Load a JavaScript/Css file from the server using a GET HTTP request,
 71          * then execute it.
 72          * @example
 73          * <code>
 74          *  getScript(url, success, charset);
 75          *  or
 76          *  getScript(url, {
 77          *      charset: string
 78          *      success: fn,
 79          *      error: fn,
 80          *      timeout: number
 81          *  });
 82          * </code>
 83          * @param {String} url resource's url
 84          * @param {Function|Object} [success] success callback or config
 85          * @param {Function} [success.success] success callback
 86          * @param {Function} [success.error] error callback
 87          * @param {Number} [success.timeout] timeout (s)
 88          * @param {String} [success.charset] charset of current resource
 89          * @param {String} [charset] charset of current resource
 90          * @returns {HTMLElement} script/style node
 91          * @memberOf KISSY
 92          */
 93         getScript:function (url, success, charset) {
 94             if (utils.isCss(url)) {
 95                 return S.getStyle(url, success, charset);
 96             }
 97 
 98             var config = success,
 99                 error,
100                 timeout,
101                 timer;
102 
103             if (S.isPlainObject(config)) {
104                 success = config.success;
105                 error = config.error;
106                 timeout = config.timeout;
107                 charset = config.charset;
108             }
109 
110             var src = utils.absoluteFilePath(url),
111                 callbacks = jsCallbacks[src] = jsCallbacks[src] || [];
112 
113             callbacks.push([success, error]);
114 
115             if (callbacks.length > 1) {
116                 // S.log(" queue js : " + callbacks.length + " : for :" + url + " by " + (config.source || ""));
117                 return callbacks.node;
118             } else {
119                 // S.log("init getScript : by " + config.source);
120             }
121 
122             var head = utils.docHead(),
123                 node = doc.createElement('script'),
124                 clearTimer = function () {
125                     if (timer) {
126                         timer.cancel();
127                         timer = undefined;
128                     }
129                 };
130 
131             node.src = url;
132             node.async = true;
133 
134             callbacks.node = node;
135 
136             if (charset) {
137                 node.charset = charset;
138             }
139 
140             var end = function (error) {
141                 var index = error ? 1 : 0;
142                 clearTimer();
143                 var callbacks = jsCallbacks[src];
144                 S.each(callbacks, function (callback) {
145                     if (callback[index]) {
146                         callback[index].call(node);
147                     }
148                 });
149                 delete jsCallbacks[src];
150             }
151 
152             //标准浏览器
153             if (node.addEventListener) {
154                 node.addEventListener('load', function () {
155                     end(0);
156                 }, false);
157                 node.addEventListener("error", function () {
158                     end(1);
159                 }, false);
160             } else {
161                 node.onreadystatechange = function () {
162                     var self = this,
163                         rs = self.readyState;
164                     if (/loaded|complete/i.test(rs)) {
165                         self.onreadystatechange = null;
166                         end(0);
167                     }
168                 };
169             }
170 
171             if (timeout) {
172                 timer = S.later(function () {
173                     end(1);
174                 }, timeout * MILLISECONDS_OF_SECOND);
175             }
176             head.insertBefore(node, head.firstChild);
177             return node;
178         }
179     });
180 
181 })(KISSY);
182 /**
183  * yiminghe@gmail.com refactor@2012-03-29
184  *  - 考虑连续重复请求单个 script 的情况,内部排队
185  *
186  * yiminghe@gmail.com 2012-03-13
187  *  - getScript
188  *      - 404 in ie<9 trigger success , others trigger error
189  *      - syntax error in all trigger success
190  **/