用html+javascript打造公文一键排版系统7:落款排版

一、公文落款的格式

公文落款包括单位署名和成文日期两个部分,其中成文日期中的数字 用阿拉伯数字将年、月、日标全,年份应标全称,月、日不编虚位(即 1 不编为 01)。

在实际应用工作中分为三种情况:

(一)加盖印章的公文

成文日期一般右空四字编排,印章用红色,不得出现空白印章。

单一机关行文时,一般在成文日期之上、以成文日期为准居中编排发文机关署名,印章端正、 居中下压发文机关署名和成文日期,使发文机关署名和成文日期居印章中心偏下位置,印章顶端应 当上距正文(或附件说明)一行之内。 联合行文时,一般将各发文机关署名按照发文机关顺序整齐排列在相应位置,并将印章一一对 应、端正、居中下压发文机关署名,最后一个印章端正、居中下压发文机关署名和成文日期,印章 之间排列整齐、互不相交或相切,每排印章两端不得超出版心,首排印章顶端应当上距正文(或附 件说明)一行之内。

(二)不加盖印章的公文

单一机关行文时,在正文(或附件说明)下空一行右空二字编排发文机关署名,在发文机关署名下一行编排成文日期,首字比发文机关署名首字右移二字,如成文日期长于发文机关署名,应当 使成文日期右空二字编排,并相应增加发文机关署名右空字数。 联合行文时,应当先编排主办机关署名,其余发文机关署名依次向下编排。

(三)加盖签发人签名章的公文

单一机关制发的公文加盖签发人签名章时,在正文(或附件说明)下空二行右空四字加盖签发 人签名章,签名章左空二字标注签发人职务,以签名章为准上下居中排布。在签发人签名章下空一 行右空四字编排成文日期。 联合行文时,应当先编排主办机关签发人职务、签名章,其余机关签发人职务、签名章依次向 下编排,与主办机关签发人职务、签名章上下对齐;每行只编排一个机关的签发人职务、签名章; 签发人职务应当标注全称。 签名章一般用红色。

二、编程实现落款排版

这里我们只考虑不加盖印章的公文的情况,而且不考虑联合行文。

要识别公文落款,我们同时对前后相邻两个段落文字p1和p2进行分析,首先,p1段末不含标点,

p2内容符合dddd年dd月dd日格式,其中d为阿拉伯数字。

我们首先利用正则表达式来判断给定字符串是否符合dddd年dd月dd日格式。代码如下:

javascript 复制代码
//增:2023-07-16
//判断是否为dddd年dd月dd日格式
String.prototype.isDateCn = function()
{
	//return (/^(\d{4})([\u5e74]{1})(\d{1,2})([\u6708]{1})\d{1,2}([\u65e5]{1})$/.test(this)); //年=\u5e74,月=\u6708,日=\u65e5
  
	return (/^(\d{4})([年]{1})(\d{1,2})([月]{1})\d{1,2}([日]{1})$/.test(this)); //年=\u5e74,月=\u6708,日=\u65e5
}


//增:2023-07-16
//判断dddd年dd月dd日是否符合闰年等规则
String.prototype.isRightDateCn = function()
{
  return (/^(?:(?!0000)[0-9]{4}([年]{1})(?:(?:0?[1-9]|1[0-2])\1(?:0?[1-9]|1[0-9]|2[0-8])|(?:0?[13-9]|1[0-2])\1(?:29|30)|(?:0?[13578]|1[02])\1(?:31))|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)([月]{1})0?2\2(?:29))([日]{1})$/.test(this));
}

在些基础上,我们编写isBadging()来判断相连两段文字是否为落款,代码如下:

javascript 复制代码
//增:2023-07-16
//功能:判断是否为落款
//输入:t1:落款单位,t2:落款日期
//输出:true:是落款;false:非落款
function isBadging(t1,t2)
{
	if (isAstatement(t1))//落款单位末尾是否带符号?
	{
		return false;//带符号,不是落款
	}

	return (t2.isDateCn());
}//isBadging(t1,t2)

如果确实是落款,我们要根据公文排版要求进行格式设置。首要需要计算出发文机关署名和成文日期的宽度,再进行比较。获取字符串宽度的方法有很多种,这里我们利用canvas.getContext().measureText().width来实现,代码如下:

javascript 复制代码
//增:2023-07-22
//功能:利用canvas取字符串宽度
//输入:s:字符串,f:字体
//输出:字符串宽度
function getStrWidth(s, f)
{
  //alert(s);
  var canvas = getStrWidth.canvas || (getStrWidth.canvas = document.createElement("canvas"));
  var ctx = canvas.getContext("2d"); 
  ctx.font = f;
  return ctx.measureText(s).width;
}//geStrWidth()

取得发文机关署名和成文日期的宽度后,我们就可以进行比较并根据比较结果来排版

比较难的是:

如成文日期长于发文机关署名,应当 使成文日期右空二字编排,并相应增加发文机关署名右空字数。

代码如下:

javascript 复制代码
//增:2023-07-16,改2023-07-22
//功能:设置落款格式
//输入:t1:落款单位,t2:落款日期
//输出:格式化后的落款单位和落款日期代码
function setBadging(t1,t2)
{
	var r = new Array();
	var f =  mtfs+ 'pt' + ' '+ mtfn;//顺序不能颠倒!
	//noSeal
	var iSize1 = getStrWidth(t1, f);
	var iSize2 = getStrWidth(t2, f);
	//document.write('<p>' + iSize1 + "  "  + iSize2);
	if (iSize2 > iSize1)
	{
		//如成文日期长于发文机关署名,应当使成文日期右空二字编排,并相应增加发文机关署名右空字数。
		r[0] = '<p style="line-height:' + rs + 'pt; font-family:' + mtfn + ';font-size:' + mtfs + 'pt; text-align:right; margin:0 ' + Math.ceil((iSize2 - iSize1)/2 + 48) + 'px 0 0">' + t1;//1em=16px,2em=32px,3em=48px
		r[1] = '<p style="line-height:' + rs + 'pt; font-family:' + mtfn + ';font-size:' + mtfs + 'pt; text-align:right; margin:0 2em 0 0">' + t2;
	}
	else
	{
		//单一机关行文时,在正文(或附件说明)下空一行右空二字编排发文机关署名,在发文机关署名下一行编排成文日期,首字比发文机关署名首字右移二字
		r[0] = '<p style="line-height:' + rs + 'pt; font-family:' + mtfn + ';font-size:' + mtfs + 'pt; text-align:right; margin:0 2em 0 0">' + t1;
		r[1] = '<p style="line-height:' + rs + 'pt; font-family:' + mtfn + ';font-size:' + mtfs + 'pt; text-align:right; margin: 0 ' + (iSize1 - iSize2) + 'px 0 0">' + t2;
	}

	return r.join('');
}//setBadging()

