nyx_server
Version:
Node内容发布
350 lines (315 loc) • 11.5 kB
JavaScript
/* 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;