整体流程
终于说到整体流程上了。之前的文章一直在解说as中如何来做词法分析,js方面丝毫未提,更没说jssc到底在页面上是怎么工作的。现在,就来详细地解释一下。
环境需求:
- 现代浏览器(废话)
- 装有Adobe Flash Player插件,版本号为9或9以上
- javascript启用
- 页面中放入jssc.swf文件
大致流程:
- swf文件载入完毕
- 内嵌在swf中的js首先被执行,寻找页面中所有符合规则的pre节点
- 顺序遍历这些pre节点,提取每个pre节点的文本内容(即原始代码)
- 将原始代码传递给swf
- swf对传递来的原始代码进行词法分析,并生成一段结果html片段(即一串li节点)
- 将结果传递回js
- js对结果进行包装(一串li节点放入ol节点中,以及标题头、边距和复制等等)
- 将对应的原始pre节点隐藏(display:none)
- 将新生成的内容插入原始pre节点的前面
可以看出,js和as耦合的地方在哪里,以及它们之间是如何相互合作的。下面将对以上9个步骤细细说来,希望更多的开发者能提出改进意见~
1.载入swf
这里没什么好说的,在页面底部加入flash标签即可。值得注意的是不同浏览器中标签有所区别,理想情况下可以使用swfobject来插入标准的html标签。不过为了兼容以及简单,一般我是这样做的:
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" id="jssc5" style="position:absolute;visibility:hidden;"> <param name="movie" value="jssc5.swf"/> <param name="flashvars" value="find=brush"/> <embed src="jssc5.swf" flashvars="find=brush" name="jssc5" type="application/x-shockwave-flash" style="position:absolute;visibility:hidden;"/> </object>
这里面有许多可配置的地方。
object的id和embed的name必须一致且唯一(应该是唯二才对),为了满足不同浏览器的需要。我设为jssc5,这也是默认值。如果和页面上某个节点有冲突需要修改,那么就需要传入参数修改配置。比如说变成jssc5_modify,就得在flashvars中这样做:
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" id="jssc5_modify" style="position:absolute;visibility:hidden;"> <param name="movie" value="jssc5.swf"/> <param name="flashvars" value="find=brush&swf=jssc5_modify"/> <embed src="jssc5.swf" flashvars="find=brush&swf=jssc5_modify" name="jssc5_modify" type="application/x-shockwave-flash" style="position:absolute;visibility:hidden;"/> </object>
注意到param标签和embed标签中都得改,为了满足浏览器兼容需要……
同样,jssc会占用一个全局js变量名jssc(注意这个jssc是指变量名字符串,而前者是指软件),这是为了在js和as之间互相调用通信必须的。如果这个变量名和页面上的js变量有冲突,那么就会造成错误。所以它也可以进行修改配置,假如要改成jssc_js,就得在flashvars中这么做:
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" id="jssc5_modify" style="position:absolute;visibility:hidden;"> <param name="movie" value="jssc5.swf"/> <param name="flashvars" value="find=brush&swf=jssc5_modify&js=jssc_js"/> <embed src="jssc5.swf" flashvars="find=brush&swf=jssc5_modify&js=jssc_js" name="jssc5_modify" type="application/x-shockwave-flash" style="position:absolute;visibility:hidden;"/> </object>
最后,还有两个可以配置的参数:css和url。前者是指新生成的结果节点的class名称,你可以用firebug看到默认的亦是jssc;后者是指定swf的路径,这是为了在非ie浏览器下做copy使用(ie可以直接调用api做复制功能),从这个意义上说,整个swf文件其实是有两种功能——词法分析和复制按钮。这么做是为了减少http请求,同时js融合在as里也是为了减少http请求。
2.内嵌的js执行
js首先会寻找页面上所有符合规则的pre节点,那么是什么规则的?默认情况下,pre的class名称如果这样开头,js就会认为它是正确的(其实并不一定要求是开头,出现在其它位置也可以,但为了良好的习惯推荐如此):
<pre class="brush:html"></pre>
这段被高亮的代码其实就是它本身。brush是键名,html是键值。假如想要高亮一段js代码,那么就需要更改键值:
<pre class="brush:js"></pre>
其它语言道理相同。另外,可以高亮的代码必须是jssc本身已经支持的语法种类,不支持的话也会被格式化,但没有高亮效果。
细心的人可能已经发现,brush键名和最开始那段代码中出现的相一致。没错,假如pre节点的class名称也有冲突,不能使用brush,要改成brush_modify,那么就要如此修改配置:
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" id="jssc5_modify" style="position:absolute;visibility:hidden;"> <param name="movie" value="jssc5.swf"/> <param name="flashvars" value="find=brush_modify&swf=jssc5_modify&js=jssc_js"/> <embed src="jssc5.swf" flashvars="find=brush_modify&swf=jssc5_modify&js=jssc_js" name="jssc5_modify" type="application/x-shockwave-flash" style="position:absolute;visibility:hidden;"/> </object>
注意param和embed中要修改2次。
在找到所有符合规则的pre节点之后,js将这些节点的引用存储下来,然后一一遍历它们。下面的经过就是每次遍历一个pre节点时所发生的。
3.遍历提取内容
提取pre节点的内容很简单,即我们熟知的innerText。不过在不同浏览器中也有让人头疼的地方。以前在做jssc4的时候,firefox2版本的innerText容量有限制,如果代码过多,提取的内容就不完整。另外也有低版本浏览器不支持innerText的可能性发生。所以综合考虑我写了个如下的js方法:
function getText(node) {
var code = node.textContent || node.innerText;
if(!code && node.firstChild) {
code = node.firstChild.nodeValue;
}
return code || "";
}
4.传递内容给as
这是as定义好的接口,js和as可以通过ExternalInterface类来实现互调。不再多说。
5.as做词法分析
这是前几篇一直在说的内容,不再多说。
6.传递结果给js
同第4点。
7.js包装结果
生成的结果其实是一串li节点,js要做的就是创建一个ol节点,然后设置innerHTML为传递来的结果字符串。如此最基本的高亮代码就完成了。之后是设置标题、起始行数、边距、复制功能和鼠标移入高亮当前行背景。
其中边距是指ol节点的paddingLeft值,因为代码行数不一样,所以左边距一定是根据行数动态进行计算的。在js中我的公式如下:
oOl.style.paddingLeft = Math.max((line.length + 2) * 9, 30) + "px";
8.隐藏pre节点
最后是将本次循环的这个pre节点隐藏。注意,这里是隐藏不是删除!因为后面还要用到代码复制功能,所以只能隐藏不能删除!
9.插入结果
将包装好的结果插入本次循环pre节点的前面,这轮循环就算走完了,再继续下一轮循环。
结束语
好了,整个系列文章算结束了。欢迎大家提出好的建议和想法,或者直接参与到开发当中来,亦或以别的方式来参与(比如说做wordpress的插件)。如果你能做出比jssc更好的高亮插件,那么我也会放弃jssc,投入新的、更好的项目中去的——这话说的好假:)



本博客所有文章均采用