这里我们将格式化后的落款单位和落款日期代码合并成一个字符串了,那么setDocFmt()作相应的修改:

javascript 复制代码
//功能:设置公文格式Set document format
//输入:无
//输出:无
function setDocFmt()
{
	taDbg.value += "\n---setDocFmt()\n";

	getArg();

	var t = getClearInfoArray();

	//标题
	if (cbDocTilte)
	{
		t[0]  = setDocTitle(t[0]) + '</p><p style="margin:0; line-height:"' + rs +'">&nbsp;';
	}
/*
	for (var i = (cbDocTilte ? 1: 0); i < t.length; i++)
	{
		t[i] = setParaFmt(t[i]);
	}
*/

	var i =  (cbDocTilte ? 1 : 0);//增:2023-07-16
	while (i < t.length)
	{
		if (isBadging(t[i],t[i+1]))
		{
			//落款前加空行
			t[i-1] += '</p><p style="margin:0; line-height:"' + rs +'">&nbsp;';
			//设置落款
			t[i] = setBadging(t[i],t[i+1]);
			t[i+1] = null;
			taDbg.value += "\nt[" + (i-1) + "]=" + t[i-1] + "\nt[" + i +"]=" + t[i] + "\nt[" +(i+1) +"]=" + t[i+1];
			//i++;
			//i++;
			i += 2;
		}
		else
		{
			t[i] = setParaFmt(t[i]);
			i++;
		}
	}//while()
	
	alert(t.join(''));
	edRichBody.innerHTML = t.join(''); 
}//setDocFmt() 

三、程序运行效果

四、完整代码如下

html 复制代码
<!DOCTYPE HTML>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<title>公文一键排版系统</title>

<script type="text/javascript">
var aFontName = [
	"方正小标宋简体",//0
	"黑体",//1
	"微软雅黑",//2
	"仿宋_GB2312",//3
	"仿宋",//4
	"楷体_GB2312",//5
	"楷体",//6
	"宋体",//7
	"Arial",//8
	"Wingdings 2"//9
];

//sId:select control id, iDefSel:default selected
function showFontNameSel(sId, iDefSel)
{
	document.write('<select id="', sId, '" width="50">');
	for (var i = 0; i < aFontName.length; i++)
	{
		document.write('<option value="', aFontName[i], '"');
		document.write(i==iDefSel ? ' selected>' : '>');
		document.write(aFontName[i],'</option>');
	}
	document.write('</select>');
}

var aFontSize = [
	['初号', 42],//0
	['小初', 36],//1
	['一号', 26],//2
	['小一', 24],//3
	['二号', 22],//4
	['小二', 18],//5
	['三号', 16],//6
	['小三', 15],//7
	['四号', 14],//8
	['小四', 12],//9
	['五号', 10.5], //10
	['小五', 9],//11
	['六号', 7.5],//12
	['小六', 6.5],//13
	['七号', 5.5],//14
	['八号', 5]//15
];

//sId:select control id, iDefSel:default selected
function showFontSizeSel(sId, iDefSel)
{
	document.write('<select id="', sId, '">');
	for (var i = 0; i < aFontSize.length; i++)
	{
		document.write('<option value="',aFontSize[i][1], '"');
		document.write(i==iDefSel ? ' selected>' : '>');
		document.write(aFontSize[i][0],'</option>');
	}
	document.write('</select>');
}

var aAlign = [
	["左对齐","left"],//0
	["居中对齐","center"],//1
	["右对齐","right"],//2
	["两端分散对齐","justify"]//3
];

//sId:select control id, iDefSel:default selected
function showAlignSel(sId, iDefSel)
{
	document.write('<select id="', sId, '">');
	for (var i = 0; i < aAlign.length; i++)
	{
		document.write('<option value="',aAlign[i][1], '"');
		document.write(i==iDefSel ? ' selected>' : '>');
		document.write(aAlign[i][0],'</option>');
	}
	document.write('</select>');
}//showAlignSel()


function setDocTitle(s)
{
/*
	//标题字体名 font name
	//var o = document.getElementById('selDocTitleFontName');
	var dtfn = document.getElementById('selDocTitleFontName').value;
	//alert(fn);
	//标题字号 font size
	var dtfs = document.getElementById('selDocTitleFontSize').value;
	//alert(fs);
	//标题对齐方式 text align
	var dtta = document.getElementById('selDocTitleAlign').value;
	//alert(ta);
	//标题行距 row spacing
	 //var rs  = document.getElementById('tbRowSp').value;
	//return '<span style="font-family:' + fn + ';font-size:' + fs +';text-align:' + ta + ';">' + s + '</span>';
*/	
	return '<p style="font-family:' + dtfn + ';font-size:' + dtfs +'pt; text-align:' + dtta + '; line-height:' +  rs + 'pt;">' + s;
}//setDocTitle()


//去除<P>中的属性
function stripPattribs(s)
{
	var i = s.indexOf('>');
	return  ((-1 != i) ? s.substr(i+1)	: s);
}

