1 /*
  2  * @fileOverview A seed where KISSY grows up from , KISS Yeah !
  3  * @author lifesinger@gmail.com, yiminghe@gmail.com
  4  */
  5 (function (S, undefined) {
  6     /**
  7      * @namespace The KISSY global namespace object. you can use
  8      * <code>
  9      *     KISSY.each/mix
 10      * </code>
 11      * to do basic operation.
 12      * or
 13      * <code>
 14      *      KISSY.use("overlay,node",function(S,Overlay,Node){
 15      *          //
 16      *      })
 17      * </code>
 18      * to do complex task with modules.
 19      * @name KISSY
 20      */
 21 
 22     function hasOwnProperty(o, p) {
 23         return Object.prototype.hasOwnProperty.call(o, p);
 24     }
 25 
 26     var host = this,
 27         MIX_CIRCULAR_DETECTION = "__MIX_CIRCULAR",
 28         hasEnumBug = !({toString:1}.propertyIsEnumerable('toString')),
 29         enumProperties = [
 30             'hasOwnProperty',
 31             'isPrototypeOf',
 32             'propertyIsEnumerable',
 33             'toString',
 34             'toLocaleString',
 35             'valueOf'
 36         ],
 37         meta = {
 38             /**
 39              * Copies all the properties of s to r.
 40              * @name KISSY.mix
 41              * @function
 42              * @param {Object} r the augmented object
 43              * @param {Object} s the object need to augment
 44              * @param {Boolean|Object} [ov=true] whether overwrite existing property or config.
 45              * @param {Boolean} [ov.overwrite=true] whether overwrite existing property.
 46              * @param {String[]} [ov.whitelist] array of white-list properties
 47              * @param {Boolean}[ov.deep=false] whether recursive mix if encounter object.
 48              * @param {String[]} [wl] array of white-list properties
 49              * @param [deep=false] {Boolean} whether recursive mix if encounter object.
 50              * @return {Object} the augmented object
 51              * @example
 52              * <code>
 53              * var t={};
 54              * S.mix({x:{y:2,z:4}},{x:{y:3,a:t}},{deep:true}) => {x:{y:3,z:4,a:{}}} , a!==t
 55              * S.mix({x:{y:2,z:4}},{x:{y:3,a:t}},{deep:true,overwrite:false}) => {x:{y:2,z:4,a:{}}} , a!==t
 56              * S.mix({x:{y:2,z:4}},{x:{y:3,a:t}},1) => {x:{y:3,a:t}}
 57              * </code>
 58              */
 59             mix:function (r, s, ov, wl, deep) {
 60                 if (typeof ov === 'object') {
 61                     wl = ov['whitelist'];
 62                     deep = ov['deep'];
 63                     ov = ov['overwrite'];
 64                 }
 65                 var cache = [], c, i = 0;
 66                 mixInternal(r, s, ov, wl, deep, cache);
 67                 while (c = cache[i++]) {
 68                     delete c[MIX_CIRCULAR_DETECTION];
 69                 }
 70                 return r;
 71             }
 72         },
 73 
 74         mixInternal = function (r, s, ov, wl, deep, cache) {
 75             if (!s || !r) {
 76                 return r;
 77             }
 78 
 79             if (ov === undefined) {
 80                 ov = true;
 81             }
 82 
 83             var i = 0, p, len;
 84 
 85             if (wl && (len = wl.length)) {
 86                 for (; i < len; i++) {
 87                     p = wl[i];
 88                     if (p in s) {
 89                         _mix(p, r, s, ov, deep, cache);
 90                     }
 91                 }
 92             } else {
 93 
 94                 s[MIX_CIRCULAR_DETECTION] = r;
 95 
 96                 cache.push(s);
 97 
 98                 for (p in s) {
 99                     if (p != MIX_CIRCULAR_DETECTION) {
100                         // no hasOwnProperty judge !
101                         _mix(p, r, s, ov, deep, cache);
102                     }
103                 }
104 
105                 // fix #101
106                 if (hasEnumBug) {
107                     for (; p = enumProperties[i++];) {
108                         if (hasOwnProperty(s, p)) {
109                             _mix(p, r, s, ov, deep, cache);
110                         }
111                     }
112                 }
113             }
114             return r;
115         },
116 
117         _mix = function (p, r, s, ov, deep, cache) {
118             // 要求覆盖
119             // 或者目的不存在
120             // 或者深度mix
121             if (ov || !(p in r) || deep) {
122                 var target = r[p],
123                     src = s[p];
124                 // prevent never-end loop
125                 if (target === src) {
126                     return;
127                 }
128                 // 来源是数组和对象,并且要求深度 mix
129                 if (deep && src && (S.isArray(src) || S.isPlainObject(src))) {
130                     if (src[MIX_CIRCULAR_DETECTION]) {
131                         r[p] = src[MIX_CIRCULAR_DETECTION];
132                     } else {
133                         // 目标值为对象或数组,直接 mix
134                         // 否则 新建一个和源值类型一样的空数组/对象,递归 mix
135                         var clone = target && (S.isArray(target) || S.isPlainObject(target)) ?
136                             target :
137                             (S.isArray(src) ? [] : {});
138                         // 记录循环标志
139                         src[MIX_CIRCULAR_DETECTION] = r[p] = clone;
140                         // 记录被记录了循环标志的对像
141                         cache.push(src);
142                         mixInternal(clone, src, ov, undefined, true, cache);
143                     }
144                 } else if (src !== undefined && (ov || !(p in r))) {
145                     r[p] = src;
146                 }
147             }
148         },
149 
150     // If KISSY is already defined, the existing KISSY object will not
151     // be overwritten so that defined namespaces are preserved.
152         seed = (host && host[S]) || {},
153 
154         guid = 0,
155         EMPTY = '';
156 
157     // The host of runtime environment. specify by user's seed or <this>,
158     // compatibled for  '<this> is null' in unknown engine.
159     seed.Env = seed.Env || {};
160     host = seed.Env.host || (seed.Env.host = host || {});
161 
162     // shortcut and meta for seed.
163     // override previous kissy
164     S = host[S] = meta.mix(seed, meta);
165 
166     S.mix(KISSY,
167         /**
168          * @lends KISSY
169          */
170         {
171             /**
172              * @private
173              */
174             configs:(S.configs || {}),
175 
176             /**
177              * The version of the library.
178              * @type {String}
179              */
180             version:'@VERSION@',
181 
182             /**
183              * Returns a new object containing all of the properties of
184              * all the supplied objects. The properties from later objects
185              * will overwrite those in earlier objects. Passing in a
186              * single object will create a shallow copy of it.
187              * @param {...} m1 objects need to be merged
188              * @return {Object} the new merged object
189              */
190             merge:function (m1) {
191                 var o = {}, i, l = arguments.length;
192                 for (i = 0; i < l; i++) {
193                     S.mix(o, arguments[i]);
194                 }
195                 return o;
196             },
197 
198             /**
199              * Applies prototype properties from the supplier to the receiver.
200              * @param   {Object} r received object
201              * @param   {...Object} s1 object need to  augment
202              *          {Boolean} [ov=true] whether overwrite existing property
203              *          {String[]} [wl] array of white-list properties
204              * @return  {Object} the augmented object
205              */
206             augment:function (r, s1) {
207                 var args = S.makeArray(arguments),
208                     len = args.length - 2,
209                     i = 1,
210                     ov = args[len],
211                     wl = args[len + 1];
212 
213                 if (!S.isArray(wl)) {
214                     ov = wl;
215                     wl = undefined;
216                     len++;
217                 }
218                 if (!S.isBoolean(ov)) {
219                     ov = undefined;
220                     len++;
221                 }
222 
223                 for (; i < len; i++) {
224                     S.mix(r.prototype, args[i].prototype || args[i], ov, wl);
225                 }
226 
227                 return r;
228             },
229 
230             /**
231              * Utility to set up the prototype, constructor and superclass properties to
232              * support an inheritance strategy that can chain constructors and methods.
233              * Static members will not be inherited.
234              * @param r {Function} the object to modify
235              * @param s {Function} the object to inherit
236              * @param {Object} [px] prototype properties to add/override
237              * @param {Object} [sx] static properties to add/override
238              * @return r {Object}
239              */
240             extend:function (r, s, px, sx) {
241                 if (!s || !r) {
242                     return r;
243                 }
244 
245                 var create = Object.create ?
246                         function (proto, c) {
247                             return Object.create(proto, {
248                                 constructor:{
249                                     value:c
250                                 }
251                             });
252                         } :
253                         function (proto, c) {
254                             function F() {
255                             }
256 
257                             F.prototype = proto;
258 
259                             var o = new F();
260                             o.constructor = c;
261                             return o;
262                         },
263                     sp = s.prototype,
264                     rp;
265 
266                 // add prototype chain
267                 rp = create(sp, r);
268                 r.prototype = S.mix(rp, r.prototype);
269                 r.superclass = create(sp, s);
270 
271                 // add prototype overrides
272                 if (px) {
273                     S.mix(rp, px);
274                 }
275 
276                 // add object overrides
277                 if (sx) {
278                     S.mix(r, sx);
279                 }
280 
281                 return r;
282             },
283 
284             /****************************************************************************************
285 
286              *                            The KISSY System Framework                                *
287 
288              ****************************************************************************************/
289 
290 
291             /**
292              * Returns the namespace specified and creates it if it doesn't exist. Be careful
293              * when naming packages. Reserved words may work in some browsers and not others.
294              * <code>
295              * S.namespace('KISSY.app'); // returns KISSY.app
296              * S.namespace('app.Shop'); // returns KISSY.app.Shop
297              * S.namespace('TB.app.Shop', true); // returns TB.app.Shop
298              * </code>
299              * @return {Object}  A reference to the last namespace object created
300              */
301             namespace:function () {
302                 var args = S.makeArray(arguments),
303                     l = args.length,
304                     o = null, i, j, p,
305                     global = (args[l - 1] === true && l--);
306 
307                 for (i = 0; i < l; i++) {
308                     p = (EMPTY + args[i]).split('.');
309                     o = global ? host : this;
310                     for (j = (host[p[0]] === o) ? 1 : 0; j < p.length; ++j) {
311                         o = o[p[j]] = o[p[j]] || { };
312                     }
313                 }
314                 return o;
315             },
316 
317             /**
318              * set KISSY configuration
319              * @param {Object|String}   c Config object or config key.
320              * @param {String} c.base   KISSY 's base path.
321              *                          Default: get from kissy(-min).js or seed(-min).js
322              * @param {String} c.tag    KISSY 's timestamp for native module.
323              *                          Default: KISSY 's build time.
324              * @param {Boolean} c.debug     whether to enable debug mod.
325              * @param {Boolean} c.combine   whether to enable combo.
326              * @param {Object} c.packages Packages definition with package name as the key.
327              * @param {String} c.packages.base    Package base path.
328              * @param {String} c.packages.tag     Timestamp for this package's module file.
329              * @param {String} c.packages.debug     Whether force debug mode for current package.
330              * @param {String} c.packages.combine     Whether allow combine for current package modules.
331              * @param {Array[]} c.map file map      File url map configs.
332              * @param {Array[]} c.map.0     A single map rule.
333              * @param {RegExp} c.map.0.0    A regular expression to match url.
334              * @param {String|Function} c.map.0.1   Replacement for String.replace.
335              * @param [v] config value.
336              * @example
337              * // use gallery from cdn
338              * <code>
339              * KISSY.config({
340              *      combine:true,
341              *      base:'',
342              *      packages:{
343              *          "gallery":{
344              *              base:"http://a.tbcdn.cn/s/kissy/gallery/"
345              *          }
346              *      },
347              *      modules:{
348              *          "gallery/x/y":{
349              *              requires:["gallery/x/z"]
350              *          }
351              *      }
352              * });
353              * </code>
354              * // use map to reduce connection count
355              * <code>
356              * S.config("map",[
357              *  [
358              *   /http:\/\/a.tbcdn.cn\/s\/kissy\/1.2.0\/(?:overlay|component|uibase|switchable)-min.js(.+)$/,
359              *   "http://a.tbcdn.cn/s/kissy/1.2.0/??overlay-min.js,component-min.js,uibase-min.js,switchable-min.js$1"
360              *  ]
361              * ]);
362              * </code>
363              */
364             config:function (c, v) {
365                 var cfg,
366                     r,
367                     self = this,
368                     runs = [],
369                     fn,
370                     p,
371                     Config = S.Config,
372                     configs = S.configs;
373                 if (S.isObject(c)) {
374                     for (p in c) {
375                         if (hasOwnProperty(c, p)) {
376                             runs.push({
377                                 name:p,
378                                 order:configs[p] && configs[p].order || 0,
379                                 value:c[p]
380                             });
381                         }
382                     }
383 
384                     runs.sort(function (a1, a2) {
385                         return a1.order > a2.order;
386                     });
387 
388                     S.each(runs, function (r) {
389                         fn = configs[p = r.name];
390                         v = r.value;
391                         if (fn) {
392                             fn.call(self, v);
393                         } else {
394                             Config[p] = v;
395                         }
396                     });
397 
398                 } else {
399                     cfg = configs[c];
400                     if (v === undefined) {
401                         if (cfg) {
402                             r = cfg.call(self);
403                         } else {
404                             r = Config[c];
405                         }
406                     } else {
407                         if (cfg) {
408                             r = cfg.call(self, v);
409                         } else {
410                             Config[c] = v;
411                         }
412                     }
413                 }
414                 return r;
415             },
416 
417             /**
418              * Prints debug info.
419              * @param msg {String} the message to log.
420              * @param {String} [cat] the log category for the message. Default
421              *        categories are "info", "warn", "error", "time" etc.
422              * @param {String} [src] the source of the the message (opt)
423              */
424             log:function (msg, cat, src) {
425                 if (S.Config.debug && msg) {
426                     if (src) {
427                         msg = src + ': ' + msg;
428                     }
429                     if (host['console'] !== undefined && console.log) {
430                         console[cat && console[cat] ? cat : 'log'](msg);
431                     }
432                 }
433             },
434 
435             /**
436              * Throws error message.
437              */
438             error:function (msg) {
439                 if (S.Config.debug) {
440                     throw msg;
441                 }
442             },
443 
444             /*
445              * Generate a global unique id.
446              * @param {String} [pre] guid prefix
447              * @return {String} the guid
448              */
449             guid:function (pre) {
450                 return (pre || EMPTY) + guid++;
451             },
452 
453             /**
454              * Get all the property names of o as array
455              * @param {Object} o
456              * @returns {Array}
457              */
458             keys:function (o) {
459                 var result = [];
460 
461                 for (var p in o) {
462                     if (hasOwnProperty(o, p)) {
463                         result.push(p);
464                     }
465                 }
466 
467                 if (hasEnumBug) {
468                     S.each(enumProperties, function (name) {
469                         if (hasOwnProperty(o, name)) {
470                             result.push(name);
471                         }
472                     });
473                 }
474 
475                 return result;
476             }
477         });
478 
479     /**
480      * Initializes
481      */
482     (function () {
483         var c;
484         S.Env = S.Env || {};
485         c = S.Config = S.Config || {};
486         // NOTICE: '@DEBUG@' will replace with '' when compressing.
487         // So, if loading source file, debug is on by default.
488         // If loading min version, debug is turned off automatically.
489         c.debug = '@DEBUG@';
490         /**
491          * The build time of the library
492          * @type {String}
493          */
494         S.__BUILD_TIME = '@TIMESTAMP@';
495     })();
496 
497     return S;
498 
499 })('KISSY', undefined);
500