/**
* Iterate over an object or an array, executing a function for each matched element.
* @param {object|array} obj
* @param {function} iterator
* @param {object} [context]
*/
cc.each = function (obj, iterator, context) {
if (!obj)
return;
if (obj instanceof Array) {
for (var i = 0, li = obj.length; i < li; i++) {
if (iterator.call(context, obj[i], i) === false)
return;
}
} else {
for (var key in obj) {
if (iterator.call(context, obj[key], key) === false)
return;
}
}
};
/**
* Copy all of the properties in source objects to target object and return the target object.
* @param {object} target
* @param {object} *sources
* @returns {object}
*/
cc.extend = function (target) {
var sources = arguments.length >= 2 ? Array.prototype.slice.call(arguments, 1) : [];
cc.each(sources, function (src) {
for (var key in src) {
if (src.hasOwnProperty(key)) {
target[key] = src[key];
}
}
});
return target;
};
/**
* Another way to subclass: Using Google Closure.
* The following code was copied + pasted from goog.base / goog.inherits
* @function
* @param {Function} childCtor
* @param {Function} parentCtor
*/
cc.inherits = function (childCtor, parentCtor) {
function tempCtor() {}
tempCtor.prototype = parentCtor.prototype;
childCtor.superClass_ = parentCtor.prototype;
childCtor.prototype = new tempCtor();
childCtor.prototype.constructor = childCtor;
// Copy "static" method, but doesn't generate subclasses.
// for( var i in parentCtor ) {
// childCtor[ i ] = parentCtor[ i ];
// }
};
/**
* Check the obj whether is function or not
* @param {*} obj
* @returns {boolean}
*/
cc.isFunction = function (obj) {
return typeof obj === 'function';
};
/**
* Check the obj whether is number or not
* @param {*} obj
* @returns {boolean}
*/
cc.isNumber = function (obj) {
return typeof obj === 'number' || Object.prototype.toString.call(obj) === '[object Number]';
};
/**
* Check the obj whether is string or not
* @param {*} obj
* @returns {boolean}
*/
cc.isString = function (obj) {
return typeof obj === 'string' || Object.prototype.toString.call(obj) === '[object String]';
};
/**
* Check the obj whether is array or not
* @param {*} obj
* @returns {boolean}
*/
cc.isArray = function (obj) {
return Array.isArray(obj) ||
(typeof obj === 'object' && Object.prototype.toString.call(obj) === '[object Array]');
};
/**
* Check the obj whether is undefined or not
* @param {*} obj
* @returns {boolean}
*/
cc.isUndefined = function (obj) {
return typeof obj === 'undefined';
};
/**
* Check the obj whether is object or not
* @param {*} obj
* @returns {boolean}
*/
cc.isObject = function (obj) {
return typeof obj === "object" && Object.prototype.toString.call(obj) === '[object Object]';
};
/**
* Check the url whether cross origin
* @param {String} url
* @returns {boolean}
*/
cc.isCrossOrigin = function (url) {
if (!url) {
cc.log("invalid URL");
return false;
}
var startIndex = url.indexOf("://");
if (startIndex === -1)
return false;
var endIndex = url.indexOf("/", startIndex + 3);
var urlOrigin = (endIndex === -1) ? url : url.substring(0, endIndex);
return urlOrigin !== location.origin;
};
//+++++++++++++++++++++++++something about async begin+++++++++++++++++++++++++++++++
/**
* Async Pool class, a helper of cc.async
* @param {Object|Array} srcObj
* @param {Number} limit the limit of parallel number
* @param {function} iterator
* @param {function} onEnd
* @param {object} target
* @constructor
*/
cc.AsyncPool = function (srcObj, limit, iterator, onEnd, target) {
var self = this;
self._finished = false;
self._srcObj = srcObj;
self._limit = limit;
self._pool = [];
self._iterator = iterator;
self._iteratorTarget = target;
self._onEnd = onEnd;
self._onEndTarget = target;
self._results = srcObj instanceof Array ? [] : {};
self._errors = srcObj instanceof Array ? [] : {};
cc.each(srcObj, function (value, index) {
self._pool.push({index: index, value: value});
});
self.size = self._pool.length;
self.finishedSize = 0;
self._workingSize = 0;
self._limit = self._limit || self.size;
self.onIterator = function (iterator, target) {
self._iterator = iterator;
self._iteratorTarget = target;
};
self.onEnd = function (endCb, endCbTarget) {
self._onEnd = endCb;
self._onEndTarget = endCbTarget;
};
self._handleItem = function () {
var self = this;
if (self._pool.length === 0 || self._workingSize >= self._limit)
return; //return directly if the array's length = 0 or the working size great equal limit number
var item = self._pool.shift();
var value = item.value, index = item.index;
self._workingSize++;
self._iterator.call(self._iteratorTarget, value, index,
function (err, result) {
if (self._finished) {
return;
}
if (err) {
self._errors[this.index] = err;
}
else {
self._results[this.index] = result;
}
self.finishedSize++;
self._workingSize--;
if (self.finishedSize === self.size) {
var errors = self._errors.length === 0 ? null : self._errors;
self.onEnd(errors, self._results);
return;
}
self._handleItem();
}.bind(item),
self);
};
self.flow = function () {
var self = this;
if (self._pool.length === 0) {
if (self._onEnd)
self._onEnd.call(self._onEndTarget, null, []);
return;
}
for (var i = 0; i < self._limit; i++)
self._handleItem();
};
self.onEnd = function(errors, results) {
self._finished = true;
if (self._onEnd) {
var selector = self._onEnd;
var target = self._onEndTarget;
self._onEnd = null;
self._onEndTarget = null;
selector.call(target, errors, results);
}
};
};
/**
* @class
*/
cc.async = /** @lends cc.async# */{
/**
* Do tasks series.
* @param {Array|Object} tasks
* @param {function} [cb] callback
* @param {Object} [target]
* @return {cc.AsyncPool}
*/
series: function (tasks, cb, target) {
var asyncPool = new cc.AsyncPool(tasks, 1, function (func, index, cb1) {
func.call(target, cb1);
}, cb, target);
asyncPool.flow();
return asyncPool;
},
/**
* Do tasks parallel.
* @param {Array|Object} tasks
* @param {function} cb callback
* @param {Object} [target]
* @return {cc.AsyncPool}
*/
parallel: function (tasks, cb, target) {
var asyncPool = new cc.AsyncPool(tasks, 0, function (func, index, cb1) {
func.call(target, cb1);
}, cb, target);
asyncPool.flow();
return asyncPool;
},
/**
* Do tasks waterfall.
* @param {Array|Object} tasks
* @param {function} cb callback
* @param {Object} [target]
* @return {cc.AsyncPool}
*/
waterfall: function (tasks, cb, target) {
var args = [];
var lastResults = [null];//the array to store the last results
var asyncPool = new cc.AsyncPool(tasks, 1,
function (func, index, cb1) {
args.push(function (err) {
args = Array.prototype.slice.call(arguments, 1);
if (tasks.length - 1 === index) lastResults = lastResults.concat(args);//while the last task
cb1.apply(null, arguments);
});
func.apply(target, args);
}, function (err) {
if (!cb)
return;
if (err)
return cb.call(target, err);
cb.apply(target, lastResults);
});
asyncPool.flow();
return asyncPool;
},
/**
* Do tasks by iterator.
* @param {Array|Object} tasks
* @param {function|Object} iterator
* @param {function} [callback]
* @param {Object} [target]
* @return {cc.AsyncPool}
*/
map: function (tasks, iterator, callback, target) {
var locIterator = iterator;
if (typeof(iterator) === "object") {
callback = iterator.cb;
target = iterator.iteratorTarget;
locIterator = iterator.iterator;
}
var asyncPool = new cc.AsyncPool(tasks, 0, locIterator, callback, target);
asyncPool.flow();
return asyncPool;
},
/**
* Do tasks by iterator limit.
* @param {Array|Object} tasks
* @param {Number} limit
* @param {function} iterator
* @param {function} cb callback
* @param {Object} [target]
*/
mapLimit: function (tasks, limit, iterator, cb, target) {
var asyncPool = new cc.AsyncPool(tasks, limit, iterator, cb, target);
asyncPool.flow();
return asyncPool;
}
};
//+++++++++++++++++++++++++something about async end+++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++something about path begin++++++++++++++++++++++++++++++++
/**
* @class
*/
cc.path = /** @lends cc.path# */{
normalizeRE: /[^\.\/]+\/\.\.\//,
/**
* Join strings to be a path.
* @example
cc.path.join("a", "b.png");//-->"a/b.png"
cc.path.join("a", "b", "c.png");//-->"a/b/c.png"
cc.path.join("a", "b");//-->"a/b"
cc.path.join("a", "b", "/");//-->"a/b/"
cc.path.join("a", "b/", "/");//-->"a/b/"
* @returns {string}
*/
join: function () {
var l = arguments.length;
var result = "";
for (var i = 0; i < l; i++) {
result = (result + (result === "" ? "" : "/") + arguments[i]).replace(/(\/|\\\\)$/, "");
}
return result;
},
/**
* Get the ext name of a path.
* @example
cc.path.extname("a/b.png");//-->".png"
cc.path.extname("a/b.png?a=1&b=2");//-->".png"
cc.path.extname("a/b");//-->null
cc.path.extname("a/b?a=1&b=2");//-->null
* @param {string} pathStr
* @returns {*}
*/
extname: function (pathStr) {
var temp = /(\.[^\.\/\?\\]*)(\?.*)?$/.exec(pathStr);
return temp ? temp[1] : null;
},
/**
* Get the main name of a file name
* @param {string} fileName
* @returns {string}
*/
mainFileName: function (fileName) {
if (fileName) {
var idx = fileName.lastIndexOf(".");
if (idx !== -1)
return fileName.substring(0, idx);
}
return fileName;
},
/**
* Get the file name of a file path.
* @example
cc.path.basename("a/b.png");//-->"b.png"
cc.path.basename("a/b.png?a=1&b=2");//-->"b.png"
cc.path.basename("a/b.png", ".png");//-->"b"
cc.path.basename("a/b.png?a=1&b=2", ".png");//-->"b"
cc.path.basename("a/b.png", ".txt");//-->"b.png"
* @param {string} pathStr
* @param {string} [extname]
* @returns {*}
*/
basename: function (pathStr, extname) {
var index = pathStr.indexOf("?");
if (index > 0) pathStr = pathStr.substring(0, index);
var reg = /(\/|\\\\)([^(\/|\\\\)]+)$/g;
var result = reg.exec(pathStr.replace(/(\/|\\\\)$/, ""));
if (!result) return null;
var baseName = result[2];
if (extname && pathStr.substring(pathStr.length - extname.length).toLowerCase() === extname.toLowerCase())
return baseName.substring(0, baseName.length - extname.length);
return baseName;
},
/**
* Get dirname of a file path.
* @example
* unix
cc.path.driname("a/b/c.png");//-->"a/b"
cc.path.driname("a/b/c.png?a=1&b=2");//-->"a/b"
cc.path.dirname("a/b/");//-->"a/b"
cc.path.dirname("c.png");//-->""
* windows
cc.path.driname("a\\b\\c.png");//-->"a\b"
cc.path.driname("a\\b\\c.png?a=1&b=2");//-->"a\b"
* @param {string} pathStr
* @returns {*}
*/
dirname: function (pathStr) {
return pathStr.replace(/((.*)(\/|\\|\\\\))?(.*?\..*$)?/, '$2');
},
/**
* Change extname of a file path.
* @example
cc.path.changeExtname("a/b.png", ".plist");//-->"a/b.plist"
cc.path.changeExtname("a/b.png?a=1&b=2", ".plist");//-->"a/b.plist?a=1&b=2"
* @param {string} pathStr
* @param {string} [extname]
* @returns {string}
*/
changeExtname: function (pathStr, extname) {
extname = extname || "";
var index = pathStr.indexOf("?");
var tempStr = "";
if (index > 0) {
tempStr = pathStr.substring(index);
pathStr = pathStr.substring(0, index);
}
index = pathStr.lastIndexOf(".");
if (index < 0) return pathStr + extname + tempStr;
return pathStr.substring(0, index) + extname + tempStr;
},
/**
* Change file name of a file path.
* @example
cc.path.changeBasename("a/b/c.plist", "b.plist");//-->"a/b/b.plist"
cc.path.changeBasename("a/b/c.plist?a=1&b=2", "b.plist");//-->"a/b/b.plist?a=1&b=2"
cc.path.changeBasename("a/b/c.plist", ".png");//-->"a/b/c.png"
cc.path.changeBasename("a/b/c.plist", "b");//-->"a/b/b"
cc.path.changeBasename("a/b/c.plist", "b", true);//-->"a/b/b.plist"
* @param {String} pathStr
* @param {String} basename
* @param {Boolean} [isSameExt]
* @returns {string}
*/
changeBasename: function (pathStr, basename, isSameExt) {
if (basename.indexOf(".") === 0) return this.changeExtname(pathStr, basename);
var index = pathStr.indexOf("?");
var tempStr = "";
var ext = isSameExt ? this.extname(pathStr) : "";
if (index > 0) {
tempStr = pathStr.substring(index);
pathStr = pathStr.substring(0, index);
}
index = pathStr.lastIndexOf("/");
index = index <= 0 ? 0 : index + 1;
return pathStr.substring(0, index) + basename + ext + tempStr;
},
//todo make public after verification
_normalize: function (url) {
var oldUrl = url = String(url);
//removing all ../
do {
oldUrl = url;
url = url.replace(this.normalizeRE, "");
} while (oldUrl.length !== url.length);
return url;
}
};