//去除HTML代码
String.prototype.stripHTML = function() 
{
    var reTag = /<(?:.|\s)*?>/g;  
	//var	reTag = /<[^>]+>/gi;	//过滤所有html标签,但不包括html标签内的内容 

    return this.replace(reTag,"");
}

String.prototype.trim = function() 
{//去除首尾空格
	return this.replace(/(^\s*)|(\s*$)/g, ""); 
	/*var t = this.replace(/(^\s*)|(\s*$)/g, ""); 
	return t =t.replace(/(^&nbsp;*)|(&nbsp*$)/g, ""); */
} 

String.prototype.ltrim = function() 
{ 
	return this.replace(/(^\s*)/g, ""); 
} 

String.prototype.rtrim = function() 
{ 
	return this.replace(/(\s*$)/g, ""); 
} 

//判断是否为中文标点符号
String.prototype.isCnPunctuation = function() 
{ 
/*
	var reg = /[\u3002|\uff1f|\uff01|\uff0c|\u3001|\uff1b|\uff1a|\u201c|\u201d|\u2018|\u2019|\uff08|\uff09|\u300a|\u300b|\u3008|\u3009|\u3010|\u3011|\u300e|\u300f|\u300c|\u300d|\ufe43|\ufe44|\u3014|\u3015|\u2026|\u2014|\uff5e|\ufe4f|\uffe5]/;
	return (reg.test(this)) ? true : false;
*/
	return (/[\u3002|\uff1f|\uff01|\uff0c|\u3001|\uff1b|\uff1a|\u201c|\u201d|\u2018|\u2019|\uff08|\uff09|\u300a|\u300b|\u3008|\u3009|\u3010|\u3011|\u300e|\u300f|\u300c|\u300d|\ufe43|\ufe44|\u3014|\u3015|\u2026|\u2014|\uff5e|\ufe4f|\uffe5]/.test(this)) ? true : false;  
}

//判断是否为英文标点符号
String.prototype.isEnPunctuation = function() 
{ 
/*
	var reg = /[\x21-\x2f\x3a-\x40\x5b-\x60\x7B-\x7F]/;
	return (reg.test(c)) ? true : false;
*/
	return (/[\x21-\x2f\x3a-\x40\x5b-\x60\x7B-\x7F]/.test(this)) ? true : false;  
}

//功能:判断是否为中文或英文标点符号
String.prototype.isPunctuation = function() 
{ 
	//return ((/[\x21-\x2f\x3a-\x40\x5b-\x60\x7B-\x7F]/.test(this)) || (/[\u3002|\uff1f|\uff01|\uff0c|\u3001|\uff1b|\uff1a|\u201c|\u201d|\u2018|\u2019|\uff08|\uff09|\u300a|\u300b|\u3008|\u3009|\u3010|\u3011|\u300e|\u300f|\u300c|\u300d|\ufe43|\ufe44|\u3014|\u3015|\u2026|\u2014|\uff5e|\ufe4f|\uffe5]/.test(this))) ? true : false; 
	return (this.isEnPunctuation() || this.isCnPunctuation()) ? true : false; 

}

//判断是否为纯半角阿拉伯数字串
String.prototype.isArabicNumEn = function() 
{
    return  /^\d+$/.test(this);
}


//判断是否为纯全角阿拉伯数字串
String.prototype.isArabicNumCn = function() 
{
	//[\uff10|\uff11|\uff12|\uff13|\uff14|\uff15|\uff16|\uff17|\uff18|\uff19]=[0|1|2|3|4|5|6|7|8|9]
	return (/^[\uff10|\uff11|\uff12|\uff13|\uff14|\uff15|\uff16|\uff17|\uff18|\uff19]+$/.test(this));
}


//判断是否为纯全角或纯半角阿拉伯数字串
String.prototype.isPureArabicNum = function() 
{
	//[\uff10|\uff11|\uff12|\uff13|\uff14|\uff15|\uff16|\uff17|\uff18|\uff19]=[0|1|2|3|4|5|6|7|8|9]
	return (this.isArabicNumEn() || this.isArabicNumCn());
}


//判断是否为全阿拉伯数字串(全角或半角阿拉伯数字均可)
String.prototype.isArabicNum = function() 
{
	//[\uff10|\uff11|\uff12|\uff13|\uff14|\uff15|\uff16|\uff17|\uff18|\uff19]=[0|1|2|3|4|5|6|7|8|9]
	return (/^[\d|\uff10|\uff11|\uff12|\uff13|\uff14|\uff15|\uff16|\uff17|\uff18|\uff19]+$/.test(this));
}

function getClearInfoArray()
{
	var s = edRichBody.innerHTML.replace(/<br(?:.|\s)*?>/gi,'</p><p>');
	var t = s.split('<p');

	taDbg.value += "\n---getClearInfoArray()\n";
	for (var i=0; i < t.length; i++)
	{
		taDbg.value += "\nt[" + i + "]=" + t[i];
	}    
	
	while (t[0].length==0 || t[0]=='></p>')
	{
		taDbg.value += "\nshift: " + t[0];
		t.shift();
	}

	while (t[t.length-1].length==0 || t[t.length-1]=='></p>')
	{
		taDbg.value += "\npop: " + t[t.length-1];
		t.pop();
	}

	for (var i=0; i < t.length; i++)
	{
		t[i] = stripPattribs(t[i]);
		//t[i] = t[i].replace(/<(?!img|p|\/p|br|a|\/a).*?>/gi, '');
		//t[i] = t[i].replace(/<(?!img|a|\/a).*?>/gi, '');
		t[i] = t[i].stripHTML();

		//以下两句顺序不能颠倒
		t[i] = t[i].replace(/&nbsp;/ig, ''); //去除空格代码	  &nbsp;
		t[i] = t[i].trim(); //去除首尾空格
	}

	while (t[t.length-1].length==0 || t[t.length-1]=='></p>')
	{
		taDbg.value += "\npop: " + t[t.length-1];
		t.pop();
	}

	taDbg.value += "\n---\n";
	for (var i=0; i < t.length; i++)
	{
		taDbg.value += "\nt[" + i + "]=" + t[i];
	} 
	 
	return t;
}


