!!! CSS规范中可能不包括任何意义上的变量,这里只是一个直观的说法。
今天写了一个jscript脚本,它扫瞄一个文本文件,遇到 $name=value 就记录一个变量定义,遇到右边没有等号的 $name 就替换成先前定义的值或包含警告内容的注释(/*WARNING: undefined ...*/)文本。
写这个脚本的主要动机是在CSS中使用变量(实际是具有C/C++宏效果的常量)。我可以在CSS文件的前部的注释中定义颜色变量,然后在后面引用它,写好后,用这个脚本把包含了这种变量的CSS文件转换成符合CSS规范的文件。
次要动机是这几天对脚本程序手痒,写程序的愿望临时超过了打游戏的。这个程序主要使用了正则表达式来完成任务,以前用C#写一个代码高亮程序时,大量使用了正则表达式,这回虽然在内容上没有超越,不过毕竟是在新环境中使用,边查手册边写,有些东西暂时还不透彻,所以显得很有技巧性。比如在string.replace()方法中,替换文本中可以包含捕获的表达式,但是如果要把这个表达式直接用作字典对象的关键字,貌似不行。不过它可以用作函数的参数,于是我在代码中就地创建了一个函数来访问字典对象。而作为函数参数的话,捕获表达式的索引也有变化。
这个脚本的用法是这样的,比如我把它保存为CSS-preprocessor.js,在一个名为current.src.css的文件中写如下CSS代码:
/*current.src.css
...
DEFINE COLORS
-------------
$pageForeColor=#FFF
$pageBgColor=#CCC
$pageHeadBgColor=#214552
$pageHeadForeColor=#FFF
$pageHeadForeColor_a=#FFF
$pageHeadDescColor=#FFF
$pageFooterBgColor=#FFF
$boxBgColor=#FFF
$contentForeColor=#FFF
$contentBgColor=#214552
$moduleBgColor=#CFDFBF
$moduleForeColor=#564b47
$unimportantColor=#999 // minor description text
$headlineColor=#FF9900 // h1,h2,h3...
$textBlockBorderColor=#FFF // pre, quote, etc.
$textBlockBgColor=#315562;
$postbodyForeColor=#FFF
$postbodyForeColor_a=#8FDFFF
$postDateColor=#446677
$postTitleColor=#FF9900
$postTitleColor_a=#FF9900
$postHeadlineColor=#FF9900
$postFooterBgColor=#8FDFFF
$moduleHeadColor=#FF9900
$moduleBorderColor=#226699
$moduleText_a=#226699
$commentsBorderColor=#999
$commentsTextColor=#FFF
$commentsBgColor=#315562
*/
body {
font-size: small;
font-family: Verdana, Tahoma, Arial, Helvetica, sans-serif;
text-align:center;
margin:0px;
padding:0 0 20px 0;
color: $pageForeColor;
background-color: $pageBgColor;
}
...
写好这个CSS后,在windows命令行中执行cscript CSS-preprocessor.js current.src.css current.css,屏幕上显示:
#13 $pageForeColor = #FFF
#14 $pageBgColor = #CCC
#16 $pageHeadBgColor = #214552
#17 $pageHeadForeColor = #FFF
#18 $pageHeadForeColor_a = #FFF
#19 $pageHeadDescColor = #FFF
#21 $pageFooterBgColor = #FFF
#23 $boxBgColor = #FFF
#24 $contentForeColor = #FFF
#25 $contentBgColor = #214552
#27 $moduleBgColor = #CFDFBF
#28 $moduleForeColor = #564b47
#30 $unimportantColor = #999
#31 $headlineColor = #FF9900
#33 $textBlockBorderColor = #FFF
#34 $textBlockBgColor = #315562
#36 $postbodyForeColor = #FFF
#37 $postbodyForeColor_a = #8FDFFF
#38 $postDateColor = #446677
#39 $postTitleColor = #FF9900
#40 $postTitleColor_a = #FF9900
#41 $postHeadlineColor = #FF9900
#42 $postFooterBgColor = #8FDFFF
#44 $moduleHeadColor = #FF9900
#45 $moduleBorderColor = #226699
#46 $moduleText_a = #226699
#48 $commentsBorderColor = #999
#49 $commentsTextColor = #FFF
#50 $commentsBgColor = #315562
#61 $pageForeColor -> #FFF
#62 $pageBgColor -> #CCC
#67 $headlineColor -> #FF9900
#89 $textBlockBorderColor -> #FFF
#90 $textBlockBgColor -> #315562
#106 $boxBgColor -> #FFF
#128 $contentForeColor -> #FFF
#129 $contentBgColor -> #214552
#136 $moduleBgColor -> #CFDFBF
#141 $pageHeadBgColor -> #214552
#148 $pageFooterBgColor -> #FFF
每行的开头是行号,余下内容表示脚本在CSS源文件中的这一行找到了一个变量的定义或引用,分别用 = 和 -> 标识。
同时,转换后的CSS被输出到current.css文件中。
以下是jscript脚本的完整内容:
/*
CSS-preprocessor.js
CSS user defined variables preprocessor 1.0 - replace variables reference with their values.
the "variable" here is something defined in css remark by the following:
$<name>=<value>
and referenced like this, e.g.:
color: $pageForeColor;
seems like php variable, but essentially it's C/C++ macro.
how to use:
(1)define and use variables in css "source" file;
(2)process the css source file with this jscript, e.g.:
C:\>cscript this.js current.src.css current.css;
in css source file, anything with the form of "$name=value" is considered as a variable definition. note that any number of blank(including tab and newline) on both side of "=" is allowed, and, to define multiple variables in a single line is possible.
anything not variable definition with the form of "$name" is considered as a variable reference, and will be replaced with it's value defined before. a undefined variable reference will be replaced with a warning remark.
--
pzy 2008-12-6
*/
// user defined variables in CSS files
var varlst = new ActiveXObject("Scripting.Dictionary");
if (WScript.Arguments.Length < 2)
{
WScript.Echo("arg0: source css file;");
WScript.Echo("arg1: dest css file;");
}
else
{
ProcessCSSVariable(WScript.Arguments(0), WScript.Arguments(1));
}
function ProcessCSSVariable(input, output)
{
var fso, ts, fout, s;
var ForReading = 1;
fso = new ActiveXObject("Scripting.FileSystemObject");
ts = fso.OpenTextFile(input, ForReading);
fout = fso.CreateTextFile(output, true);
WScript.Echo(input + " => " + output);
while (!ts.AtEndOfStream)
{
s = ts.ReadLine();
var vardef = s.match(/\$[_\-0-9a-zA-Z]+[ \t\n]?=[ \t\n]?[#0-9a-fA-F]+/g);
if (vardef)
{
for (var i = 0; i < vardef.length; ++i)
{
var sep = vardef[i].indexOf("=");
var name = vardef[i].substr(0, sep);
var value = vardef[i].substr(sep + 1);
WScript.Echo("#" + (ts.line - 1) + "\t" + name + " = " + value);
varlst.add(name, value);
}
// output as-is
fout.WriteLine(s);
}
else
{
// output replaced line
fout.WriteLine(s.replace(/(\$[_\-0-9a-zA-Z]+)/g,
//varlst("$1")
function($0)
{
var value = varlst.Exists($0) ? varlst($0) : "/*WARNING: undefined: " + $0 + "*/";
WScript.Echo("#" + (ts.line - 1) + "\t" + $0 + " -> " + value);
return value;
}
));
}
}
}