UNPKG

sumeru

Version:

A Realtime Javascript RIA Framework For Mobile WebApp

243 lines (187 loc) 9.65 kB
var runnable = function(fw){ var tpls = fw.addSubPackage('render'); //所有分子粒度模板的容器 var MAIN = 'main_tpl'; /* * // 模版的ID,'view/' + tplName 产生 * tplId:{ * // 如果不是MAIN,就认为是子controller使用.销毁主controller时,应同时销毁子controller  * type:{String} * // 指向页面DOM的ID * domId: {String} * //使用当前模版的controllerId数组 * usering : [controllerId], * } */ var tplContentToController = {}; /** * 从一个tplName得到tplId */ var getTplId = function(tplName){ return 'view/' + tplName; }; /** * 从一个tplName取得tplContentId */ var getTplContentId = function(tplName){ return getTplId(tplName) + "@@content"; }; var escapeRegex = function(str){ return (str+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); } tpls.__reg("_buildRender",function(session,source,Handlebars){ var tplName = session.__currentTplName; var isSub = session.__isSubController; var __UK = session.__UK + "_"; var tplId = getTplId(tplName); var recordId = (isSub ? __UK : "") + tplId; // 不能变更tplId,因为tplId将用于在缓存模版的script中取值 var tplContentId = (isSub ? __UK : "") + getTplContentId(tplName); var controllerId = session.__getId(); // session与controller共用相同ID. var tplContentDom; if(tplContentToController[recordId] === undefined){ tplContentToController[recordId] = { type:MAIN, domId:'', usering:[] }; } var tpl = tplContentToController[recordId]; // 如果是子controller,则通过session取得父,并获取ID tpl.type = session.__isSubController ? session.getMain().__getId() : MAIN; tpl.domId = tplContentId; if(tpl.usering.indexOf(controllerId) == -1){ tpl.usering.push(controllerId); } if(tpl.usering.length > 1){ fw.controller.findAndDestroy(tpl.usering,controllerId); } // 解析 //FIXME tplContent和renderBone似乎没有被调用 var tpl = { tplContent:null, renderBone:null, renderBlock:{}, blocksRelation : {} }; tpl.domId = tplContentId; /** * 重用模版的根结点. */ var reg_replaceUK = /(<[\s]*block[^>]+tpl-id=['"])(.+)(['"][^>]*>)/gm; // var parserElement = document.createElement('div'); // var source = document.getElementById(tplId).innerHTML; //=================== // 渲染方法 source = source.replace(reg_replaceUK,function(match, p1, p2, p3){ var rv = p1 + __UK + p2 + p3; return rv; }); /** * blocksRelation * 存储嵌套模板关系的数据结构 * { * tpl-id : { * tpl-id : {空对象代表无下层嵌套view}, * ... * }, * * tpl-id2 : .... * } */ var blocksRelation = {}; var blockPairStart = /(<[\s]*block[^>]+tpl-id=['"]([^'"\s]+)['"][^>]*>)([\s\S]*)/mi, blockPairEnd = /<[\s]*\/[\s]*block[\s]*>/mi, nearbyBlockPairEnd = /(<[\s]*\/[\s]*block[\s]*>)[\s\S]*/mi; //最近的一个结束符 //source = source + ' '; //加一个空格是为了兼容readBlockRelation的正则 var source_ = source, emptyedBlockSource_ = source, //最终将是清理掉每个block标签中内容的结果,对于有嵌套的不做清除 relationLevelStack = [blocksRelation]; //这个函数匹配之后做什么 //匹配<block>后用handlebars进行了渲染 var readBlockRelation = function(){ var pairStartMatcher, pairStartPos, pairStartLength, pairEndPos, match_tplid, nextPairStartPos; while (pairStartMatcher = source_.match(blockPairStart)){ //读取当前匹配的tpl-id match_tplid = pairStartMatcher[2]; //计算<block标签的长度 pairStartLength = pairStartMatcher[1].length; //计算<block标签的index pairStartPos = source_.indexOf(pairStartMatcher[1]); //寻找第一个出现的结束标签 pairEndPos = source_.search(blockPairEnd); if (pairEndPos == -1) { //语法存在错误,少一个</block>的情况 pairEndPos = source_.length; }; if (pairEndPos < pairStartPos) { //如果在当前开头之前还有没处理的关闭标签,就退出这一层递归,交由上一层处理 return; }; //在关系表中记录当前匹配的tplid var relationStack = relationLevelStack[relationLevelStack.length - 1]; relationStack[match_tplid] = {}; //截取模板代码,只取当前匹配的<block标签的后面 source_ = source_.substr(pairStartPos + pairStartLength); pairEndPos -= pairStartPos + pairStartLength; //寻找下一个出现的<block标签 nextPairStartPos = source_.search(blockPairStart); relationLevelStack.push(relationStack[match_tplid]); //如果存在嵌套的下一个block开始标签 if (nextPairStartPos != -1 && nextPairStartPos < pairEndPos) { //递归进去读取子block readBlockRelation(relationStack[match_tplid]); relationLevelStack.pop(); //递归结束后,找到结束的</block>与当前等待的开始标签匹配 var nextPairEndMatcher = source_.match(nearbyBlockPairEnd); if (nextPairEndMatcher) { var nextPairEndMatcherPos = source_.search(nearbyBlockPairEnd), nextPairEndMatcherLength = nextPairEndMatcher[1].length; //截取模板代码,只取当前匹配的</block>标签的后面 source_ = source_.substr(nextPairEndMatcherPos + nextPairEndMatcherLength); //构造一个正则 从原始的source中提取出这一段html var tmp_reg = new RegExp('<[\\s]*block[^>]+tpl-id=[\'"]' + match_tplid + '[\'"][^>]*>([\\s\\S]+)<[\\s]*\/[\\s]*block[\\s]*>' + escapeRegex(source_) + '$', 'mi'); //注意这里使用的是原始的source var tmp_match = source.match(tmp_reg); if (tmp_match) { tpl.renderBlock[match_tplid] = Handlebars.compile(tmp_match[1]); }; }; } else { relationLevelStack.pop(); tpl.renderBlock[match_tplid] = Handlebars.compile(source_.substr(0, pairEndPos)); //对于没有嵌套的,在渲染骨架时,清除其内的内容 var emptyBottomBlockRegexp = new RegExp('(<[\\s]*block[^>]+tpl-id=[\'"]' + match_tplid + '[\'"][^>]*>)[\\s\\S]*?(<[\\s]*\/[\\s]*block[\\s]*>)', 'mi'); emptyedBlockSource_ = emptyedBlockSource_.replace(emptyBottomBlockRegexp, "\$1\$2"); //截取模板代码,只取当前匹配的</block>标签的后面 var nextPairEndMatcher = source_.match(nearbyBlockPairEnd); if (nextPairEndMatcher) { var nextPairEndMatcherPos = source_.search(nearbyBlockPairEnd), nextPairEndMatcherLength = nextPairEndMatcher[1].length; source_ = source_.substr(nextPairEndMatcherPos + nextPairEndMatcherLength); } } } } readBlockRelation(); delete relationLevelStack; tpl.blocksRelation = blocksRelation; //使用非贪婪匹配正则,去掉block中的元素 //source = source.replace(/(<block[^>]*>)[\s\S]*?(<\/block>)/ig,"\$1\$2"); //先把骨头架子渲染出来,不带有具体的block内容 var renderFunc = tpl.renderBone = Handlebars.compile(emptyedBlockSource_); //recycle // parserElement = null; tpl.tplContent = renderFunc({}); return tpl; },true); } if(typeof module !='undefined' && module.exports){ module.exports = runnable; }else{//这里是前端 runnable(sumeru); }