function clearDocFmt()
{
/*
	var s = edRichBody.innerHTML;
	var t = s.split('<p');
	//var i = 0;

	taDbg.value += "\n---clearDocFmt()\n";
	for (var i=0; i < t.length; i++)
	{
		taDbg.value += "\nt[" + i + "]=" + t[i];
	}    
	
	while (t[0].length==0 || t[0]=='></p>')
	{
		taDbg.value += "\nshift: " + t[0];
		t.shift();
	}

	while (t[t.length-1].length==0 || t[t.length-1]=='></p>')
	{
		taDbg.value += "\npop: " + t[t.length-1];
		t.pop();
	}

	for (var i=0; i < t.length; i++)
	{
		t[i] = stripPattribs(t[i]);
		//t[i] = t[i].replace(/<(?!img|p|\/p|br|a|\/a).*?>/gi, '');
		//t[i] = t[i].replace(/<(?!img|a|\/a).*?>/gi, '');
		t[i] = t[i].stripHTML();
		t[i] = t[i].trim(); //去除首尾空格
		t[i] = t[i].replace(/&nbsp;/ig, ''); //去除空格代码	  &nbsp;
	}

	while (t[t.length-1].length==0 || t[t.length-1]=='></p>')
	{
		taDbg.value += "\npop: " + t[t.length-1];
		t.pop();
	}

	taDbg.value += "\n---\n";
	for (var i=0; i < t.length; i++)
	{
		taDbg.value += "\nt[" + i + "]=" + t[i];
	}    
	//t.unshift('<p>');
	s = t.join('</p><p>');
	s = '<p>' + s;
*/
	var s = '<p>' + getClearInfoArray().join('</p><p>');

	//alert(s);
	edRichBody.innerHTML = s;
	//alert(edRichBody.innerHTML);
}                    

//功能:是否以标点符号结束Is aunctuation at the end of the string
String.prototype.isEndWithPunctuation = function()
{
/*
	var c = this.substring(this.length-1);
	return c.isPunctuation();
*/
	return this.substring(this.length-1).isPunctuation();
}


//语句结束符号字符串,考虑到三级标题序号可能包括英语句号,此处不将英语句号列为语句结束符号
var sStatementEndPunctuation = '。!?...!?';


//功能:获取段落文字中的第一个语句结束符号位置
//输入:p:字符串
//输出:第一个语句结束符号位置
function getFirstPunctuationPos(p)
{
	//taDbg.value += '\n ---getFirstPunctuationPos(' + p + ')\n';
	var r = p.length, n;

	for (var i = 0; i < sStatementEndPunctuation.length; i++)
	{
		n = p.indexOf(sStatementEndPunctuation[i]);
		if ( (-1 != n) && (n < r) )
		{
			r = n;
			//taDbg.value += '\n' + sStatementEndPunctuation[i] + ': n=' + n + '    r=' + r;
		}
	}
	return r;
}//getFirstPunctuationPos(p)


//功能:判断字符串是否只有一句话
//输入:p:字符串
//输出:true:是一句话;false:不是一句话
function isAstatement(p)
{
/*
	for  (var i = 0; i < sStatementEndPunctuation.length; i++)
	{

		var n = p.indexOf(sStatementEndPunctuation[i]);
		if  (n !=-1 &&  n == p.length-1) 
		{
			return  true;
		}
	}
	return false;
*/
	var n = getFirstPunctuationPos(p);
	return  ((( -1 != n) &&  (n == p.length-1)) ? true : false);
}

/*
//功能:标题是否单独成行 Is paragraph title a single line?	 
//输入:t:文字
//输出:true:是独立标题行,false:不是独立标题行
function ptIsALine(t)
{
	return isAstatement(t) ;
} //ptIsALine(t)    
*/

//功能:设置一级标题set paragraph format with primay title 
//输入:t:文字
//输出:格式化字符串
function setParaTitle1(t)
{
	var r;
	if (isAstatement(t))	//(ptIsALine(t))	 //标题是否单独成行
	{
		//return '<p style="font-family:' + fn + ';font-size:' + fs +'pt; text-align:' + ta + '; line-height:' +  rs + 'pt;">' + s;
		r = '<p style="margin:0; font-family:' + pt1fn + ';font-size:' + pt1fs +'pt; line-height:' +  rs + 'pt; text-indent: '+ sn +'em;">' + t;
	}
	else
	{
		//标题不单独成行
		var n = getFirstPunctuationPos(t);//t.indexOf('。');
		r = '<p style="margin:0; line-height:' +  rs + 'pt; text-indent: '+ sn +'em; font-family:' + mtfn + '"><span style="font-family:' + pt1fn + ';font-size:' + pt1fs +'pt;" >' + t.substring(0, n) + '</span>' + 	t.substring(n);
	}

	taDbg.value += "\n---setParaTitle1:" + r;
	
	return r;
} //setParaTitle1(t)


