UNPKG

sumeru

Version:

A Realtime Javascript RIA Framework For Mobile WebApp

548 lines (454 loc) 18.4 kB
var runnable = function(fw){ if(fw.utils){ return fw.utils; } var utils = fw.addSubPackage('utils'); //========== inner function =================// var arrSplice = Array.prototype.splice; var arrConcat = Array.prototype.concat; var isArray = Array.isArray; var callArrSpl = function(arr/*,...args*/){ return arrSplice.apply(arr,arrSplice.call(arguments,1)); }; var oKeys = Object.keys; var callArrConcat = function(arr){ return arrConcat.apply(callArrSpl(arr,0),callArrSpl(arguments,1)); }; function _cpp(source){ oKeys(source).forEach(function(key){ this[key] = source[key]; },this); }; //====== below publish =======// /** * copy对像的属性及方法到指定的目标上. * @param target {Object} 目标对像 * @param ...args {...Object} 源对像 */ var cpp = utils.__reg('cpp',function(target/*,...args*/){ var objs = callArrSpl(arguments,1); objs.forEach(_cpp,target); return target; }); var extendFrom = utils.__reg('extendFrom',function(_base,_exts){ var rv = null , fun=function(){}; if(Object.create){ rv = Object.create(_base); }else{ fun.prototype = _base; rv = new fun(); } return cpp(rv,_exts); }); /** * 创建一个对像的代理对像,用于隐藏原始对像上的部份方法与全部属性 */ var getProxy = utils.__reg('getProxy',function(obj,nameList){ var proxy = {}; nameList.forEach(function(key){ var me = this; proxy[key] = function(){ if(me[key] instanceof Function){ return me[key].apply(me,arguments); }else{ throw key + ' is not a function'; } }; },obj); return proxy; }); /** * 销毁一个对像上的引用 */ var cleanObj = utils.__reg('cleanObj',function(obj,each){ var keys = Object.keys(obj); keys.forEach(function(key){ try{ if(key != 'isDestroy'){ each && each(this[key]); if(typeof(this[key]) == 'array' ){ this[key].length = 0; } delete this[key]; } }catch (e) {} },obj); }); /** * 对传入字符进行完整符合RFC3986的URI编码. * @param str {string}将进行编码的字符串 * @returns {string} */ var encodeURIComponentFull = utils.__reg('encodeURIComponentFull',function(str){ var result = encodeURIComponent(str); // 处理encodeURIComponent不编码的特殊字符 result = result.replace(/!/g , '%21'); // . %2E result = result.replace(/\*/g , '%2A'); // . %2E result = result.replace(/'/g , '%27'); // . %2E result = result.replace(/\(/g , '%28'); // . %2E result = result.replace(/\)/g , '%29'); // . %2E result = result.replace(/\./g , '%2E'); // . %2E result = result.replace(/\-/g , '%2D'); // . %2E result = result.replace(/\_/g , '%5F'); // . %2E result = result.replace(/\~/g , '%7E'); // . %2E return result; }); /** * 将URI参数还原为map结构 * @param str {String} 可解码的uri参数 * @returns {Object} 解码后的map对像 */ var uriParamToMap = utils.__reg('uriParamToMap',function (str){ var rv = {}; // 如果str为空串,null,undefined,则直接返回空字符串 if(!str){ return rv; } var params = str.split('&'); params.forEach(function(item){ var parts = item.split('='); // 仅处理正常的key,value, 非正常则忽略 if(parts[0]){ this[parts[0]] = decodeURIComponent(parts[1]); } },rv); return rv; }); var joinArrayAndEncodeURI = function(arr,separator){ var rv = []; arr.forEach(function(item){ rv.push(encodeURIComponentFull(item)); }); return rv.join(separator); }; var mapToUriParam = utils.__reg('mapToUriParam',function(map){ var rv = [],keys = null; // 非对像类型,不进行处理 if(typeof(map) != 'object' || Array.isArray(map)){ return ''; } keys = Object.keys(map); keys.forEach(function(key){ var value = map[key]; switch(typeof(value)){ case "string": case "number": case "boolean": rv.push(key + "=" + encodeURIComponentFull(value)); case "object": if(Array.isArray(value)){ rv.push(key + "=" + joinArrayAndEncodeURI(value)); } default: return; } }); return rv.join("&"); }); var randomInt = utils.__reg('randomInt',function (min,max){ return Math.floor(Math.random() * (max - min + 1) + min); }); var randomStr_str = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'; var randomStr_len = randomStr_str.length - 1; utils.__reg('randomStr',function randomStr(max){ var rv = ''; for(var i=0;i<max;i++){ rv += randomStr_str[randomInt(0,randomStr_len)]; } return rv; }); /** * 解析JSON,相比JSON.parse能忽略一些错误,如JSON.parse不能解析单引号等。但有被注入的风险。 * 所以在方法中屏蔽了对window,document,sumeru,XMLHttpRequest等对像的直接引用。 */ var parseJSON = utils.__reg('parseJSON',function(str){ //使用Function的方式parse JSON字符串,并隐藏 window,document,sumeru,XMLHttpRequest等对像,防止注入 return (new Function('window','document','sumeru','XMLHttpRequest','return ' + str + ';')).call({},undefined,undefined,undefined,undefined); }); var isSimpleType = utils.__reg('isSimpleType',function(value){ switch(typeof(value)){ case "string": case "number": case "boolean": return true; } return false; }); var setStyles = utils.__reg('setStyles',function setStyles(element,propertys){ var sty = element.style , val = ""; var reg = /^(left|top|bottom|right|width|height)$/i; for(var key in propertys){ val = propertys[key]; if(typeof(propertys[key]) == 'number' && reg.test(key)){ val += "px"; } sty[key] = val; } return element; }); /** * 实现方法链,即一个方法的传出是后一个方法的传入, * * function的建议写法为 * * function(param1,param2,....,onerror,){ * .... // 处理过程 * onerror(); // 处理失败通知 * return; * .... // 处理过程 * onsuccess(param1,param2,....,onerror); //处理成功通知执行下一个 * } * * 其中 * param1... 在调用run的时候传入,将自动做为function的参数在调用时被传入 * onerror 在调用run时做为最后一个参数传入.如果不传则不会接收到异常中止的通知。因为错误控制不属于chain处理中的必要内容,所以不自动传入。 * onsuccess 为自动传入,调用时请将除onsuccess以外的参数,处理后原顺序传入。 * * 此实现支持异步处理,即方法最后一个参数补充传入一个callback用于执行下一个方法。 * 同步实现请自己去写循环.... * * @param chainItems {Array} 链上的组成方法,每个元素为一个function. * @param finalCallback {function} 当执行完成整条方法链时,最终被调用的通知方法。 * @returns {function} 一个可执行的方法,用于启动方法链,该方法只能执行一次, 执行后,该方法的参数将做为每一个chainItem的参数被传入。 */ fw.utils.__reg('chain',function(chainItems,finalCallback){ // 确保接收到的是一整组可执行的并且参数数量一至的方法 if(!Array.isArray(chainItems)){ return false; } var arrlen = chainItems[0].length; if(!chainItems.every(function(item){ return item instanceof Function && item.length === arrlen; })){ return false; } var i = 0; var runNext = null; runNext = function(){ var item = chainItems[i++]; if(item !== undefined){ var args = callArrConcat(arguments,runNext); item.apply(this,args); // 如果上层方法使用call和apply执行,则有this,否则没有 }else{ finalCallback.apply(this,callArrSpl(arguments,0)); } }; return runNext; }); //========默认的getTimeStamp方法,获取本地时间。当连接服务器后,此方法将会被覆盖为获得云端时间的方法 =======// fw.utils.__reg('getTimeStamp', function(){ return (new Date()).valueOf(); }); //========= 以下为旧的未整理过的代码,wangsu ==========// var __randomMap = {}; fw.__random = function(len) { len = len || 10; var chars = "qwertyuiopasdfghjklzxcvbnm1234567890", charsLen = chars.length, len2 = len, rand = ""; while (len2--) { rand += chars.charAt(Math.floor(Math.random() * charsLen)); } if (__randomMap[rand]) { return random(len); } __randomMap[rand] = 1; return rand; }; //========= 以下为用到的工具代码,huangxin03 ==========// //深度克隆 var clone = function(item){ if (!item) { return item; } // null, undefined values check var types = [ Number, String, Boolean ], result; // normalizing primitives if someone did new String('aaa'), or new Number('444'); types.forEach(function(type) { if (item instanceof type) { result = type( item ); } }); if (typeof result == "undefined") { if (Object.prototype.toString.call( item ) === "[object Array]") { result = []; item.forEach(function(child, index, array) { result[index] = clone( child ); }); } else if (typeof item == "object") { // testing that this is DOM if (item.nodeType && typeof item.cloneNode == "function") { var result = item.cloneNode( true ); } else if (!item.prototype) { // check that this is a literal if (item instanceof Date) { result = new Date(item); } else { // it is an object literal result = {}; for (var i in item) { result[i] = clone( item[i] ); } } } else { // depending what you would like here, // just keep the reference, or create new object if (false && item.constructor) { // would not advice to do that, reason? Read below result = new item.constructor(); } else { result = item; } } } else { result = item; } } return result; } fw.utils.__reg('deepClone', clone); //merge two object, append b to a var merge = function(a, b){ var copy = clone(a); for(x in b){ typeof copy[x] !== 'undefined' ? false :copy[x] = b[x]; } return copy; } fw.utils.__reg('merge', merge); // modify from node emitter var simpleEventEmitter = function(){ this._events = {}; }; simpleEventEmitter.prototype = { addEventListener:function(type,listener){ if ('function' !== typeof listener) { throw new Error('addListener only takes instances of Function'); } if (!this._events) this._events = {}; // To avoid recursion in the case that type == "newListeners"! Before // adding it to the listeners, first emit "newListeners". this.emit('newListener', type, typeof listener.listener === 'function' ? listener.listener : listener); if (!this._events[type]) { // Optimize the case of one listener. Don't need the extra array object. this._events[type] = listener; } else if (isArray(this._events[type])) { // If we've already got an array, just append. this._events[type].push(listener); } else { // Adding the second element, need to change to array. this._events[type] = [this._events[type], listener]; } // Check for listener leak if (isArray(this._events[type]) && !this._events[type].warned) { var m; m = this._maxListeners; if (m && m > 0 && this._events[type].length > m) { this._events[type].warned = true; console.error('(node) warning: possible EventEmitter memory ' + 'leak detected. %d listeners added. ' + 'Use emitter.setMaxListeners() to increase limit.', this._events[type].length); console.trace(); } } return this; }, on:function(type,listener){ return this.addEventListener.apply(this,arguments); }, once:function(type,listener){ if ('function' !== typeof listener) { throw new Error('.once only takes instances of Function'); } var self = this; function g() { self.removeListener(type, g); listener.apply(this, arguments); }; g.listener = listener; self.on(type, g); return this; }, removeListener:function(type,listener){ if ('function' !== typeof listener) { throw new Error('removeListener only takes instances of Function'); } // does not use listeners(), so no side effect of creating _events[type] if (!this._events || !this._events[type]) return this; var list = this._events[type]; if (isArray(list)) { var position = -1; for (var i = 0, length = list.length; i < length; i++) { if (list[i] === listener || (list[i].listener && list[i].listener === listener)) { position = i; break; } } if (position < 0) return this; list.splice(position, 1); if (list.length == 0) delete this._events[type]; } else if (list === listener || (list.listener && list.listener === listener)) { delete this._events[type]; } return this; }, removeAllListeners : function(type) { if (arguments.length === 0) { this._events = {}; return this; } // does not use listeners(), so no side effect of creating _events[type] if (type && this._events && this._events[type]) this._events[type] = null; return this; }, emit:function(event){ var type = arguments[0]; if (!this._events) return false; var handler = this._events[type]; if (!handler) return false; if (typeof handler == 'function') { switch (arguments.length) { // fast cases case 1: handler.call(this); break; case 2: handler.call(this, arguments[1]); break; case 3: handler.call(this, arguments[1], arguments[2]); break; // slower default: var l = arguments.length; var args = new Array(l - 1); for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; handler.apply(this, args); } return true; } else if (isArray(handler)) { var l = arguments.length; var args = new Array(l - 1); for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; var listeners = handler.slice(); for (var i = 0, l = listeners.length; i < l; i++) { listeners[i].apply(this, args); } return true; } else { return false; } } }; fw.utils.__reg('emitter', simpleEventEmitter); }; if(typeof module !='undefined' && module.exports){ module.exports = runnable; }else{ runnable(sumeru); }