UNPKG

nyx_server

Version:

Node内容发布

350 lines (315 loc) 11.5 kB
/* global global */ var fs = require("fs"); var Promise = require("bluebird"); var htmlparser = require("htmlparser2"); var domUtil = htmlparser.DomUtils; var ElementType = require("domelementtype"); var util = require("util"); var logger = require("log4js"); var log = logger.getLogger("TemplateContent"); function TemplateContent(filePath){ this.filePath = filePath; this.nodeId = 0; this.contentPromise = null; this.resetContent(); this.filePathCatch = {}; } /** * 模板内容 */ TemplateContent.prototype.getContent = function(requestParams){ var mode = requestParams.mode; if(mode == 'preview' || mode == 'publish'){ return this.getOriginContent(); //得到原始内容 }else if(mode == 'edit'){ return this.getDom(requestParams).then(function(dom){ var content = domUtil.getOuterHTML(dom); content = generateSource(content , mode); //设置节点的 notedit属性 //将<?> 标记转换为 <%%> 标记 content = content.replace(/<[?]{1,2}|[?]{1,2}>/ig ,function(match , offset , input){ return match.replace(/\?/g , "%"); }); return content; }); } }; /** * 得到dom没有修改的内容,但是修改了 */ TemplateContent.prototype.getOriginContent = function(reset){ var self = this; // if(reset || !this.filePathCatch[self.filePath]){ var p = new Promise(function(resolve , reject){ fs.readFile(self.filePath ,{encoding:'utf8',flag:'r'}, function(err , content){ if(err){ reject(err); }else{ resolve(content); } }); }); //this.filePathCatch[self.filePath] = p; return p; // }else{ // return this.filePathCatch[self.filePath]; // } }; TemplateContent.prototype.resetContent = function(){ delete this.contentPromise; this.contentPromise = this.getOriginContent(); }; /** * 得到文档的dom结构 */ TemplateContent.prototype.getDom = function(requestParams){ var mode = requestParams.mode; return this.contentPromise.then(function(content){ //替换<%%>脚本到htmlparser2能够处理的<??>标签 content = content.replace(/<[%]{1,2}|[%]{1,2}>/ig ,function(match , offset , input){ return match.replace(/%/g , "?"); }); return new Promise(function(resolve , reject){ var domHandler = new htmlparser.DomHandler(function(err , dom){ if(err){ reject(err); }else{ resolve(dom); } } , {"withStartIndices":true} , function(ele){ if(mode == 'edit'){ if(domUtil.isTag(ele)){ ele.attribs[global.nxyConfig.nodeidAttr] = ele.startIndex; //设置节点的nodeid属性 } } if(ElementType.Directive == ele.type){ ele.data = addChipParams(ele.data , ele.startIndex , requestParams); //修改chip脚本内容 } }); domHandler.onprocessinginstruction = function(name, data){ var element = { name: name, data: data, type: ElementType.Directive }; this._addDomElement(element); if(this._elementCB) this._elementCB(element); }; var parser = new htmlparser.Parser(domHandler); parser.write(content); parser.done(); }); }); }; /** * 得到模板文件的路径 */ TemplateContent.prototype.getFilePath = function(){ return this.filePath; }; /** * 同步内容到原始文件 */ TemplateContent.prototype.sync = function(dom){ domUtil.findAll(function(ele){ //删除nodeid属性 delete ele.attribs[global.nxyConfig.nodeidAttr]; //节点nodeid属性 delete ele.attribs[global.nxyConfig.noeditAttr]; //节点notedit属性 return domUtil.isTag(ele); } , dom); var content = domUtil.getOuterHTML(dom); var d = "?"; var ds = "<\\"+d+"{1,2}"+"|\\"+d+"{1,2}>"; var regexp = new RegExp(ds , 'ig'); content = content.replace(regexp , function(match , offset , input){ var r = new RegExp("\\"+d , 'ig'); return match.replace(r , "%"); }); return this.syncContent(content); }; TemplateContent.prototype.syncContent = function(content){ var self = this; return new Promise(function(resolve , reject){ fs.writeFile(self.filePath , content , function(err){ if(err){ reject(err); }else{ self.resetContent(); resolve(true); } }); }); }; /** * 替换节点 * @param {String}nodeId */ TemplateContent.prototype.replace = function(nodeId , replaceContent){ var self = this; return this.getOriginContent().then(function(content){ content = content.replace(/<[%]{1,2}|[%]{1,2}>/ig ,function(match , offset , input){ return match.replace(/%/g , "?"); }); return new Promise(function(resolve , reject){ var domHandler = new htmlparser.DomHandler(function(err , dom){ if(err){ reject(err); }else{ resolve(dom); } } , {"withStartIndices":true} , function(ele){ }); var parser = new htmlparser.Parser(domHandler); parser.write(content); parser.done(); }); }).then(function(dom){ var haschange = false; function _replace(_dom){ var textNode = { name: "?", data : "?="+replaceContent+"?", type : ElementType.Directive }; var _matchNode = domUtil.findOne(function(ele){ return ele.startIndex == nodeId; } , _dom); if(_matchNode){ domUtil.replaceElement(_matchNode , textNode); haschange = true; }else{ log.info("template ``"+self.filePath+", node "+nodeId+" not match"); } } if(Array.isArray(dom)){ _replace(dom); }else{ _replace([dom]); } return new Promise(function(resolve , reject){ if(haschange){ self.sync(dom).then(function(){ resolve(true); }).error(function(){ reject(false); }); }else{ resolve(true); } }); }).catch(function(err){ console.log(err); throw new Error(err); }); }; TemplateContent.prototype.find = function(node){ }; function addChipParams(content , nodeid , requestInfo){ //var regex = /chip(\s*)\((\s*[^,]*\s*)(?:,(\s*[^,]*\s*))?\)/; // return content.replace(regex , function(match , space , param1 , param2 , offset , input){ // param2 += ","+nodeid+","+JSON.stringify(requestInfo); // var ret = "chip"+space+"("+param1+","+param2+")"; // console.log('---->addChipParams' , ret); // return ret; // }); var regex = /chip(\s*)\(([^)]*)\)/;; return content.replace(regex , function(match , space , param , offset , input){ param += ","+nodeid;//+","+JSON.stringify(requestInfo); var ret = "chip"+space+"("+param+")"; return ret; }); } function escapeRegExpChars(string) { if (!string) { return ''; } return String(string).replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); }; function generateSource(templateText , mode) { var matches = parseTemplateText(templateText) , d = global.nxyConfig.ejs_delimiter; var startTag = false; var ret = ''; var bracketsStack = []; if (matches && matches.length) { matches.forEach(function (line, index) { var closing; if ( line.indexOf('<' + d) === 0 // If it is a tag && line.indexOf('<' + d + d) !== 0) { // and is not escaped closing = matches[index + 2]; if (!(closing == d + '>' || closing == '-' + d + '>')) { throw new Error('Could not find matching close tag for "' + line + '".'); } } if(line.indexOf('<' + d) == 0){ startTag = true; } if(line.indexOf(d + '>') == 0){ startTag = false; } if(startTag && line.indexOf('<' + d) !== 0){ //这里分析花括号,花括号要成对出现 parseBrackets(line , bracketsStack); } if(mode == "edit"){ if(bracketsStack.length > 0 && startTag==false){ line = line.replace(/(<[^\/][^>]*>)/g , function(match , block , offset , input){ return match.replace(/>|\/>/ig , " "+global.nxyConfig.noeditAttr+">"); }); } } ret += line; }); } return ret; } function parseBrackets(content , stack){ var str = content , pat = new RegExp('({|})') , result = pat.exec(str) , firstPos , lastPos; while (result) { firstPos = result.index; lastPos = pat.lastIndex; if (firstPos !== 0) { str = str.slice(firstPos); } var v = result[0]; var v1 = stack[0]; if((typeof v1 != 'undefined') && (v1 !== v)){ stack.shift(); }else{ stack.push(result[0]); } str = str.slice(result[0].length); result = pat.exec(str); } return stack; } function parseTemplateText(templateText) { var str = templateText , regstr = '(<%%|<%=|<%-|<%#|<%|%>|-%>)' , pat = new RegExp(regstr.replace(/%/g , escapeRegExpChars(global.nxyConfig.ejs_delimiter))) , result = pat.exec(str) , arr = [] , firstPos , lastPos; while (result) { firstPos = result.index; lastPos = pat.lastIndex; if (firstPos !== 0) { arr.push(str.substring(0, firstPos)); str = str.slice(firstPos); } arr.push(result[0]); str = str.slice(result[0].length); result = pat.exec(str); } if (str) { arr.push(str); } return arr; } module.exports = TemplateContent;