//功能:设置二级标题set paragraph format with secondary title 
//输入:t:文字
//输出:格式化字符串
function setParaTitle2(t)
{
	taDbg.value += "\n---setParaTitle2:" + t;
	var r;
	//var b = document.getElementById("cbSecondaryTitleStrong").checked; //是否加粗
	if  (isAstatement(t))//(ptIsALine(t))	 //标题是否单独成行
	{
		//return '<p style="font-family:' + fn + ';font-size:' + fs +'pt; text-align:' + ta + '; line-height:' +  rs + 'pt;">' + s;
		r = '<p style="margin:0; font-family:' + st2fn + ';font-size:' + st2fs +'pt; line-height:' +  rs + 'pt; text-indent: '+ sn +'em;' + (st2Strong ? 'font-weight: bold;' : '') + '">' + t;
	}
	else
	{
		//标题不单独成行
		var n = getFirstPunctuationPos(t);
		r = '<p style="margin:0; line-height:' +  rs + 'pt; text-indent: '+ sn +'em; font-size:' + st2fs +'pt; font-family:' + mtfn + '"><span style="font-family:' + st2fn +  (st2Strong ? ';font-weight: bold;' : '') + '" >' + t.substring(0, n) + '</span>' + 	t.substring(n);
	}

	return r;
}//setParaTitle2(t)

 
//功能:在段落文本末尾添加缺少标点符号的提示文本
//输入:q:待添加提示的文本
//输出:添加提示后的文本
function appendMissPunctuationPrompt(q)
{
	const strMissPunctuation = "*公文一键排版系统温馨提示:此处是否遗漏标点符号";
	var k = q.lastIndexOf(strMissPunctuation); 

/*
	//alert(q);
	if (-1 != k)//是否已包含缺少标点符号的提示文本?
	{
		q = q.substring(0, k);//已包含则舍弃
		//alert(q);
	}
	q += '<span style="color:red; font-weight:bold;">' + strMissPunctuation + '</span>';
*/
	q = (-1 != k ?  q.substring(0, k) : q) +   '<span style="color:red; font-weight:bold;">' + strMissPunctuation + '</span>';
	return q;
	//return (-1 != k ?  q.substring(0, k) : q) +   '<span style="color:red; font-weight:bold;">' + strMissPunctuation + '</span>';
}//appendMissPunctuationPrompt()


//功能:设置三级标题set paragraph format with third title 
//输入:t:文字
//输出:格式化字符串
function setParaTitle3(t)
{
	taDbg.value += "\n---setParaTitle3:" + t;
	var r;
	//var b = document.getElementById("cbThirdTitleString").checked; //是否加粗
	if  (isAstatement(t))//(ptIsALine(t))	 //标题是否单独成行
	{
		//return '<p style="font-family:' + fn + ';font-size:' + fs +'pt; text-align:' + ta + '; line-height:' +  rs + 'pt;">' + s;
		r = '<p style="margin:0; font-family:' + mtfn + ';font-size:' + mtfs +'pt; line-height:' +  rs + 'pt; text-indent: '+ sn +'em;' + (tt3Strong ? 'font-weight: bold;' : '') + '">' + t;
	}
	else
	{
		//标题不单独成行
		var n = getFirstPunctuationPos(t);
		r = '<p style="margin:0; line-height:' +  rs + 'pt; text-indent: '+ sn + 'em; font-size:' + mtfs + 'pt; font-family:' + mtfn + '">' + (tt3Strong ? '<span style="font-weight: bold;">' : '')  + t.substring(0, n) + (tt3Strong ? '</span>' : '') + t.substring(n);
		if ( !r.isEndWithPunctuation())
		{
			r = appendMissPunctuationPrompt(r);
		}
	}//if

	return r;
}//setParaTitle3(t)

 
//是否为只包含一二三四五六七八九十的字符串
String.prototype.isCnNum = function() 
{
	//[\u4e00|\u4e8c|\u4e09|\u56db|\u4e94|\u516d|\u4e03|\u516b|\u4e5d|\u5341] = [一二三四五六七八九十]
	return (/^[\u4e00|\u4e8c|\u4e09|\u56db|\u4e94|\u516d|\u4e03|\u516b|\u4e5d|\u5341]+$/.test(this));
}


//Is the paragraph with primary title?一级标题
function isIncludePrimaryTitle(p)
{
	var t = p.indexOf('、');
	return ((-1 != t) && (p.substring(0,t).isCnNum())) ? true : false;
	//return /^[\u4e00|\u4e8c|\u4e09|\u56db|\u4e94|\u516d|\u4e03|\u516b|\u4e5d|\u5341]+[\u3001]{1}/.test(p); //可匹配" 十一、三四"中的"十一、"
	//return /^\s*[\u4e00|\u4e8c|\u4e09|\u56db|\u4e94|\u516d|\u4e03|\u516b|\u4e5d|\u5341]+[\u3001]{1}/.test(p); //可匹配"   十一、三四"或" 十一、三四"中的"十一、"
	//(\b[\u4e00|\u4e8c|\u4e09|\u56db|\u4e94|\u516d|\u4e03|\u516b|\u4e5d|\u5341])*[\u3001]{1},可匹配"十一、三四"中的顿号
	//\b[\u4e00|\u4e8c|\u4e09|\u56db|\u4e94|\u516d|\u4e03|\u516b|\u4e5d|\u5341]*[\u3001]{1},可匹配"a十一、三四"中的"十一、"
}//isIncludePrimaryTitle(p)


//Is a secondary title serial number with parenthesis是带小括号的二级标题序号吗?
function isT2SNwithParenthesis(p)
{
	var t = p[0];
	if (t == '(')
	{
		t = p.indexOf(')');
		if ((-1 != t) && ((p.substring(1,t)).isCnNum())) 
		{
			return true;
		}
	}//if

	if (t == '(')
	{
		t= p.indexOf(')');
		if ((-1 != t) && (p.substring(1,t).isCnNum())) 
		{
			return true;
		}
	}//if

	return false;//二级标题	
}//isSNwithParenthesis(p)


//Is the paragraph with secondary title?二级标题
function isIncludeSecondaryTitle(p)
{
	var t = p[0];//t = p.substring(0, 1);
	if (-1!= "㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩".indexOf(t))
	{
		return true;
	}

	if (isT2SNwithParenthesis(p))
	{
		return true;//二级标题
	}

	return false;
}//isIncludeSecondaryTitle(p)


//Is the paragraph with third title?三级标题
function isIncludeThirdTitle(p)
{
	var t = p.indexOf('.');
	if (-1==t)
	{
		t = p.indexOf('.');
	}
	return ((-1 != t) && p.substring(0,t).isPureArabicNum()) ? true : false;
}//isIncludeThirdTitle(p)



