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