1+ /*
2+ Rev 146 from:
3+ http://svn.danwebb.net/external/CodeHighlighter/trunk/
4+ */
5+
6+ /* Unobtrustive Code Highlighter By Dan Webb 11/2005
7+ Version: 0.4
8+
9+ Usage:
10+ Add a script tag for this script and any stylesets you need to use
11+ to the page in question, add correct class names to CODE elements,
12+ define CSS styles for elements. That's it!
13+
14+ Known to work on:
15+ IE 5.5+ PC
16+ Firefox/Mozilla PC/Mac
17+ Opera 7.23 + PC
18+ Safari 2
19+
20+ Known to degrade gracefully on:
21+ IE5.0 PC
22+
23+ Note: IE5.0 fails due to the use of lookahead in some stylesets. To avoid script errors
24+ in older browsers use expressions that use lookahead in string format when defining stylesets.
25+
26+ This script is inspired by star-light by entirely cunning Dean Edwards
27+ http://dean.edwards.name/star-light/.
28+ */
29+
30+ // replace callback support for safari.
31+ if ( "a" . replace ( / a / , function ( ) { return "b" } ) != "b" ) ( function ( ) {
32+ var default_replace = String . prototype . replace ;
33+ String . prototype . replace = function ( search , replace ) {
34+ // replace is not function
35+ if ( typeof replace != "function" ) {
36+ return default_replace . apply ( this , arguments )
37+ }
38+ var str = "" + this ;
39+ var callback = replace ;
40+ // search string is not RegExp
41+ if ( ! ( search instanceof RegExp ) ) {
42+ var idx = str . indexOf ( search ) ;
43+ return (
44+ idx == - 1 ? str :
45+ default_replace . apply ( str , [ search , callback ( search , idx , str ) ] )
46+ )
47+ }
48+ var reg = search ;
49+ var result = [ ] ;
50+ var lastidx = reg . lastIndex ;
51+ var re ;
52+ while ( ( re = reg . exec ( str ) ) != null ) {
53+ var idx = re . index ;
54+ var args = re . concat ( idx , str ) ;
55+ result . push (
56+ str . slice ( lastidx , idx ) ,
57+ callback . apply ( null , args ) . toString ( )
58+ ) ;
59+ if ( ! reg . global ) {
60+ lastidx += RegExp . lastMatch . length ;
61+ break
62+ } else {
63+ lastidx = reg . lastIndex ;
64+ }
65+ }
66+ result . push ( str . slice ( lastidx ) ) ;
67+ return result . join ( "" )
68+ }
69+ } ) ( ) ;
70+
71+ var CodeHighlighter = { styleSets : new Array } ;
72+
73+ CodeHighlighter . addStyle = function ( name , rules ) {
74+ // using push test to disallow older browsers from adding styleSets
75+ if ( [ ] . push ) this . styleSets . push ( {
76+ name : name ,
77+ rules : rules ,
78+ ignoreCase : arguments [ 2 ] || false
79+ } )
80+
81+ function setEvent ( ) {
82+ // set highlighter to run on load (use LowPro if present)
83+ if ( typeof Event != 'undefined' && typeof Event . onReady == 'function' )
84+ return Event . onReady ( CodeHighlighter . init . bind ( CodeHighlighter ) ) ;
85+
86+ var old = window . onload ;
87+
88+ if ( typeof window . onload != 'function' ) {
89+ window . onload = function ( ) { CodeHighlighter . init ( ) } ;
90+ } else {
91+ window . onload = function ( ) {
92+ old ( ) ;
93+ CodeHighlighter . init ( ) ;
94+ }
95+ }
96+ }
97+
98+ // only set the event when the first style is added
99+ if ( this . styleSets . length == 1 ) setEvent ( ) ;
100+ }
101+
102+ CodeHighlighter . init = function ( ) {
103+ if ( ! document . getElementsByTagName ) return ;
104+ if ( "a" . replace ( / a / , function ( ) { return "b" } ) != "b" ) return ; // throw out Safari versions that don't support replace function
105+ // throw out older browsers
106+
107+ var codeEls = document . getElementsByTagName ( "CODE" ) ;
108+ // collect array of all pre elements
109+ codeEls . filter = function ( f ) {
110+ var a = new Array ;
111+ for ( var i = 0 ; i < this . length ; i ++ ) if ( f ( this [ i ] ) ) a [ a . length ] = this [ i ] ;
112+ return a ;
113+ }
114+
115+ var rules = new Array ;
116+ rules . toString = function ( ) {
117+ // joins regexes into one big parallel regex
118+ var exps = new Array ;
119+ for ( var i = 0 ; i < this . length ; i ++ ) exps . push ( this [ i ] . exp ) ;
120+ return exps . join ( "|" ) ;
121+ }
122+
123+ function addRule ( className , rule ) {
124+ // add a replace rule
125+ var exp = ( typeof rule . exp != "string" ) ?String ( rule . exp ) . substr ( 1 , String ( rule . exp ) . length - 2 ) :rule . exp ;
126+ // converts regex rules to strings and chops of the slashes
127+ rules . push ( {
128+ className : className ,
129+ exp : "(" + exp + ")" ,
130+ length : ( exp . match ( / ( ^ | [ ^ \\ ] ) \( [ ^ ? ] / g) || "" ) . length + 1 , // number of subexps in rule
131+ replacement : rule . replacement || null
132+ } ) ;
133+ }
134+
135+ function parse ( text , ignoreCase ) {
136+ // main text parsing and replacement
137+ return text . replace ( new RegExp ( rules , ( ignoreCase ) ?"gi" :"g" ) , function ( ) {
138+ var i = 0 , j = 1 , rule ;
139+ while ( rule = rules [ i ++ ] ) {
140+ if ( arguments [ j ] ) {
141+ // if no custom replacement defined do the simple replacement
142+ if ( ! rule . replacement ) return "<span class=\"" + rule . className + "\">" + arguments [ 0 ] + "</span>" ;
143+ else {
144+ // replace $0 with the className then do normal replaces
145+ var str = rule . replacement . replace ( "$0" , rule . className ) ;
146+ for ( var k = 1 ; k <= rule . length - 1 ; k ++ ) str = str . replace ( "$" + k , arguments [ j + k ] ) ;
147+ return str ;
148+ }
149+ } else j += rule . length ;
150+ }
151+ } ) ;
152+ }
153+
154+ function highlightCode ( styleSet ) {
155+ // clear rules array
156+ var parsed , clsRx = new RegExp ( "(\\s|^)" + styleSet . name + "(\\s|$)" ) ;
157+ rules . length = 0 ;
158+
159+ // get stylable elements by filtering out all code elements without the correct className
160+ var stylableEls = codeEls . filter ( function ( item ) { return clsRx . test ( item . className ) } ) ;
161+
162+ // add style rules to parser
163+ for ( var className in styleSet . rules ) addRule ( className , styleSet . rules [ className ] ) ;
164+
165+
166+ // replace for all elements
167+ for ( var i = 0 ; i < stylableEls . length ; i ++ ) {
168+ // EVIL hack to fix IE whitespace badness if it's inside a <pre>
169+ if ( / M S I E / . test ( navigator . appVersion ) && stylableEls [ i ] . parentNode . nodeName == 'PRE' ) {
170+ stylableEls [ i ] = stylableEls [ i ] . parentNode ;
171+
172+ parsed = stylableEls [ i ] . innerHTML . replace ( / ( < c o d e [ ^ > ] * > ) ( [ ^ < ] * ) < \/ c o d e > / i, function ( ) {
173+ return arguments [ 1 ] + parse ( arguments [ 2 ] , styleSet . ignoreCase ) + "</code>"
174+ } ) ;
175+ parsed = parsed . replace ( / \n ( * ) / g, function ( ) {
176+ var spaces = "" ;
177+ for ( var i = 0 ; i < arguments [ 1 ] . length ; i ++ ) spaces += " " ;
178+ return "\n" + spaces ;
179+ } ) ;
180+ parsed = parsed . replace ( / \t / g, " " ) ;
181+ parsed = parsed . replace ( / \n ( < \/ \w + > ) ? / g, "<br />$1" ) . replace ( / < b r \/ > [ \n \r \s ] * < b r \/ > / g, "<p><br></p>" ) ;
182+
183+ } else parsed = parse ( stylableEls [ i ] . innerHTML , styleSet . ignoreCase ) ;
184+
185+ stylableEls [ i ] . innerHTML = parsed ;
186+ }
187+ }
188+
189+ // run highlighter on all stylesets
190+ for ( var i = 0 ; i < this . styleSets . length ; i ++ ) {
191+ highlightCode ( this . styleSets [ i ] ) ;
192+ }
193+ }
194+
195+
196+
197+ CodeHighlighter . addStyle ( "css" , {
198+ comment : {
199+ exp : / \/ \* [ ^ * ] * \* + ( [ ^ \/ ] [ ^ * ] * \* + ) * \/ /
200+ } ,
201+ keywords : {
202+ exp : / @ \w [ \w \s ] * /
203+ } ,
204+ selectors : {
205+ exp : "([\\w-:\\[.#][^{};>]*)(?={)"
206+ } ,
207+ properties : {
208+ exp : "([\\w-]+)(?=\\s*:)"
209+ } ,
210+ units : {
211+ exp : / ( [ 0 - 9 ] ) ( e m | e n | p x | % | p t ) \b / ,
212+ replacement : "$1<span class=\"$0\">$2</span>"
213+ } ,
214+ urls : {
215+ exp : / u r l \( [ ^ \) ] * \) /
216+ }
217+ } ) ;
218+
219+ CodeHighlighter . addStyle ( "ruby" , {
220+ comment : {
221+ exp : / # [ ^ \n ] + /
222+ } ,
223+ brackets : {
224+ exp : / \( | \) /
225+ } ,
226+ string : {
227+ exp : / ' [ ^ ' ] * ' | " [ ^ " ] * " /
228+ } ,
229+ keywords : {
230+ exp : / \b ( d o | e n d | s e l f | c l a s s | d e f | i f | m o d u l e | y i e l d | t h e n | e l s e | f o r | u n t i l | u n l e s s | w h i l e | e l s i f | c a s e | w h e n | b r e a k | r e t r y | r e d o | r e s c u e | r e q u i r e | r a i s e ) \b /
231+ } ,
232+ /* Added by Shelly Fisher ([email protected] ) */ 233+ symbol : {
234+ exp : / ( [ ^ : ] ) ( : [ A - Z a - z 0 - 9 _ ! ? ] + ) /
235+ }
236+ } ) ;
237+
238+ CodeHighlighter . addStyle ( "javascript" , {
239+ comment : {
240+ exp : / ( \/ \/ [ ^ \n ] * \n ) | ( \/ \* [ ^ * ] * \* + ( [ ^ \/ ] [ ^ * ] * \* + ) * \/ ) /
241+ } ,
242+ brackets : {
243+ exp : / \( | \) /
244+ } ,
245+ string : {
246+ exp : / ' [ ^ ' ] * ' | " [ ^ " ] * " /
247+ } ,
248+ keywords : {
249+ exp : / \b ( a r g u m e n t s | b r e a k | c a s e | c o n t i n u e | d e f a u l t | d e l e t e | d o | e l s e | f a l s e | f o r | f u n c t i o n | i f | i n | i n s t a n c e o f | n e w | n u l l | r e t u r n | s w i t c h | t h i s | t r u e | t y p e o f | v a r | v o i d | w h i l e | w i t h ) \b /
250+ } ,
251+ global : {
252+ exp : / \b ( t o S t r i n g | v a l u e O f | w i n d o w | e l e m e n t | p r o t o t y p e | c o n s t r u c t o r | d o c u m e n t | e s c a p e | u n e s c a p e | p a r s e I n t | p a r s e F l o a t | s e t T i m e o u t | c l e a r T i m e o u t | s e t I n t e r v a l | c l e a r I n t e r v a l | N a N | i s N a N | I n f i n i t y ) \b /
253+ }
254+ } ) ;
255+
256+ CodeHighlighter . addStyle ( "html" , {
257+ comment : {
258+ exp : / & l t ; ! \s * ( - - ( [ ^ - ] | [ \r \n ] | - [ ^ - ] ) * - - \s * ) & g t ; /
259+ } ,
260+ tag : {
261+ exp : / ( & l t ; \/ ? ) ( [ a - z A - Z ] + \s ? ) / ,
262+ replacement : "$1<span class=\"$0\">$2</span>"
263+ } ,
264+ string : {
265+ exp : / ' [ ^ ' ] * ' | " [ ^ " ] * " /
266+ } ,
267+ attribute : {
268+ exp : / \b ( [ a - z A - Z - :] + ) ( = ) / ,
269+ replacement : "<span class=\"$0\">$1</span>$2"
270+ } ,
271+ doctype : {
272+ exp : / & l t ; ! D O C T Y P E ( [ ^ & ] | & [ ^ g ] | & g [ ^ t ] ) * & g t ; /
273+ }
274+ } ) ;
275+
276+ CodeHighlighter . addStyle ( "shell" , {
277+ keywords : {
278+ exp : / ( \$ ? ) ( [ ^ \n ] + ) /
279+ }
280+ } ) ;
0 commit comments