//功能:获取文字串的标题级别
//输入:p:文字串
//输出:1:一级标题,2:二级标题,3:三级标题,0:其它
function getTitleLevel(p)
{
	taDbg.value += "\n---getTitleLevel:" + p;

	//var t = p[0];//t = p.substring(0, 1);
	if  (isIncludeSecondaryTitle(p))//(t=='(' || t=='(' )
	{
		//alert(t);
		return 2;//二级标题
	}
	
	if (isIncludePrimaryTitle(p))//一级标题
	{
		return 1;
	}

	if (isIncludeThirdTitle(p))//三级标题
	{
		return 3;
	}

	return 0;
}//getTitleLevel(p)


//功能:设置段落格式set paragraph format
//输入:p:段落文字
//输出:设置格式的文本
function setParaFmt(p)
{
	switch (getTitleLevel(p))
	{
		case 1:
			t = setParaTitle1(p);//一级标题
			break;
		case 2:
			t = setParaTitle2(p);//二级标题
			break;
		case 3:
			t = setParaTitle3(p);//三级标题
			break;
		default:	//main text正文
			t = '<p style="margin:0; line-height:' +  rs + 'pt; text-indent: '+ sn +'em;font-family:' + mtfn + '; font-size:'+ mtfs + 'pt;">' + p;
	}//switch

	//taDbg.value += "\n---setParaFmt:" + t;

	return t;
}//setParaFmt(p)


function getArg()
{
	// 排版内容包括公文标题
	cbDocTilte  = document.getElementById('cbDocTilte').checked;
	//标题字体名 document title font name
	dtfn = document.getElementById('selDocTitleFontName').value;
	//alert(fn);
	//标题字号 document title font size
	dtfs = document.getElementById('selDocTitleFontSize').value;
	//alert(fs);
	//标题对齐方式 document title text align
	dtta = document.getElementById('selDocTitleAlign').value;

	//一级标题字号 primary title font name
	pt1fn = document.getElementById('selPrimaryTitleFontName').value;
	//一级标题字号  primary titlefont size
	pt1fs = document.getElementById('selPrimaryTitleFontSize').value;

	//二级标题字号 psecondary title font name
	st2fn = document.getElementById('selSecondaryTitleFontName').value;
	//二级标题字号  secondary title font size
	st2fs = document.getElementById('selSecondaryTitleFontSize').value;
	//二级标题字体加粗  secondary title strong
	st2Strong	 = document.getElementById('cbSecondaryTitleStrong').checked;

	//三级标题字体加粗  third title strong
	tt3Strong = document.getElementById('cbThirdTitleStrong').checked;

	//正文字体名称
	mtfn = document.getElementById('selMainTextFontName').value;
	//正文字体字号
	mtfs = document.getElementById('selMainTextFontSize').value;

	//行距 row spacing
	rs  = document.getElementById('tbRowSp').value;
	//首行行首空格数
	sn  = document.getElementById('tbLeadSpNum').value;
}//	  getArg()


//增:2023-07-16
//判断dddd年dd月dd日是否符合闰年等规则
String.prototype.isRightDateCn = function()
{
  return (/^(?:(?!0000)[0-9]{4}([年]{1})(?:(?:0?[1-9]|1[0-2])\1(?:0?[1-9]|1[0-9]|2[0-8])|(?:0?[13-9]|1[0-2])\1(?:29|30)|(?:0?[13578]|1[02])\1(?:31))|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)([月]{1})0?2\2(?:29))([日]{1})$/.test(this));
}


//增:2023-07-16
//判断是否为dddd年dd月dd日格式
String.prototype.isDateCn = function()
{
	//return (/^(\d{4})([\u5e74]{1})(\d{1,2})([\u6708]{1})\d{1,2}([\u65e5]{1})$/.test(this)); //年=\u5e74,月=\u6708,日=\u65e5
  
	return (/^(\d{4})([年]{1})(\d{1,2})([月]{1})\d{1,2}([日]{1})$/.test(this)); //年=\u5e74,月=\u6708,日=\u65e5
}


//增:2023-07-16
//功能:判断是否为落款
//输入:t1:落款单位,t2:落款日期
//输出:true:是落款;false:非落款
function isBadging(t1,t2)
{
	if (isAstatement(t1))//落款单位末尾是否带符号?
	{
		return false;//带符号,不是落款
	}

	return (t2.isDateCn());
}//isBadging(t1,t2)


//增:2023-07-22
//功能:利用canvas取字符串宽度
//输入:s:字符串,f:字体
//输出:字符串宽度
function getStrWidth(s, f)
{
  //alert(s);
  var canvas = getStrWidth.canvas || (getStrWidth.canvas = document.createElement("canvas"));
  var ctx = canvas.getContext("2d"); 
  ctx.font = f;
  return ctx.measureText(s).width;
}//geStrWidth()
canvas.getContext().measureText().width


//增:2023-07-16,改2023-07-22
//功能:设置落款格式
//输入:t1:落款单位,t2:落款日期
//输出:格式化后的落款单位和落款日期代码
function setBadging(t1,t2)
{
	var r = new Array();
	var f =  mtfs+ 'pt' + ' '+ mtfn;//顺序不能颠倒!
	//noSeal
	var iSize1 = getStrWidth(t1, f);
	var iSize2 = getStrWidth(t2, f);
	//document.write('<p>' + iSize1 + "  "  + iSize2);
	if (iSize2 > iSize1)
	{
		//如成文日期长于发文机关署名,应当使成文日期右空二字编排,并相应增加发文机关署名右空字数。
		r[0] = '<p style="line-height:' + rs + 'pt; font-family:' + mtfn + ';font-size:' + mtfs + 'pt; text-align:right; margin:0 ' + Math.ceil((iSize2 - iSize1)/2 + 48) + 'px 0 0">' + t1;//1em=16px,2em=32px,3em=48px
		r[1] = '<p style="line-height:' + rs + 'pt; font-family:' + mtfn + ';font-size:' + mtfs + 'pt; text-align:right; margin:0 2em 0 0">' + t2;
	}
	else
	{
		//单一机关行文时,在正文(或附件说明)下空一行右空二字编排发文机关署名,在发文机关署名下一行编排成文日期,首字比发文机关署名首字右移二字
		r[0] = '<p style="line-height:' + rs + 'pt; font-family:' + mtfn + ';font-size:' + mtfs + 'pt; text-align:right; margin:0 2em 0 0">' + t1;
		r[1] = '<p style="line-height:' + rs + 'pt; font-family:' + mtfn + ';font-size:' + mtfs + 'pt; text-align:right; margin: 0 ' + (iSize1 - iSize2) + 'px 0 0">' + t2;
	}

	return r.join('');
}//setBadging()


