UNPKG

magix

Version:

view manager framewrok

568 lines (565 loc) 16.5 kB
let Magix_PathToObjCache = new G_Cache(); let Magix_Booted = 0; //let Magix_PathCache = new G_Cache(); let Magix_ParamsObjectTemp; let Magix_ParamsFn = (match, name, value) => { try { value = decodeURIComponent(value); } catch (_magix) { } Magix_ParamsObjectTemp[name] = value; }; /** * 路径 * @param {String} url 参考地址 * @param {String} part 相对参考地址的片断 * @return {String} * @example * http://www.a.com/a/b.html?a=b#!/home?e=f / => http://www.a.com/ * http://www.a.com/a/b.html?a=b#!/home?e=f ./ =>http://www.a.com/a/ * http://www.a.com/a/b.html?a=b#!/home?e=f ../../ => http://www.a.com/ * http://www.a.com/a/b.html?a=b#!/home?e=f ./../ => http://www.a.com/ * //g.cn/a.html */ /*let G_Path = function(url, part) { let key = url + G_SPLITER + part; let result = Magix_PathCache.get(key), domain = G_EMPTY, idx; if (!Magix_PathCache.has(key)) { //有可能结果为空,url='' path=''; let m = url.match(Magix_ProtocalReg); if (m) { idx = url.indexOf(Magix_SLASH, m[0].length); if (idx < 0) idx = url.length; domain = url.slice(0, idx); url = url.slice(idx); } url = url.replace(Magix_PathTrimParamsReg, G_EMPTY).replace(Magix_PathTrimFileReg, Magix_SLASH); if (!part.indexOf(Magix_SLASH)) { url = G_EMPTY; } result = url + part; console.log('url', url, 'part', part, 'result', result); while (Magix_PathRelativeReg.test(result)) { result = result.replace(Magix_PathRelativeReg, Magix_SLASH); } Magix_PathCache.set(key, result = domain + result); } return result; };*/ /** * 把路径字符串转换成对象 * @param {String} path 路径字符串 * @return {Object} 解析后的对象 * @example * let obj = Magix.parseUri('/xxx/?a=b&c=d'); * // obj = {path:'/xxx/',params:{a:'b',c:'d'}} */ let G_ParseUri = path => { //把形如 /xxx/?a=b&c=d 转换成对象 {path:'/xxx/',params:{a:'b',c:'d'}} //1. /xxx/a.b.c.html?a=b&c=d path /xxx/a.b.c.html //2. /xxx/?a=b&c=d path /xxx/ //3. /xxx/#?a=b => path /xxx/ //4. /xxx/index.html# => path /xxx/index.html //5. /xxx/index.html => path /xxx/index.html //6. /xxx/# => path /xxx/ //7. a=b&c=d => path '' //8. /s?src=b# => path /s params:{src:'b'} //9. a=YT3O0sPH1No= => path '' params:{a:'YT3O0sPH1No='} //10.a=YT3O0sPH1No===&b=c => path '' params:{a:'YT3O0sPH1No===',b:'c'} //11. ab?a&b => path ab params:{a:'',b:''} //12. a=b&c => path '' params:{a:'b',c:''} //13. =abc => path '=abc' //14. ab= => path '' params:{ab:''} //15. a&b => path '' params:{a:'',b:''} let r = Magix_PathToObjCache.get(path), pathname; if (!r) { Magix_ParamsObjectTemp = {}; pathname = path.replace(Magix_PathTrimParamsReg, G_EMPTY); if (path == pathname && Magix_IsParam.test(pathname)) pathname = G_EMPTY; //考虑 YT3O0sPH1No= base64后的pathname path.replace(pathname, G_EMPTY).replace(Magix_ParamsReg, Magix_ParamsFn); Magix_PathToObjCache.set(path, r = { a: pathname, b: Magix_ParamsObjectTemp }); } return { path: r.a, params: { ...r.b } }; }; /*#if(!modules.mini){#*/ /** * 转换成字符串路径 * @param {String} path 路径 * @param {Object} params 参数对象 * @param {Object} [keo] 保留空白值的对象 * @return {String} 字符串路径 * @example * let str = Magix.toUri('/xxx/',{a:'b',c:'d'}); * // str == /xxx/?a=b&c=d * * let str = Magix.toUri('/xxx/',{a:'',c:2}); * * // str == /xxx/?a=&c=2 * * let str = Magix.toUri('/xxx/',{a:'',c:2},{c:1}); * * // str == /xxx/?c=2 * let str = Magix.toUri('/xxx/',{a:'',c:2},{a:1,c:1}); * * // str == /xxx/?a=&c=2 */ let G_ToUri = (path, params, keo) => { let arr = [], v, p, f; for (p in params) { v = params[p] + G_EMPTY; if (v || G_Has(keo, p)) { v = encodeURIComponent(v); arr.push(f = p + '=' + v); } } if (f) { path += (path && (~path.indexOf('?') ? '&' : '?')) + arr.join('&'); } return path; }; let G_ToMap = (list, key) => { let e, map = {}, l; if (list) { for (e of list) { map[(key && e) ? e[key] : e] = key ? e : (map[e] | 0) + 1; //对于简单数组,采用累加的方式,以方便知道有多少个相同的元素 } } return map; }; /*#}#*/ /*#if(modules.updater){#*/ let G_ParseCache = new G_Cache(); let G_ParseExpr = (expr, data, result) => { if (G_ParseCache.has(expr)) { result = G_ParseCache.get(expr); } else { //jshint evil:true result = G_ToTry(Function(`return ${expr}`)); if (expr.indexOf(G_SPLITER) > -1) { G_TranslateData(data, result); } else { G_ParseCache.set(expr, result); } } if (DEBUG) { result = Safeguard(result); } return result; }; let CallIndex = 0; let CallList = []; let CallBreakTime = 48; let StartCall = () => { let last = G_Now(), next; while (1) { next = CallList[CallIndex - 1]; if (next) { next.apply(CallList[CallIndex], CallList[CallIndex + 1]); CallIndex += 3; if (G_Now() - last > CallBreakTime && CallList.length > CallIndex) { setTimeout(StartCall); console.log(`[CF] take a break of ${CallList.length} at ${CallIndex}`); break; } } else { CallList.length = CallIndex = 0; break; } } }; let CallFunction = (fn, args, context) => { CallList.push(fn, context, args); if (!CallIndex) { CallIndex = 1; setTimeout(StartCall); } }; /*#}#*/ let Mark = (host, key) => { let deletedKey = G_SPLITER + '@{marker#object.deleted}'; let markObjectKey = G_SPLITER + '@{marker#object}'; let sign; if (!host[deletedKey]) { let markHost = host[markObjectKey] || (host[markObjectKey] = {}); if (!markHost.hasOwnProperty(key)) { markHost[key] = 0; } sign = ++markHost[key]; } return () => { let temp = host[markObjectKey]; return temp && sign === temp[key]; } }; let Unmark = host => { host[G_SPLITER + '@{marker#object}'] = 0; host[G_SPLITER + '@{marker#object.deleted}'] = 1; }; let EventDefaultOptions = { bubbles: true, cancelable: true }; let DispatchEvent = (element, type, data) => { let e = new Event(type, EventDefaultOptions); G_Assign(e, data); element.dispatchEvent(e); }; /** * Magix对象,提供常用方法 * @name Magix * @namespace */ let Magix = { /** * @lends Magix */ mark: Mark, unmark: Unmark, dispatch: DispatchEvent, task: CallFunction, /** * 设置或获取配置信息 * @param {Object} cfg 初始化配置参数对象 * @param {String} cfg.defaultView 默认加载的view * @param {String} cfg.defaultPath 当无法从地址栏取到path时的默认值。比如使用hash保存路由信息,而初始进入时并没有hash,此时defaultPath会起作用 * @param {Object} cfg.routes path与view映射关系表 * @param {String} cfg.unmatchView 在routes里找不到匹配时使用的view,比如显示404 * @param {String} cfg.rootId 根view的id * @param {Array} cfg.exts 需要加载的扩展 * @param {Function} cfg.error 发布版以try catch执行一些用户重写的核心流程,当出错时,允许开发者通过该配置项进行捕获。注意:您不应该在该方法内再次抛出任何错误! * @example * Magix.config({ * rootId:'J_app_main', * defaultView:'app/views/layouts/default',//默认加载的view * defaultPath:'/home', * routes:{ * "/home":"app/views/layouts/default" * } * }); * * * let config = Magix.config(); * * console.log(config.rootId); * * // 可以多次调用该方法,除内置的配置项外,您也可以缓存一些数据,如 * Magix.config({ * user:'彳刂' * }); * * console.log(Magix.config('user')); */ config(cfg, r) { r = Magix_Cfg; if (cfg) { if (G_IsObject(cfg)) { r = G_Assign(r, cfg); } else { r = r[cfg]; } } return r; }, /** * 应用初始化入口 * @function * @param {Object} [cfg] 配置信息对象,更多信息请参考Magix.config方法 * @return {Object} 配置信息对象 * @example * Magix.boot({ * rootId:'J_app_main' * }); * */ /*#if(modules.router){#*/ boot(cfg) { G_Assign(Magix_Cfg, cfg); //先放到配置信息中,供ini文件中使用 /*#if(modules.configIni){#*/ G_Require(Magix_Cfg.ini, I => { G_Assign(Magix_Cfg, I, cfg); /*#}#*/ G_Require(Magix_Cfg.exts, () => { Router.on(G_CHANGED, Dispatcher_NotifyChange); /*#if(modules.state){#*/ State.on(G_CHANGED, Dispatcher_NotifyChange); /*#}#*/ Magix_Booted = 1; Router_Bind(); }); /*#if(modules.configIni){#*/ }); /*#}#*/ }, /*#}else{#*/ boot(cfg) { G_Assign(Magix_Cfg, cfg); G_Require(Magix_Cfg.exts, () => { Vframe_Root().mountView(Magix_Cfg.defaultView); /*#if(modules.state){#*/ State.on(G_CHANGED, Dispatcher_NotifyChange); /*#}#*/ }); }, /*#}#*/ /*#if(!modules.mini){#*/ /** * 把列表转化成hash对象 * @param {Array} list 源数组 * @param {String} [key] 以数组中对象的哪个key的value做为hash的key * @return {Object} * @example * let map = Magix.toMap([1,2,3,5,6]); * //=> {1:1,2:1,3:1,4:1,5:1,6:1} * * let map = Magix.toMap([{id:20},{id:30},{id:40}],'id'); * //=>{20:{id:20},30:{id:30},40:{id:40}} * * console.log(map['30']);//=> {id:30} * //转成对象后不需要每次都遍历数组查询 */ toMap: G_ToMap, /*#}#*/ /** * 以try cache方式执行方法,忽略掉任何异常 * @function * @param {Array} fns 函数数组 * @param {Array} [args] 参数数组 * @param {Object} [context] 在待执行的方法内部,this的指向 * @return {Object} 返回执行的最后一个方法的返回值 * @example * let result = Magix.toTry(function(){ * return true * }); * * // result == true * * let result = Magix.toTry(function(){ * throw new Error('test'); * }); * * // result == undefined * * let result = Magix.toTry([function(){ * throw new Error('test'); * },function(){ * return true; * }]); * * // result == true * * //异常的方法执行时,可以通过Magix.config中的error来捕获,如 * * Magix.config({ * error:function(e){ * console.log(e);//在这里可以进行错误上报 * } * }); * * let result = Magix.toTry(function(a1,a2){ * return a1 + a2; * },[1,2]); * * // result == 3 * let o={ * title:'test' * }; * let result = Magix.toTry(function(){ * return this.title; * },null,o); * * // result == 'test' */ toTry: G_ToTry, /*#if(!modules.mini){#*/ /** * 转换成字符串路径 * @function * @param {String} path 路径 * @param {Object} params 参数对象 * @param {Object} [keo] 保留空白值的对象 * @return {String} 字符串路径 * @example * let str = Magix.toUrl('/xxx/',{a:'b',c:'d'}); * // str == /xxx/?a=b&c=d * * let str = Magix.toUrl('/xxx/',{a:'',c:2}); * * // str==/xxx/?a=&c=2 * * let str = Magix.toUrl('/xxx/',{a:'',c:2},{c:1}); * * // str == /xxx/?c=2 * let str = Magix.toUrl('/xxx/',{a:'',c:2},{a:1,c:1}); * * // str == /xxx/?a=&c=2 */ toUrl: G_ToUri, /*#}#*/ /** * 把路径字符串转换成对象 * @function * @param {String} path 路径字符串 * @return {Object} 解析后的对象 * @example * let obj = Magix.parseUrl('/xxx/?a=b&c=d'); * // obj = {path:'/xxx/',params:{a:'b',c:'d'}} */ parseUrl: G_ParseUri, /* * 路径 * @function * @param {String} url 参考地址 * @param {String} part 相对参考地址的片断 * @return {String} * @example * http://www.a.com/a/b.html?a=b#!/home?e=f / => http://www.a.com/ * http://www.a.com/a/b.html?a=b#!/home?e=f ./ =>http://www.a.com/a/ * http://www.a.com/a/b.html?a=b#!/home?e=f ../../ => http://www.a.com/ * http://www.a.com/a/b.html?a=b#!/home?e=f ./../ => http://www.a.com/ */ //path: G_Path, /** * 把src对象的值混入到aim对象上 * @function * @param {Object} aim 要mix的目标对象 * @param {Object} src mix的来源对象 * @example * let o1={ * a:10 * }; * let o2={ * b:20, * c:30 * }; * * Magix.mix(o1,o2);//{a:10,b:20,c:30} * * * @return {Object} */ mix: G_Assign, /** * 检测某个对象是否拥有某个属性 * @function * @param {Object} owner 检测对象 * @param {String} prop 属性 * @example * let obj={ * key1:undefined, * key2:0 * } * * Magix.has(obj,'key1');//true * Magix.has(obj,'key2');//true * Magix.has(obj,'key3');//false * * * @return {Boolean} 是否拥有prop属性 */ has: G_Has, /*#if(!modules.mini){#*/ /** * 获取对象的keys * @param {Object} object 获取key的对象 * @type {Array} * @beta * @module linkage|router * @example * let o = { * a:1, * b:2, * test:3 * }; * let keys = Magix.keys(o); * * // keys == ['a','b','test'] * @return {Array} */ keys: G_Keys, /*#}#*/ /** * 判断一个节点是否在另外一个节点内,如果比较的2个节点是同一个节点,也返回true * @function * @param {String|HTMLElement} node节点或节点id * @param {String|HTMLElement} container 容器 * @example * let root = $('html'); * let body = $('body'); * * let r = Magix.inside(body[0],root[0]); * * // r == true * * let r = Magix.inside(root[0],body[0]); * * // r == false * * let r = Magix.inside(root[0],root[0]); * * // r == true * * @return {Boolean} */ inside: G_NodeIn, /** * document.getElementById的简写 * @param {String} id * @return {HTMLElement|Null} * @example * // html * // <div id="root"></div> * * let node = Magix.node('root'); * * // node => div[id='root'] * * // node是document.getElementById的简写 */ node: G_GetById, /*#if(modules.style){#*/ /** * 应用样式 * @beta * @module style * @param {String} prefix 样式的名称前缀 * @param {String} css 样式字符串 * @example * // 该方法配合magix-combine工具使用 * // 更多信息可参考magix-combine工具:https://github.com/thx/magix-combine * // 样式问题可查阅这里:https://github.com/thx/magix-combine/issues/6 * */ applyStyle: View_ApplyStyle, /*#}#*/ /** * 返回全局唯一ID * @function * @param {String} [prefix] 前缀 * @return {String} * @example * * let id = Magix.guid('mx-'); * // id maybe mx-7 */ guid: G_Id, use: G_Require, Cache: G_Cache, /*#if(modules.naked&&!modules.mini){#*/ fire: G_Trigger, type: G_Type, /*#}#*/ nodeId: IdIt, use: G_Require, guard: Safeguard };