//功能:设置公文格式Set document format
//输入:无
//输出:无
function setDocFmt()
{
	taDbg.value += "\n---setDocFmt()\n";

	getArg();

	var t = getClearInfoArray();

	//标题
	if (cbDocTilte)
	{
		t[0]  = setDocTitle(t[0]) + '</p><p style="margin:0; line-height:"' + rs +'">&nbsp;';
	}
/*
	for (var i = (cbDocTilte ? 1: 0); i < t.length; i++)
	{
		t[i] = setParaFmt(t[i]);
	}
*/

	var i =  (cbDocTilte ? 1 : 0);//增:2023-07-16
	while (i < t.length)
	{
		if (isBadging(t[i],t[i+1]))
		{
			//落款前加空行
			t[i-1] += '</p><p style="margin:0; line-height:"' + rs +'">&nbsp;';
			//设置落款
			t[i] = setBadging(t[i],t[i+1]);
			t[i+1] = null;
			taDbg.value += "\nt[" + (i-1) + "]=" + t[i-1] + "\nt[" + i +"]=" + t[i] + "\nt[" +(i+1) +"]=" + t[i+1];
			//i++;
			//i++;
			i += 2;
		}
		else
		{
			t[i] = setParaFmt(t[i]);
			i++;
		}
	}//while()
	
	alert(t.join(''));
	edRichBody.innerHTML = t.join(''); 
}//setDocFmt() 

</script>

</head>

<body>
<fieldset  style="width: 1100px;">
 <legend>实时编辑区</legend>
<iframe id="editor" width="1200px" height="400px" style="border: solid 1px;"></iframe>
</fieldset>
<p>
	<input type="button" id="btnclearDocFmt" value="清除格式" onclick="clearDocFmt()" />
	<input type="button" id="btnsetDocFmt" value="一键排版" onclick="setDocFmt()" />
	<input type="button" id="btnShowSrc" value="显示源码" onclick="showSrc()" style="background:yellow; border-radius: 25px;" />
	<input type="button" id="btnB" value="B" title="加粗/正常"  style="font-weight:bolder" onclick="execCmd('bold',false,null)" />
	<input type="button" id="btnItalic" value="I" title="斜体/正常"  style="font-weight:bolder;font-style:italic" onclick="execCmd('italic',false,null)" />
	<input type="button" id="btnUnderline" value="I" title="下划线"  style="font-weight:bolder;text-decoration:underline" onclick="execCmd('underline',false,null)" />
</p>
<fieldset style="width: 1200px;">
  <legend>参数设置</legend>
	公文标题:<input type="checkbox" checked id="cbDocTilte">排版内容包括公文标题
	<script>
		showFontNameSel("selDocTitleFontName", 0);
		document.write(' ');
		showFontSizeSel("selDocTitleFontSize", 4);
		document.write(' ');
		showAlignSel("selDocTitleAlign", 1);
	</script>

	<p>正文一级标题:
	<script>
		showFontNameSel("selPrimaryTitleFontName", 1);
		document.write(' ');
		showFontSizeSel("selPrimaryTitleFontSize", 6);
	</script>
	</p>

 	<p>正文二级标题:
	<script>
		showFontNameSel("selSecondaryTitleFontName", 5);
		document.write(' ');
		showFontSizeSel("selSecondaryTitleFontSize", 6);
	</script>
		<input type="checkbox" checked id="cbSecondaryTitleStrong">粗体
	</p>

 	<p>正文三级标题:
		<input type="checkbox" checked id="cbThirdTitleStrong">粗体
	</p>

 	<p>正文:	
		<script>
			showFontNameSel("selMainTextFontName", 3);
			document.write(' ');
			showFontSizeSel("selMainTextFontSize", 6);
			document.write(' ');
		</script>
		行距(行间距):<input type="text" id="tbRowSp" value="28" size="2"><!--  row spacing//-->  段落首行行首空格数:<input type="text" id="tbLeadSpNum" value="2" size="2">
	</P>
 </fieldset>

<p>调试信息</p>
<textarea id="taDbg" style="width: 1225px; height: 200px">调试信息</textarea>

<script type="text/javascript">

const edRich = document.getElementById("editor");
const taDbg = document.getElementById("taDbg");
const btnShowSrc = document.getElementById("btnShowSrc");

//排版内容是否包括公文标题
var cbDocTilte;		//  = document.getElementById('cbDocTilte').value;
//标题字体名 document title font name
var dtfn;	// = document.getElementById('selDocTitleFontName').value;
//标题字号 document title font size
var dtfs;	// = document.getElementById('selDocTitleFontSize').value;
//标题对齐方式 document title text align
var dtta;// = document.getElementById('selDocTitleAlign').value;

//一级标题字号 font name
var pt1fn;	// = document.getElementById('selPrimaryTitleFontName').value;
//一级标题字号 font size
var pt1fs;	// = document.getElementById('selPrimaryTitleFontSize').value;

//二级标题字号 psecondary title font name
var st2fn;	// = document.getElementById('selSecondaryTitleFontName').value;
//二级标题字号  secondary title font size
var st2fs;	// = document.getElementById('selSecondaryTitleFontSize').value;
//二级标题字体加粗  secondary title strong
var st2Strong;	// = document.getElementById('cbSecondaryTitleStrong').value;

//三级标题字体加粗  third title strong
var tt3Strong;	//	 = document.getElementById('cbThirdTitleStrong').value;

//行距 row spacing
 var rs;		//  = document.getElementById('tbRowSp').value;
//首行行首空格数
 var sn;		//  = document.getElementById('tbLeadSpNum').value;

//正文字体名称
var mtfn;	// = document.getElementById('selMainTextFontName').value;
	//正文字体字号
var mtfs;	// = document.getElementById('selMainTextFontSize').value;       
var edRichDoc;
var edRichBody;
//var edRichHTML;
if (typeof(edRich) !="undefined")
 {
	edRichDoc = edRich.contentWindow.document;
	edRichDoc.designMode = "on";
	edRichDoc.contentEditable = true;
	edRichBody = 	edRichDoc.body;
	edRichBody.innerHTML = '<p><a href="http://blog.csdn.net/purpleendurer">http://blog.csdn.net/purpleendurer</a></p><p></p><p style="font-family:方正小标宋简体;font-size:22pt; text-align:center; line-height:28pt;"><p align="center" style="text-align:center;text-indent:24.0pt;line-height:28.0pt"><span lang="EN-US" style="font-size:22.0pt;font-family:方正小标宋简体;mso-hansi-font-family:黑体;color:black">SQL</span><span style="font-size:22.0pt;font-family:方正小标宋简体;mso-hansi-font-family:黑体;color:black">注入基础<span lang="EN-US"><o:p></o:p></span></span></p><p style="text-indent:24.0pt;line-height:28.0pt;font-variant-ligatures: normal;font-variant-caps: normal;orphans: 2;text-align:start;widows: 2;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;word-spacing:0px"><span style="font-size:16.0pt;font-family:黑体;color:black">一、<span lang="EN-US">SQL</span>注入分类<span lang="EN-US"><o:p></o:p></span></span></p><p style="text-indent:24.0pt;line-height:28.0pt;font-variant-ligatures: normal;font-variant-caps: normal;orphans: 2;text-align:start;widows: 2;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;word-spacing:0px"><b><span style="font-size:16.0pt;font-family:楷体_GB2312;color:black">(一)什么是<span lang="EN-US">SQL</span>注入<span lang="EN-US">?<o:p></o:p></span></span></b></p><p style="text-indent:24.0pt;line-height:28.0pt;font-variant-ligatures: normal;font-variant-caps: normal;orphans: 2;text-align:start;widows: 2;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;word-spacing:0px"><span lang="EN-US" style="font-size:16.0pt;font-family:仿宋_GB2312;color:black">SLQ</span><span style="font-size:16.0pt;font-family:仿宋_GB2312;color:black">注入<span lang="EN-US">(</span>英文<span lang="EN-US">: Sqlinject)</span>:当<span lang="EN-US">web</span>应用向后台数据库传递<span lang="EN-US">SQL</span>语句进行数据库操作时,如果对用户输入的参数没有经过严格的过滤,那么用户可以构造特殊的<span lang="EN-US">sq1</span>语句,从而带入到数据库中执行,获取或修改数据库中的数据。<span lang="EN-US"><o:p></o:p></span></span></p><p>测试1</p><p style="text-indent:24.0pt;line-height:28.0pt;font-variant-ligatures: normal;font-variant-caps: normal;orphans: 2;text-align:start;widows: 2;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;word-spacing:0px">河池市××××局</p><p>2023年7月22日</p><p>测试2</p><p>广西壮族自治区河池市××××局</p><p>2023年7月22日</p><p>测试3</p><p>河池市××局</p><p>2023年7月22日</p><p>测试4</p><p>河池市×局</p><p>2023年7月22日</p>'
}
else
{
	window.alert("undefined");
}

function replaceStr(s1,s2)
{
	try
	{
		var r = document.body.createTextRange();
		if (r.findText(s1))
		{
			r.expand('charactor');
			r.select();
			r.text = s2;
			r.scrollIntoView();
		}
		else
		{
			alert('"'+s+'" not found!');
		}
	}
	catch (e)
	{
		alert(e.description);
	}
}


function showSrc()
{
	if (btnShowSrc.value=="显示源码")
	{
		edRichBody.innerText = edRichBody.innerHTML;
		//edRichBody.innerText = edRichBody.innerHTML.replace('</p>','</p>'+chr(10));	  
		//edRichBody.innerText = edRichBody.innerText.replace('<\/p>','<\/p>'+chr(10)+chr(13));	  

		btnShowSrc.value = "显示预览";
		btnShowSrc.style.background = "cyan";
	}
	else
	{
		edRichBody.innerHTML = edRichBody.innerText;
		//edRichBody.innerHTML = edRichBody.innerText.replace(chr(10)+chr(13),'');
		btnShowSrc.value = "显示源码";
		btnShowSrc.style.background = "yellow";
	}
}


function execCmd(cmd,f,v)
{
	edRichDoc.execCommand(cmd,f,v);
}
</script>
</body>
</html>
相关推荐
小吕学编程13 分钟前
ES练习册
java·前端·elasticsearch
Asthenia041220 分钟前
Netty编解码器详解与实战
前端
袁煦丞25 分钟前
每天省2小时!这个网盘神器让我告别云存储混乱(附内网穿透神操作)
前端·程序员·远程工作
一个专注写代码的程序媛1 小时前
vue组件间通信
前端·javascript·vue.js
一笑code2 小时前
美团社招一面
前端·javascript·vue.js
懒懒是个程序员2 小时前
layui时间范围
前端·javascript·layui
NoneCoder2 小时前
HTML响应式网页设计与跨平台适配
前端·html
凯哥19702 小时前
在 Uni-app 做的后台中使用 Howler.js 实现强大的音频播放功能
前端
烛阴2 小时前
面试必考!一招教你区分JavaScript静态函数和普通函数,快收藏!
前端·javascript
GetcharZp2 小时前
xterm.js 终端神器到底有多强?用了才知道!
前端·后端·go