Project

General

Profile

1
/**
2
 * SyntaxHighlighter
3
 * http://alexgorbatchev.com/
4
 *
5
 * SyntaxHighlighter is donationware. If you are using it, please donate.
6
 * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate
7
 *
8
 * @version
9
 * 2.1.364 (October 15 2009)
10
 * 
11
 * @copyright
12
 * Copyright (C) 2004-2009 Alex Gorbatchev.
13
 *
14
 * @license
15
 * This file is part of SyntaxHighlighter.
16
 * 
17
 * SyntaxHighlighter is free software: you can redistribute it and/or modify
18
 * it under the terms of the GNU Lesser General Public License as published by
19
 * the Free Software Foundation, either version 3 of the License, or
20
 * (at your option) any later version.
21
 * 
22
 * SyntaxHighlighter is distributed in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25
 * GNU General Public License for more details.
26
 * 
27
 * You should have received a copy of the GNU General Public License
28
 * along with SyntaxHighlighter.  If not, see <http://www.gnu.org/copyleft/lesser.html>.
29
 */
30
//
31
// Begin anonymous function. This is used to contain local scope variables without polutting global scope.
32
//
33
if (!window.SyntaxHighlighter) var SyntaxHighlighter = function() { 
34

    
35
// Shortcut object which will be assigned to the SyntaxHighlighter variable.
36
// This is a shorthand for local reference in order to avoid long namespace 
37
// references to SyntaxHighlighter.whatever...
38
var sh = {
39
	defaults : {
40
		/** Additional CSS class names to be added to highlighter elements. */
41
		'class-name' : '',
42
		
43
		/** First line number. */
44
		'first-line' : 1,
45
		
46
		/**
47
		 * Pads line numbers. Possible values are:
48
		 *
49
		 *   false - don't pad line numbers.
50
		 *   true  - automaticaly pad numbers with minimum required number of leading zeroes.
51
		 *   [int] - length up to which pad line numbers.
52
		 */
53
		'pad-line-numbers' : true,
54
		
55
		/** Lines to highlight. */
56
		'highlight' : null,
57
		
58
		/** Enables or disables smart tabs. */
59
		'smart-tabs' : true,
60
		
61
		/** Gets or sets tab size. */
62
		'tab-size' : 4,
63
		
64
		/** Enables or disables gutter. */
65
		'gutter' : true,
66
		
67
		/** Enables or disables toolbar. */
68
		'toolbar' : true,
69
		
70
		/** Forces code view to be collapsed. */
71
		'collapse' : false,
72
		
73
		/** Enables or disables automatic links. */
74
		'auto-links' : true,
75
		
76
		/** Gets or sets light mode. Equavalent to turning off gutter and toolbar. */
77
		'light' : false,
78
		
79
		/** Enables or disables automatic line wrapping. */
80
		'wrap-lines' : true,
81
		
82
		'html-script' : false
83
	},
84
	
85
	config : {
86
		/** Enables use of <SCRIPT type="syntaxhighlighter" /> tags. */
87
		useScriptTags : true,
88
		
89
		/** Path to the copy to clipboard SWF file. */
90
		clipboardSwf : null,
91

    
92
		/** Width of an item in the toolbar. */
93
		toolbarItemWidth : 16,
94

    
95
		/** Height of an item in the toolbar. */
96
		toolbarItemHeight : 16,
97
		
98
		/** Blogger mode flag. */
99
		bloggerMode : false,
100
		
101
		stripBrs : false,
102
		
103
		/** Name of the tag that SyntaxHighlighter will automatically look for. */
104
		tagName : 'pre',
105
		
106
		strings : {
107
			expandSource : 'show source',
108
			viewSource : 'view source',
109
			copyToClipboard : 'copy to clipboard',
110
			copyToClipboardConfirmation : 'The code is in your clipboard now',
111
			print : 'print',
112
			help : '?',
113
			alert: 'SyntaxHighlighter\n\n',
114
			noBrush : 'Can\'t find brush for: ',
115
			brushNotHtmlScript : 'Brush wasn\'t configured for html-script option: ',
116
			
117
			// this is populated by the build script
118
			aboutDialog : '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>About SyntaxHighlighter</title></head><body style="font-family:Geneva,Arial,Helvetica,sans-serif;background-color:#fff;color:#000;font-size:1em;text-align:center;"><div style="text-align:center;margin-top:3em;"><div style="font-size:xx-large;">SyntaxHighlighter</div><div style="font-size:.75em;margin-bottom:4em;"><div>version 2.1.364 (October 15 2009)</div><div><a href="http://alexgorbatchev.com" target="_blank" style="color:#0099FF;text-decoration:none;">http://alexgorbatchev.com</a></div><div>If you like this script, please <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=2930402" style="color:#0099FF;text-decoration:none;">donate</a> to keep development active!</div></div><div>JavaScript code syntax highlighter.</div><div>Copyright 2004-2009 Alex Gorbatchev.</div></div></body></html>'
119
		},
120

    
121
		/** If true, output will show HTML produces instead. */
122
		debug : false
123
	},
124
	
125
	/** Internal 'global' variables. */
126
	vars : {
127
		discoveredBrushes : null,
128
		spaceWidth : null,
129
		printFrame : null,
130
		highlighters : {}
131
	},
132
	
133
	/** This object is populated by user included external brush files. */
134
	brushes : {},
135

    
136
	/** Common regular expressions. */
137
	regexLib : {
138
		multiLineCComments			: /\/\*[\s\S]*?\*\//gm,
139
		singleLineCComments			: /\/\/.*$/gm,
140
		singleLinePerlComments		: /#.*$/gm,
141
		doubleQuotedString			: /"([^\\"\n]|\\.)*"/g,
142
		singleQuotedString			: /'([^\\'\n]|\\.)*'/g,
143
		multiLineDoubleQuotedString	: /"([^\\"]|\\.)*"/g,
144
		multiLineSingleQuotedString	: /'([^\\']|\\.)*'/g,
145
		xmlComments					: /(&lt;|<)!--[\s\S]*?--(&gt;|>)/gm,
146
		url							: /&lt;\w+:\/\/[\w-.\/?%&=@:;]*&gt;|\w+:\/\/[\w-.\/?%&=@:;]*/g,
147
		
148
		/** <?= ?> tags. */
149
		phpScriptTags 				: { left: /(&lt;|<)\?=?/g, right: /\?(&gt;|>)/g },
150
		
151
		/** <%= %> tags. */
152
		aspScriptTags				: { left: /(&lt;|<)%=?/g, right: /%(&gt;|>)/g },
153
		
154
		/** <script></script> tags. */
155
		scriptScriptTags			: { left: /(&lt;|<)\s*script.*?(&gt;|>)/gi, right: /(&lt;|<)\/\s*script\s*(&gt;|>)/gi }
156
	},
157

    
158
	toolbar : {
159
		/**
160
		 * Creates new toolbar for a highlighter.
161
		 * @param {Highlighter} highlighter    Target highlighter.
162
		 */
163
		create : function(highlighter)
164
		{
165
			var div = document.createElement('DIV'),
166
				items = sh.toolbar.items
167
				;
168
			
169
			div.className = 'toolbar';
170
			
171
			for (var name in items) 
172
			{
173
				var constructor = items[name],
174
					command = new constructor(highlighter),
175
					element = command.create()
176
					;
177
				
178
				highlighter.toolbarCommands[name] = command;
179
				
180
				if (element == null)
181
					continue;
182
					
183
				if (typeof(element) == 'string')
184
					element = sh.toolbar.createButton(element, highlighter.id, name);
185
				
186
				element.className += 'item ' + name;
187
				div.appendChild(element);
188
			}
189
			
190
			return div;
191
		},
192
		
193
		/**
194
		 * Create a standard anchor button for the toolbar.
195
		 * @param {String} label			Label text to display.
196
		 * @param {String} highlighterId	Highlighter ID that this button would belong to.
197
		 * @param {String} commandName		Command name that would be executed.
198
		 * @return {Element}				Returns an 'A' element.
199
		 */
200
		createButton : function(label, highlighterId, commandName)
201
		{
202
			var a = document.createElement('a'),
203
				style = a.style,
204
				config = sh.config,
205
				width = config.toolbarItemWidth,
206
				height = config.toolbarItemHeight
207
				;
208
			
209
			a.href = '#' + commandName;
210
			a.title = label;
211
			a.highlighterId = highlighterId;
212
			a.commandName = commandName;
213
			a.innerHTML = label;
214
			
215
			if (isNaN(width) == false)
216
				style.width = width + 'px';
217

    
218
			if (isNaN(height) == false)
219
				style.height = height + 'px';
220
			
221
			a.onclick = function(e)
222
			{
223
				try
224
				{
225
					sh.toolbar.executeCommand(
226
						this, 
227
						e || window.event,
228
						this.highlighterId, 
229
						this.commandName
230
					);
231
				}
232
				catch(e)
233
				{
234
					sh.utils.alert(e.message);
235
				}
236
				
237
				return false;
238
			};
239
			
240
			return a;
241
		},
242
		
243
		/**
244
		 * Executes a toolbar command.
245
		 * @param {Element}		sender  		Sender element.
246
		 * @param {MouseEvent}	event			Original mouse event object.
247
		 * @param {String}		highlighterId	Highlighter DIV element ID.
248
		 * @param {String}		commandName		Name of the command to execute.
249
		 * @return {Object} Passes out return value from command execution.
250
		 */
251
		executeCommand : function(sender, event, highlighterId, commandName, args)
252
		{
253
			var highlighter = sh.vars.highlighters[highlighterId], 
254
				command
255
				;
256

    
257
			if (highlighter == null || (command = highlighter.toolbarCommands[commandName]) == null) 
258
				return null;
259

    
260
			return command.execute(sender, event, args);
261
		},
262
		
263
		/** Collection of toolbar items. */
264
		items : {
265
			expandSource : function(highlighter)
266
			{
267
				this.create = function()
268
				{
269
					if (highlighter.getParam('collapse') != true)
270
						return;
271
					
272
					return sh.config.strings.expandSource;
273
				};
274
			
275
				this.execute = function(sender, event, args)
276
				{
277
					var div = highlighter.div;
278
					
279
					sender.parentNode.removeChild(sender);
280
					div.className = div.className.replace('collapsed', '');
281
				};
282
			},
283
		
284
			/** 
285
			 * Command to open a new window and display the original unformatted source code inside.
286
			 */
287
			viewSource : function(highlighter)
288
			{
289
				this.create = function()
290
				{
291
					return sh.config.strings.viewSource;
292
				};
293
				
294
				this.execute = function(sender, event, args)
295
				{
296
					var code = sh.utils.fixInputString(highlighter.originalCode).replace(/</g, '&lt;'),
297
						wnd = sh.utils.popup('', '_blank', 750, 400, 'location=0, resizable=1, menubar=0, scrollbars=1')
298
						;
299
					
300
					code = sh.utils.unindent(code);
301
					
302
					wnd.document.write('<pre>' + code + '</pre>');
303
					wnd.document.close();
304
				};
305
			},
306
			
307
			/**
308
			 * Command to copy the original source code in to the clipboard.
309
			 * Uses Flash method if <code>clipboardSwf</code> is configured.
310
			 */
311
			copyToClipboard : function(highlighter)
312
			{
313
				var flashDiv, flashSwf,
314
					highlighterId = highlighter.id
315
					;
316
				
317
				this.create = function()
318
				{
319
					var config = sh.config;
320
					
321
					// disable functionality if running locally
322
					if (config.clipboardSwf == null)
323
						return null;
324

    
325
					function params(list)
326
					{
327
						var result = '';
328
						
329
						for (var name in list)
330
							result += "<param name='" + name + "' value='" + list[name] + "'/>";
331
							
332
						return result;
333
					};
334
					
335
					function attributes(list)
336
					{
337
						var result = '';
338
						
339
						for (var name in list)
340
							result += " " + name + "='" + list[name] + "'";
341
							
342
						return result;
343
					};
344
					
345
					var args1 = {
346
							width				: config.toolbarItemWidth,
347
							height				: config.toolbarItemHeight,
348
							id					: highlighterId + '_clipboard',
349
							type				: 'application/x-shockwave-flash',
350
							title				: sh.config.strings.copyToClipboard
351
						},
352
						
353
						// these arguments are used in IE's <param /> collection
354
						args2 = {
355
							allowScriptAccess	: 'always',
356
							wmode				: 'transparent',
357
							flashVars			: 'highlighterId=' + highlighterId,
358
							menu				: 'false'
359
						},
360
						swf = config.clipboardSwf,
361
						html
362
					;
363

    
364
					if (/msie/i.test(navigator.userAgent))
365
					{
366
						html = '<object'
367
							+ attributes({
368
								classid : 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000',
369
								codebase : 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0'
370
							})
371
							+ attributes(args1)
372
							+ '>'
373
							+ params(args2)
374
							+ params({ movie : swf })
375
							+ '</object>'
376
						;
377
					}
378
					else
379
					{
380
						html = '<embed'
381
							+ attributes(args1)
382
							+ attributes(args2)
383
							+ attributes({ src : swf })
384
							+ '/>'
385
						;
386
					}
387

    
388
					flashDiv = document.createElement('div');
389
					flashDiv.innerHTML = html;
390
					
391
					return flashDiv;
392
				};
393
				
394
				this.execute = function(sender, event, args)
395
				{
396
					var command = args.command;
397

    
398
					switch (command)
399
					{
400
						case 'get':
401
							var code = sh.utils.unindent(
402
								sh.utils.fixInputString(highlighter.originalCode)
403
									.replace(/&lt;/g, '<')
404
									.replace(/&gt;/g, '>')
405
									.replace(/&amp;/g, '&')
406
								);
407

    
408
							if(window.clipboardData)
409
								// will fall through to the confirmation because there isn't a break
410
								window.clipboardData.setData('text', code);
411
							else
412
								return sh.utils.unindent(code);
413
							
414
						case 'ok':
415
							sh.utils.alert(sh.config.strings.copyToClipboardConfirmation);
416
							break;
417
							
418
						case 'error':
419
							sh.utils.alert(args.message);
420
							break;
421
					}
422
				};
423
			},
424
			
425
			/** Command to print the colored source code. */
426
			printSource : function(highlighter)
427
			{
428
				this.create = function()
429
				{
430
					return sh.config.strings.print;
431
				};
432
				
433
				this.execute = function(sender, event, args)
434
				{
435
					var iframe = document.createElement('IFRAME'),
436
						doc = null
437
						;
438
					
439
					// make sure there is never more than one hidden iframe created by SH
440
					if (sh.vars.printFrame != null)
441
						document.body.removeChild(sh.vars.printFrame);
442
					
443
					sh.vars.printFrame = iframe;
444
					
445
					// this hides the iframe
446
					iframe.style.cssText = 'position:absolute;width:0px;height:0px;left:-500px;top:-500px;';
447
				
448
					document.body.appendChild(iframe);
449
					doc = iframe.contentWindow.document;
450
					
451
					copyStyles(doc, window.document);
452
					doc.write('<div class="' + highlighter.div.className.replace('collapsed', '') + ' printing">' + highlighter.div.innerHTML + '</div>');
453
					doc.close();
454
					
455
					iframe.contentWindow.focus();
456
					iframe.contentWindow.print();
457
					
458
					function copyStyles(destDoc, sourceDoc)
459
					{
460
						var links = sourceDoc.getElementsByTagName('link');
461
					
462
						for(var i = 0; i < links.length; i++)
463
							if(links[i].rel.toLowerCase() == 'stylesheet' && /shCore\.css$/.test(links[i].href))
464
								destDoc.write('<link type="text/css" rel="stylesheet" href="' + links[i].href + '"></link>');
465
					};
466
				};
467
			},
468

    
469
			/** Command to display the about dialog window. */
470
			about : function(highlighter)
471
			{
472
				this.create = function()
473
				{	
474
					return sh.config.strings.help;
475
				};
476

    
477
				this.execute = function(sender, event)
478
				{	
479
					var wnd = sh.utils.popup('', '_blank', 500, 250, 'scrollbars=0'),
480
						doc = wnd.document
481
						;
482
					
483
					doc.write(sh.config.strings.aboutDialog);
484
					doc.close();
485
					wnd.focus();
486
				};
487
			}
488
		}
489
	},
490

    
491
	utils : {
492
		/**
493
		 * Finds an index of element in the array.
494
		 * @ignore
495
		 * @param {Object} searchElement
496
		 * @param {Number} fromIndex
497
		 * @return {Number} Returns index of element if found; -1 otherwise.
498
		 */
499
		indexOf : function(array, searchElement, fromIndex)
500
		{
501
			fromIndex = Math.max(fromIndex || 0, 0);
502

    
503
			for (var i = fromIndex; i < array.length; i++)
504
				if(array[i] == searchElement)
505
					return i;
506

    
507
			return -1;
508
		},
509
		
510
		/**
511
		 * Generates a unique element ID.
512
		 */
513
		guid : function(prefix)
514
		{
515
			return prefix + Math.round(Math.random() * 1000000).toString();
516
		},
517
		
518
		/**
519
		 * Merges two objects. Values from obj2 override values in obj1.
520
		 * Function is NOT recursive and works only for one dimensional objects.
521
		 * @param {Object} obj1 First object.
522
		 * @param {Object} obj2 Second object.
523
		 * @return {Object} Returns combination of both objects.
524
		 */
525
		merge: function(obj1, obj2)
526
		{
527
			var result = {}, name;
528

    
529
			for (name in obj1) 
530
				result[name] = obj1[name];
531
			
532
			for (name in obj2) 
533
				result[name] = obj2[name];
534
				
535
			return result;
536
		},
537
		
538
		/**
539
		 * Attempts to convert string to boolean.
540
		 * @param {String} value Input string.
541
		 * @return {Boolean} Returns true if input was "true", false if input was "false" and value otherwise.
542
		 */
543
		toBoolean: function(value)
544
		{
545
			switch (value)
546
			{
547
				case "true":
548
					return true;
549
					
550
				case "false":
551
					return false;
552
			}
553
			
554
			return value;
555
		},
556
		
557
		/**
558
		 * Opens up a centered popup window.
559
		 * @param {String} url		URL to open in the window.
560
		 * @param {String} name		Popup name.
561
		 * @param {int} width		Popup width.
562
		 * @param {int} height		Popup height.
563
		 * @param {String} options	window.open() options.
564
		 * @return {Window}			Returns window instance.
565
		 */
566
		popup: function(url, name, width, height, options)
567
		{
568
			var x = (screen.width - width) / 2,
569
				y = (screen.height - height) / 2
570
				;
571
				
572
			options +=	', left=' + x + 
573
						', top=' + y +
574
						', width=' + width +
575
						', height=' + height
576
				;
577
			options = options.replace(/^,/, '');
578

    
579
			var win = window.open(url, name, options);
580
			win.focus();
581
			return win;
582
		},
583
		
584
		/**
585
		 * Adds event handler to the target object.
586
		 * @param {Object} obj		Target object.
587
		 * @param {String} type		Name of the event.
588
		 * @param {Function} func	Handling function.
589
		 */
590
		addEvent: function(obj, type, func)
591
		{
592
			if (obj.attachEvent) 
593
			{
594
				obj['e' + type + func] = func;
595
				obj[type + func] = function()
596
				{
597
					obj['e' + type + func](window.event);
598
				}
599
				obj.attachEvent('on' + type, obj[type + func]);
600
			}
601
			else 
602
			{
603
				obj.addEventListener(type, func, false);
604
			}
605
		},
606
		
607
		/**
608
		 * Displays an alert.
609
		 * @param {String} str String to display.
610
		 */
611
		alert: function(str)
612
		{
613
			alert(sh.config.strings.alert + str)
614
		},
615
		
616
		/**
617
		 * Finds a brush by its alias.
618
		 *
619
		 * @param {String} alias	Brush alias.
620
		 * @param {Boolean} alert	Suppresses the alert if false.
621
		 * @return {Brush}			Returns bursh constructor if found, null otherwise.
622
		 */
623
		findBrush: function(alias, alert)
624
		{
625
			var brushes = sh.vars.discoveredBrushes,
626
				result = null
627
				;
628
			
629
			if (brushes == null) 
630
			{
631
				brushes = {};
632
				
633
				// Find all brushes
634
				for (var brush in sh.brushes) 
635
				{
636
					var aliases = sh.brushes[brush].aliases;
637
					
638
					if (aliases == null) 
639
						continue;
640
					
641
					// keep the brush name
642
					sh.brushes[brush].name = brush.toLowerCase();
643
					
644
					for (var i = 0; i < aliases.length; i++) 
645
						brushes[aliases[i]] = brush;
646
				}
647
				
648
				sh.vars.discoveredBrushes = brushes;
649
			}
650
			
651
			result = sh.brushes[brushes[alias]];
652

    
653
			if (result == null && alert != false)
654
				sh.utils.alert(sh.config.strings.noBrush + alias);
655
			
656
			return result;
657
		},
658
		
659
		/**
660
		 * Executes a callback on each line and replaces each line with result from the callback.
661
		 * @param {Object} str			Input string.
662
		 * @param {Object} callback		Callback function taking one string argument and returning a string.
663
		 */
664
		eachLine: function(str, callback)
665
		{
666
			var lines = str.split('\n');
667
			
668
			for (var i = 0; i < lines.length; i++)
669
				lines[i] = callback(lines[i]);
670
				
671
			return lines.join('\n');
672
		},
673
		
674
		/**
675
		 * This is a special trim which only removes first and last empty lines
676
		 * and doesn't affect valid leading space on the first line.
677
		 * 
678
		 * @param {String} str   Input string
679
		 * @return {String}      Returns string without empty first and last lines.
680
		 */
681
		trimFirstAndLastLines: function(str)
682
		{
683
			return str.replace(/^[ ]*[\n]+|[\n]*[ ]*$/g, '');
684
		},
685
		
686
		/**
687
		 * Parses key/value pairs into hash object.
688
		 * 
689
		 * Understands the following formats:
690
		 * - name: word;
691
		 * - name: [word, word];
692
		 * - name: "string";
693
		 * - name: 'string';
694
		 * 
695
		 * For example:
696
		 *   name1: value; name2: [value, value]; name3: 'value'
697
		 *   
698
		 * @param {String} str    Input string.
699
		 * @return {Object}       Returns deserialized object.
700
		 */
701
		parseParams: function(str)
702
		{
703
			var match, 
704
				result = {},
705
				arrayRegex = new XRegExp("^\\[(?<values>(.*?))\\]$"),
706
				regex = new XRegExp(
707
					"(?<name>[\\w-]+)" +
708
					"\\s*:\\s*" +
709
					"(?<value>" +
710
						"[\\w-%#]+|" +		// word
711
						"\\[.*?\\]|" +		// [] array
712
						'".*?"|' +			// "" string
713
						"'.*?'" +			// '' string
714
					")\\s*;?",
715
					"g"
716
				)
717
				;
718

    
719
			while ((match = regex.exec(str)) != null) 
720
			{
721
				var value = match.value
722
					.replace(/^['"]|['"]$/g, '') // strip quotes from end of strings
723
					;
724
				
725
				// try to parse array value
726
				if (value != null && arrayRegex.test(value))
727
				{
728
					var m = arrayRegex.exec(value);
729
					value = m.values.length > 0 ? m.values.split(/\s*,\s*/) : [];
730
				}
731
				
732
				result[match.name] = value;
733
			}
734
			
735
			return result;
736
		},
737
	
738
		/**
739
		 * Wraps each line of the string into <code/> tag with given style applied to it.
740
		 * 
741
		 * @param {String} str   Input string.
742
		 * @param {String} css   Style name to apply to the string.
743
		 * @return {String}      Returns input string with each line surrounded by <span/> tag.
744
		 */
745
		decorate: function(str, css)
746
		{
747
			if (str == null || str.length == 0 || str == '\n') 
748
				return str;
749
	
750
			str = str.replace(/</g, '&lt;');
751
	
752
			// Replace two or more sequential spaces with &nbsp; leaving last space untouched.
753
			str = str.replace(/ {2,}/g, function(m)
754
			{
755
				var spaces = '';
756
				
757
				for (var i = 0; i < m.length - 1; i++)
758
					spaces += '&nbsp;';
759
				
760
				return spaces + ' ';
761
			});
762

    
763
			// Split each line and apply <span class="...">...</span> to them so that
764
			// leading spaces aren't included.
765
			if (css != null) 
766
				str = sh.utils.eachLine(str, function(line)
767
				{
768
					if (line.length == 0) 
769
						return '';
770
					
771
					var spaces = '';
772
					
773
					line = line.replace(/^(&nbsp;| )+/, function(s)
774
					{
775
						spaces = s;
776
						return '';
777
					});
778
					
779
					if (line.length == 0) 
780
						return spaces;
781
					
782
					return spaces + '<code class="' + css + '">' + line + '</code>';
783
				});
784

    
785
			return str;
786
		},
787
	
788
		/**
789
		 * Pads number with zeros until it's length is the same as given length.
790
		 * 
791
		 * @param {Number} number	Number to pad.
792
		 * @param {Number} length	Max string length with.
793
		 * @return {String}			Returns a string padded with proper amount of '0'.
794
		 */
795
		padNumber : function(number, length)
796
		{
797
			var result = number.toString();
798
			
799
			while (result.length < length)
800
				result = '0' + result;
801
			
802
			return result;
803
		},
804
		
805
		/**
806
		 * Measures width of a single space character.
807
		 * @return {Number} Returns width of a single space character.
808
		 */
809
		measureSpace : function()
810
		{
811
			var container = document.createElement('div'),
812
				span,
813
				result = 0,
814
				body = document.body,
815
				id = sh.utils.guid('measureSpace'),
816
				
817
				// variable names will be compressed, so it's better than a plain string
818
				divOpen = '<div class="',
819
				closeDiv = '</div>',
820
				closeSpan = '</span>'
821
				;
822

    
823
			// we have to duplicate highlighter nested structure in order to get an acurate space measurment
824
			container.innerHTML = 
825
				divOpen + 'syntaxhighlighter">' 
826
					+ divOpen + 'lines">' 
827
						+ divOpen + 'line">' 
828
							+ divOpen + 'content'
829
								+ '"><span class="block"><span id="' + id + '">&nbsp;' + closeSpan + closeSpan
830
							+ closeDiv 
831
						+ closeDiv 
832
					+ closeDiv 
833
				+ closeDiv
834
				;
835
			
836
			body.appendChild(container);
837
			span = document.getElementById(id);
838
			
839
			if (/opera/i.test(navigator.userAgent))
840
			{
841
				var style = window.getComputedStyle(span, null);
842
				result = parseInt(style.getPropertyValue("width"));
843
			}
844
			else
845
			{
846
				result = span.offsetWidth;
847
			}
848

    
849
			body.removeChild(container);
850

    
851
			return result;
852
		},
853
		
854
		/**
855
		 * Replaces tabs with spaces.
856
		 * 
857
		 * @param {String} code		Source code.
858
		 * @param {Number} tabSize	Size of the tab.
859
		 * @return {String}			Returns code with all tabs replaces by spaces.
860
		 */
861
		processTabs : function(code, tabSize)
862
		{
863
			var tab = '';
864
			
865
			for (var i = 0; i < tabSize; i++)
866
				tab += ' ';
867

    
868
			return code.replace(/\t/g, tab);
869
		},
870
		
871
		/**
872
		 * Replaces tabs with smart spaces.
873
		 * 
874
		 * @param {String} code    Code to fix the tabs in.
875
		 * @param {Number} tabSize Number of spaces in a column.
876
		 * @return {String}        Returns code with all tabs replaces with roper amount of spaces.
877
		 */
878
		processSmartTabs : function(code, tabSize)
879
		{
880
			var lines = code.split('\n'),
881
				tab = '\t',
882
				spaces = ''
883
				;
884
			
885
			// Create a string with 1000 spaces to copy spaces from... 
886
			// It's assumed that there would be no indentation longer than that.
887
			for (var i = 0; i < 50; i++) 
888
				spaces += '                    '; // 20 spaces * 50
889
					
890
			// This function inserts specified amount of spaces in the string
891
			// where a tab is while removing that given tab.
892
			function insertSpaces(line, pos, count)
893
			{
894
				return line.substr(0, pos)
895
					+ spaces.substr(0, count)
896
					+ line.substr(pos + 1, line.length) // pos + 1 will get rid of the tab
897
					;
898
			};
899
	
900
			// Go through all the lines and do the 'smart tabs' magic.
901
			code = sh.utils.eachLine(code, function(line)
902
			{
903
				if (line.indexOf(tab) == -1) 
904
					return line;
905
				
906
				var pos = 0;
907
				
908
				while ((pos = line.indexOf(tab)) != -1) 
909
				{
910
					// This is pretty much all there is to the 'smart tabs' logic.
911
					// Based on the position within the line and size of a tab,
912
					// calculate the amount of spaces we need to insert.
913
					var spaces = tabSize - pos % tabSize;
914
					line = insertSpaces(line, pos, spaces);
915
				}
916
				
917
				return line;
918
			});
919
			
920
			return code;
921
		},
922
		
923
		/**
924
		 * Performs various string fixes based on configuration.
925
		 */
926
		fixInputString : function(str)
927
		{
928
			var br = /<br\s*\/?>|&lt;br\s*\/?&gt;/gi;
929
			
930
			if (sh.config.bloggerMode == true)
931
				str = str.replace(br, '\n');
932

    
933
			if (sh.config.stripBrs == true)
934
				str = str.replace(br, '');
935
				
936
			return str;
937
		},
938
		
939
		/**
940
		 * Removes all white space at the begining and end of a string.
941
		 * 
942
		 * @param {String} str   String to trim.
943
		 * @return {String}      Returns string without leading and following white space characters.
944
		 */
945
		trim: function(str)
946
		{
947
			return str.replace(/^\s+|\s+$/g, '');
948
		},
949
		
950
		/**
951
		 * Unindents a block of text by the lowest common indent amount.
952
		 * @param {String} str   Text to unindent.
953
		 * @return {String}      Returns unindented text block.
954
		 */
955
		unindent: function(str)
956
		{
957
			var lines = sh.utils.fixInputString(str).split('\n'),
958
				indents = new Array(),
959
				regex = /^\s*/,
960
				min = 1000
961
				;
962
			
963
			// go through every line and check for common number of indents
964
			for (var i = 0; i < lines.length && min > 0; i++) 
965
			{
966
				var line = lines[i];
967
				
968
				if (sh.utils.trim(line).length == 0) 
969
					continue;
970
				
971
				var matches = regex.exec(line);
972
				
973
				// In the event that just one line doesn't have leading white space
974
				// we can't unindent anything, so bail completely.
975
				if (matches == null) 
976
					return str;
977
					
978
				min = Math.min(matches[0].length, min);
979
			}
980
			
981
			// trim minimum common number of white space from the begining of every line
982
			if (min > 0) 
983
				for (var i = 0; i < lines.length; i++) 
984
					lines[i] = lines[i].substr(min);
985
			
986
			return lines.join('\n');
987
		},
988
	
989
		/**
990
		 * Callback method for Array.sort() which sorts matches by
991
		 * index position and then by length.
992
		 * 
993
		 * @param {Match} m1	Left object.
994
		 * @param {Match} m2    Right object.
995
		 * @return {Number}     Returns -1, 0 or -1 as a comparison result.
996
		 */
997
		matchesSortCallback: function(m1, m2)
998
		{
999
			// sort matches by index first
1000
			if(m1.index < m2.index)
1001
				return -1;
1002
			else if(m1.index > m2.index)
1003
				return 1;
1004
			else
1005
			{
1006
				// if index is the same, sort by length
1007
				if(m1.length < m2.length)
1008
					return -1;
1009
				else if(m1.length > m2.length)
1010
					return 1;
1011
			}
1012
			
1013
			return 0;
1014
		},
1015
	
1016
		/**
1017
		 * Executes given regular expression on provided code and returns all
1018
		 * matches that are found.
1019
		 * 
1020
		 * @param {String} code    Code to execute regular expression on.
1021
		 * @param {Object} regex   Regular expression item info from <code>regexList</code> collection.
1022
		 * @return {Array}         Returns a list of Match objects.
1023
		 */ 
1024
		getMatches: function(code, regexInfo)
1025
		{
1026
			function defaultAdd(match, regexInfo)
1027
			{
1028
				return [new sh.Match(match[0], match.index, regexInfo.css)];
1029
			};
1030
			
1031
			var index = 0,
1032
				match = null,
1033
				result = [],
1034
				func = regexInfo.func ? regexInfo.func : defaultAdd
1035
				;
1036
			
1037
			while((match = regexInfo.regex.exec(code)) != null)
1038
				result = result.concat(func(match, regexInfo));
1039
				
1040
			return result;
1041
		},
1042
		
1043
		processUrls: function(code)
1044
		{
1045
			var lt = '&lt;',
1046
				gt = '&gt;'
1047
				;
1048
			
1049
			return code.replace(sh.regexLib.url, function(m)
1050
			{
1051
				var suffix = '', prefix = '';
1052
				
1053
				// We include &lt; and &gt; in the URL for the common cases like <http://google.com>
1054
				// The problem is that they get transformed into &lt;http://google.com&gt;
1055
				// Where as &gt; easily looks like part of the URL string.
1056
				
1057
				if (m.indexOf(lt) == 0)
1058
				{
1059
					prefix = lt;
1060
					m = m.substring(lt.length);
1061
				}
1062

    
1063
				if (m.indexOf(gt) == m.length - gt.length)
1064
				{
1065
					m = m.substring(0, m.length - gt.length);
1066
					suffix = gt;
1067
				}
1068
				
1069
				return prefix + '<a href="' + m + '">' + m + '</a>' + suffix;
1070
			});
1071
		},
1072
		
1073
		/**
1074
		 * Finds all <SCRIPT TYPE="syntaxhighlighter" /> elements.
1075
		 * @return {Array} Returns array of all found SyntaxHighlighter tags.
1076
		 */
1077
		getSyntaxHighlighterScriptTags: function()
1078
		{
1079
			var tags = document.getElementsByTagName('script'),
1080
				result = []
1081
				;
1082
			
1083
			for (var i = 0; i < tags.length; i++)
1084
				if (tags[i].type == 'syntaxhighlighter')
1085
					result.push(tags[i]);
1086
					
1087
			return result;
1088
		},
1089
		
1090
		/**
1091
		 * Strips <![CDATA[]]> from <SCRIPT /> content because it should be used
1092
		 * there in most cases for XHTML compliance.
1093
		 * @param {String} original	Input code.
1094
		 * @return {String} Returns code without leading <![CDATA[]]> tags.
1095
		 */
1096
		stripCData: function(original)
1097
		{
1098
			var left = '<![CDATA[',
1099
				right = ']]>',
1100
				// for some reason IE inserts some leading blanks here
1101
				copy = sh.utils.trim(original),
1102
				changed = false
1103
				;
1104
			
1105
			if (copy.indexOf(left) == 0)
1106
			{
1107
				copy = copy.substring(left.length);
1108
				changed = true;
1109
			}
1110
			
1111
			if (copy.indexOf(right) == copy.length - right.length)
1112
			{
1113
				copy = copy.substring(0, copy.length - right.length);
1114
				changed = true;
1115
			}
1116
			
1117
			return changed ? copy : original;
1118
		}
1119
	}, // end of utils
1120
	
1121
	/**
1122
	 * Shorthand to highlight all elements on the page that are marked as 
1123
	 * SyntaxHighlighter source code.
1124
	 * 
1125
	 * @param {Object} globalParams		Optional parameters which override element's 
1126
	 * 									parameters. Only used if element is specified.
1127
	 * 
1128
	 * @param {Object} element	Optional element to highlight. If none is
1129
	 * 							provided, all elements in the current document 
1130
	 * 							are highlighted.
1131
	 */ 
1132
	highlight : function(globalParams, element)
1133
	{
1134
		function toArray(source)
1135
		{
1136
			var result = [];
1137
			
1138
			for (var i = 0; i < source.length; i++) 
1139
				result.push(source[i]);
1140
				
1141
			return result;
1142
		};
1143
		
1144
		var elements = element ? [element] : toArray(document.getElementsByTagName(sh.config.tagName)), 
1145
			propertyName = 'innerHTML', 
1146
			highlighter = null,
1147
			conf = sh.config
1148
			;
1149

    
1150
		// support for <SCRIPT TYPE="syntaxhighlighter" /> feature
1151
		if (conf.useScriptTags)
1152
			elements = elements.concat(sh.utils.getSyntaxHighlighterScriptTags());
1153

    
1154
		if (elements.length === 0) 
1155
			return;
1156
	
1157
		for (var i = 0; i < elements.length; i++) 
1158
		{
1159
			var target = elements[i], 
1160
				params = sh.utils.parseParams(target.className),
1161
				brushName,
1162
				code,
1163
				result
1164
				;
1165

    
1166
			// local params take precedence over globals
1167
			params = sh.utils.merge(globalParams, params);
1168
			brushName = params['brush'];
1169

    
1170
			if (brushName == null)
1171
				continue;
1172

    
1173
			// Instantiate a brush
1174
			if (params['html-script'] == 'true' || sh.defaults['html-script'] == true) 
1175
			{
1176
				highlighter = new sh.HtmlScript(brushName);
1177
				brushName = 'htmlscript';
1178
			}
1179
			else
1180
			{
1181
				var brush = sh.utils.findBrush(brushName);
1182
				
1183
				if (brush)
1184
				{
1185
					brushName = brush.name;
1186
					highlighter = new brush();
1187
				}
1188
				else
1189
				{
1190
					continue;
1191
				}
1192
			}
1193
			
1194
			code = target[propertyName];
1195
			
1196
			// remove CDATA from <SCRIPT/> tags if it's present
1197
			if (conf.useScriptTags)
1198
				code = sh.utils.stripCData(code);
1199
			
1200
			params['brush-name'] = brushName;
1201
			highlighter.highlight(code, params);
1202
			
1203
			result = highlighter.div;
1204
			
1205
			if (sh.config.debug) 
1206
			{
1207
				result = document.createElement('textarea');
1208
				result.value = highlighter.div.innerHTML;
1209
				result.style.width = '70em';
1210
				result.style.height = '30em';
1211
			}
1212
			
1213
			target.parentNode.replaceChild(result, target);
1214
		}
1215
	},
1216

    
1217
	/**
1218
	 * Main entry point for the SyntaxHighlighter.
1219
	 * @param {Object} params Optional params to apply to all highlighted elements.
1220
	 */
1221
	all : function(params)
1222
	{
1223
		sh.utils.addEvent(
1224
			window,
1225
			'load',
1226
			function() { sh.highlight(params); }
1227
		);
1228
	}
1229
}; // end of sh
1230

    
1231
/**
1232
 * Match object.
1233
 */
1234
sh.Match = function(value, index, css)
1235
{
1236
	this.value = value;
1237
	this.index = index;
1238
	this.length = value.length;
1239
	this.css = css;
1240
	this.brushName = null;
1241
};
1242

    
1243
sh.Match.prototype.toString = function()
1244
{
1245
	return this.value;
1246
};
1247

    
1248
/**
1249
 * Simulates HTML code with a scripting language embedded.
1250
 * 
1251
 * @param {String} scriptBrushName Brush name of the scripting language.
1252
 */
1253
sh.HtmlScript = function(scriptBrushName)
1254
{
1255
	var brushClass = sh.utils.findBrush(scriptBrushName),
1256
		scriptBrush,
1257
		xmlBrush = new sh.brushes.Xml(),
1258
		bracketsRegex = null
1259
		;
1260

    
1261
	if (brushClass == null)
1262
		return;
1263
	
1264
	scriptBrush = new brushClass();
1265
	this.xmlBrush = xmlBrush;
1266
	
1267
	if (scriptBrush.htmlScript == null)
1268
	{
1269
		sh.utils.alert(sh.config.strings.brushNotHtmlScript + scriptBrushName);
1270
		return;
1271
	}
1272
	
1273
	xmlBrush.regexList.push(
1274
		{ regex: scriptBrush.htmlScript.code, func: process }
1275
	);
1276
	
1277
	function offsetMatches(matches, offset)
1278
	{
1279
		for (var j = 0; j < matches.length; j++) 
1280
			matches[j].index += offset;
1281
	}
1282
	
1283
	function process(match, info)
1284
	{
1285
		var code = match.code,
1286
			matches = [],
1287
			regexList = scriptBrush.regexList,
1288
			offset = match.index + match.left.length,
1289
			htmlScript = scriptBrush.htmlScript,
1290
			result
1291
			;
1292

    
1293
		// add all matches from the code
1294
		for (var i = 0; i < regexList.length; i++)
1295
		{
1296
			result = sh.utils.getMatches(code, regexList[i]);
1297
			offsetMatches(result, offset);
1298
			matches = matches.concat(result);
1299
		}
1300
		
1301
		// add left script bracket
1302
		if (htmlScript.left != null && match.left != null)
1303
		{
1304
			result = sh.utils.getMatches(match.left, htmlScript.left);
1305
			offsetMatches(result, match.index);
1306
			matches = matches.concat(result);
1307
		}
1308
		
1309
		// add right script bracket
1310
		if (htmlScript.right != null && match.right != null)
1311
		{
1312
			result = sh.utils.getMatches(match.right, htmlScript.right);
1313
			offsetMatches(result, match.index + match[0].lastIndexOf(match.right));
1314
			matches = matches.concat(result);
1315
		}
1316
		
1317
		for (var j = 0; j < matches.length; j++)
1318
			matches[j].brushName = brushClass.name;
1319

    
1320
		return matches;
1321
	}
1322
};
1323

    
1324
sh.HtmlScript.prototype.highlight = function(code, params)
1325
{
1326
	this.xmlBrush.highlight(code, params);
1327
	this.div = this.xmlBrush.div;
1328
}
1329

    
1330
/**
1331
 * Main Highlither class.
1332
 * @constructor
1333
 */
1334
sh.Highlighter = function()
1335
{
1336
};
1337

    
1338
sh.Highlighter.prototype = {
1339
	/**
1340
	 * Returns value of the parameter passed to the highlighter.
1341
	 * @param {String} name				Name of the parameter.
1342
	 * @param {Object} defaultValue		Default value.
1343
	 * @return {Object}					Returns found value or default value otherwise.
1344
	 */
1345
	getParam : function(name, defaultValue)
1346
	{
1347
		var result = this.params[name];
1348
		return sh.utils.toBoolean(result == null ? defaultValue : result);
1349
	},
1350
	
1351
	/**
1352
	 * Shortcut to document.createElement().
1353
	 * @param {String} name		Name of the element to create (DIV, A, etc).
1354
	 * @return {HTMLElement}	Returns new HTML element.
1355
	 */
1356
	create: function(name)
1357
	{
1358
		return document.createElement(name);
1359
	},
1360
	
1361
	/**
1362
	 * Applies all regular expression to the code and stores all found
1363
	 * matches in the `this.matches` array.
1364
	 * @param {Array} regexList		List of regular expressions.
1365
	 * @param {String} code			Source code.
1366
	 * @return {Array}				Returns list of matches.
1367
	 */
1368
	findMatches: function(regexList, code)
1369
	{
1370
		var result = [];
1371
		
1372
		if (regexList != null)
1373
			for (var i = 0; i < regexList.length; i++) 
1374
				// BUG: length returns len+1 for array if methods added to prototype chain (oising@gmail.com)
1375
				if (typeof (regexList[i]) == "object")
1376
					result = result.concat(sh.utils.getMatches(code, regexList[i]));
1377
		
1378
		// sort the matches
1379
		return result.sort(sh.utils.matchesSortCallback);
1380
	},
1381
	
1382
	/**
1383
	 * Checks to see if any of the matches are inside of other matches. 
1384
	 * This process would get rid of highligted strings inside comments, 
1385
	 * keywords inside strings and so on.
1386
	 */
1387
	removeNestedMatches: function()
1388
	{
1389
		var matches = this.matches;
1390
		
1391
		// Optimized by Jose Prado (http://joseprado.com)
1392
		for (var i = 0; i < matches.length; i++) 
1393
		{ 
1394
			if (matches[i] === null)
1395
				continue;
1396
			
1397
			var itemI = matches[i],
1398
				itemIEndPos = itemI.index + itemI.length
1399
				;
1400
			
1401
			for (var j = i + 1; j < matches.length && matches[i] !== null; j++) 
1402
			{
1403
				var itemJ = matches[j];
1404
				
1405
				if (itemJ === null) 
1406
					continue;
1407
				else if (itemJ.index > itemIEndPos) 
1408
					break;
1409
				else if (itemJ.index == itemI.index && itemJ.length > itemI.length)
1410
					this.matches[i] = null;
1411
				else if (itemJ.index >= itemI.index && itemJ.index < itemIEndPos) 
1412
					this.matches[j] = null;
1413
			}
1414
		}
1415
	},
1416
	
1417
	/**
1418
	 * Splits block of text into individual DIV lines.
1419
	 * @param {String} code     Code to highlight.
1420
	 * @return {String}         Returns highlighted code in HTML form.
1421
	 */
1422
	createDisplayLines : function(code)
1423
	{
1424
		var lines = code.split(/\n/g),
1425
			firstLine = parseInt(this.getParam('first-line')),
1426
			padLength = this.getParam('pad-line-numbers'),
1427
			highlightedLines = this.getParam('highlight', []),
1428
			hasGutter = this.getParam('gutter')
1429
			;
1430
		
1431
		code = '';
1432
		
1433
		if (padLength == true)
1434
			padLength = (firstLine + lines.length - 1).toString().length;
1435
		else if (isNaN(padLength) == true)
1436
			padLength = 0;
1437

    
1438
		for (var i = 0; i < lines.length; i++)
1439
		{
1440
			var line = lines[i],
1441
				indent = /^(&nbsp;|\s)+/.exec(line),
1442
				lineClass = 'alt' + (i % 2 == 0 ? 1 : 2),
1443
				lineNumber = sh.utils.padNumber(firstLine + i, padLength),
1444
				highlighted = sh.utils.indexOf(highlightedLines, (firstLine + i).toString()) != -1,
1445
				spaces = null
1446
				;
1447

    
1448
			if (indent != null)
1449
			{
1450
				spaces = indent[0].toString();
1451
				line = line.substr(spaces.length);
1452
			}
1453

    
1454
			line = sh.utils.trim(line);
1455
			
1456
			if (line.length == 0)
1457
				line = '&nbsp;';
1458
			
1459
			if (highlighted)
1460
				lineClass += ' highlighted';
1461
			
1462
			code += 
1463
				'<div class="line ' + lineClass + '">'
1464
					+ '<table>'
1465
						+ '<tr>'
1466
							+ (hasGutter ? '<td class="number"><code>' + lineNumber + '</code></td>' : '')
1467
							+ '<td class="content">'
1468
								+ (spaces != null ? '<code class="spaces">' + spaces.replace(' ', '&nbsp;') + '</code>' : '')
1469
								+ line
1470
							+ '</td>'
1471
						+ '</tr>'
1472
					+ '</table>'
1473
				+ '</div>'
1474
				;
1475
		}
1476
		
1477
		return code;
1478
	},
1479
	
1480
	/**
1481
	 * Finds all matches in the source code.
1482
	 * @param {String} code		Source code to process matches in.
1483
	 * @param {Array} matches	Discovered regex matches.
1484
	 * @return {String} Returns formatted HTML with processed mathes.
1485
	 */
1486
	processMatches: function(code, matches)
1487
	{
1488
		var pos = 0, 
1489
			result = '',
1490
			decorate = sh.utils.decorate, // make an alias to save some bytes
1491
			brushName = this.getParam('brush-name', '')
1492
			;
1493
		
1494
		function getBrushNameCss(match)
1495
		{
1496
			var result = match ? (match.brushName || brushName) : brushName;
1497
			return result ? result + ' ' : '';
1498
		};
1499
		
1500
		// Finally, go through the final list of matches and pull the all
1501
		// together adding everything in between that isn't a match.
1502
		for (var i = 0; i < matches.length; i++) 
1503
		{
1504
			var match = matches[i],
1505
				matchBrushName
1506
				;
1507
			
1508
			if (match === null || match.length === 0) 
1509
				continue;
1510
			
1511
			matchBrushName = getBrushNameCss(match);
1512
			
1513
			result += decorate(code.substr(pos, match.index - pos), matchBrushName + 'plain')
1514
					+ decorate(match.value, matchBrushName + match.css)
1515
					;
1516

    
1517
			pos = match.index + match.length;
1518
		}
1519

    
1520
		// don't forget to add whatever's remaining in the string
1521
		result += decorate(code.substr(pos), getBrushNameCss() + 'plain');
1522

    
1523
		return result;
1524
	},
1525
	
1526
	/**
1527
	 * Highlights the code and returns complete HTML.
1528
	 * @param {String} code     Code to highlight.
1529
	 * @param {Object} params   Parameters object.
1530
	 */
1531
	highlight: function(code, params)
1532
	{
1533
		// using variables for shortcuts because JS compressor will shorten local variable names
1534
		var conf = sh.config,
1535
			vars = sh.vars,
1536
			div,
1537
			divClassName,
1538
			tabSize,
1539
			important = 'important'
1540
			;
1541

    
1542
		this.params = {};
1543
		this.div = null;
1544
		this.lines = null;
1545
		this.code = null;
1546
		this.bar = null;
1547
		this.toolbarCommands = {};
1548
		this.id = sh.utils.guid('highlighter_');
1549

    
1550
		// register this instance in the highlighters list
1551
		vars.highlighters[this.id] = this;
1552

    
1553
		if (code === null) 
1554
			code = '';
1555
		
1556
		// local params take precedence over defaults
1557
		this.params = sh.utils.merge(sh.defaults, params || {});
1558

    
1559
		// process light mode
1560
		if (this.getParam('light') == true)
1561
			this.params.toolbar = this.params.gutter = false;
1562
		
1563
		this.div = div = this.create('DIV');
1564
		this.lines = this.create('DIV');
1565
		this.lines.className = 'lines';
1566

    
1567
		className = 'syntaxhighlighter';
1568
		div.id = this.id;
1569
		
1570
		// make collapsed
1571
		if (this.getParam('collapse'))
1572
			className += ' collapsed';
1573
		
1574
		// disable gutter
1575
		if (this.getParam('gutter') == false)
1576
			className += ' nogutter';
1577
		
1578
		// disable line wrapping
1579
		if (this.getParam('wrap-lines') == false)
1580
		 	this.lines.className += ' no-wrap';
1581

    
1582
		// add custom user style name
1583
		className += ' ' + this.getParam('class-name');
1584
		
1585
		// add brush alias to the class name for custom CSS
1586
		className += ' ' + this.getParam('brush-name');
1587
		
1588
		div.className = className;
1589
		
1590
		this.originalCode = code;
1591
		this.code = sh.utils.trimFirstAndLastLines(code)
1592
			.replace(/\r/g, ' ') // IE lets these buggers through
1593
			;
1594
		
1595
		tabSize = this.getParam('tab-size');
1596
		
1597
		// replace tabs with spaces
1598
		this.code = this.getParam('smart-tabs') == true
1599
			? sh.utils.processSmartTabs(this.code, tabSize)
1600
			: sh.utils.processTabs(this.code, tabSize)
1601
			;
1602

    
1603
		this.code = sh.utils.unindent(this.code);
1604

    
1605
		// add controls toolbar
1606
		if (this.getParam('toolbar')) 
1607
		{
1608
			this.bar = this.create('DIV');
1609
			this.bar.className = 'bar';
1610
			this.bar.appendChild(sh.toolbar.create(this));
1611
			div.appendChild(this.bar);
1612
			
1613
			// set up toolbar rollover
1614
			var bar = this.bar;
1615
			function hide() { bar.className = bar.className.replace('show', ''); }
1616
			div.onmouseover = function() { hide(); bar.className += ' show'; };
1617
			div.onmouseout = function() { hide(); }
1618
		}
1619
		
1620
		div.appendChild(this.lines);
1621
	
1622
		this.matches = this.findMatches(this.regexList, this.code);
1623
		this.removeNestedMatches();
1624
		
1625
		code = this.processMatches(this.code, this.matches);
1626
		
1627
		// finally, split all lines so that they wrap well
1628
		code = this.createDisplayLines(sh.utils.trim(code));
1629
		
1630
		// finally, process the links
1631
		if (this.getParam('auto-links'))
1632
			code = sh.utils.processUrls(code);
1633

    
1634
		this.lines.innerHTML = code;
1635
	},
1636
	
1637
	/**
1638
	 * Converts space separated list of keywords into a regular expression string.
1639
	 * @param {String} str    Space separated keywords.
1640
	 * @return {String}       Returns regular expression string.
1641
	 */	
1642
	getKeywords: function(str)
1643
	{
1644
		str = str
1645
			.replace(/^\s+|\s+$/g, '')
1646
			.replace(/\s+/g, '|')
1647
			;
1648
		
1649
		return '\\b(?:' + str + ')\\b';
1650
	},
1651
	
1652
	/**
1653
	 * Makes a brush compatible with the `html-script` functionality.
1654
	 * @param {Object} regexGroup Object containing `left` and `right` regular expressions.
1655
	 */
1656
	forHtmlScript: function(regexGroup)
1657
	{
1658
		this.htmlScript = {
1659
			left : { regex: regexGroup.left, css: 'script' },
1660
			right : { regex: regexGroup.right, css: 'script' },
1661
			code : new XRegExp(
1662
				"(?<left>" + regexGroup.left.source + ")" +
1663
				"(?<code>.*?)" +
1664
				"(?<right>" + regexGroup.right.source + ")",
1665
				"sgi"
1666
				)
1667
		};
1668
	}
1669
}; // end of Highlighter
1670

    
1671
return sh;
1672
}(); // end of anonymous function
1673

    
1674

    
1675
/**
1676
 * XRegExp 0.6.1
1677
 * (c) 2007-2008 Steven Levithan
1678
 * <http://stevenlevithan.com/regex/xregexp/>
1679
 * MIT License
1680
 * 
1681
 * provides an augmented, cross-browser implementation of regular expressions
1682
 * including support for additional modifiers and syntax. several convenience
1683
 * methods and a recursive-construct parser are also included.
1684
 */
1685

    
1686
// prevent running twice, which would break references to native globals
1687
if (!window.XRegExp) {
1688
// anonymous function to avoid global variables
1689
(function () {
1690
// copy various native globals for reference. can't use the name ``native``
1691
// because it's a reserved JavaScript keyword.
1692
var real = {
1693
        exec:    RegExp.prototype.exec,
1694
        match:   String.prototype.match,
1695
        replace: String.prototype.replace,
1696
        split:   String.prototype.split
1697
    },
1698
    /* regex syntax parsing with support for all the necessary cross-
1699
       browser and context issues (escapings, character classes, etc.) */
1700
    lib = {
1701
        part:       /(?:[^\\([#\s.]+|\\(?!k<[\w$]+>|[pP]{[^}]+})[\S\s]?|\((?=\?(?!#|<[\w$]+>)))+|(\()(?:\?(?:(#)[^)]*\)|<([$\w]+)>))?|\\(?:k<([\w$]+)>|[pP]{([^}]+)})|(\[\^?)|([\S\s])/g,
1702
        replaceVar: /(?:[^$]+|\$(?![1-9$&`']|{[$\w]+}))+|\$(?:([1-9]\d*|[$&`'])|{([$\w]+)})/g,
1703
        extended:   /^(?:\s+|#.*)+/,
1704
        quantifier: /^(?:[?*+]|{\d+(?:,\d*)?})/,
1705
        classLeft:  /&&\[\^?/g,
1706
        classRight: /]/g
1707
    },
1708
    indexOf = function (array, item, from) {
1709
        for (var i = from || 0; i < array.length; i++)
1710
            if (array[i] === item) return i;
1711
        return -1;
1712
    },
1713
    brokenExecUndef = /()??/.exec("")[1] !== undefined,
1714
    plugins = {};
1715

    
1716
/**
1717
 * Accepts a pattern and flags, returns a new, extended RegExp object.
1718
 * differs from a native regex in that additional flags and syntax are
1719
 * supported and browser inconsistencies are ameliorated.
1720
 * @ignore
1721
 */
1722
XRegExp = function (pattern, flags) {
1723
    if (pattern instanceof RegExp) {
1724
        if (flags !== undefined)
1725
            throw TypeError("can't supply flags when constructing one RegExp from another");
1726
        return pattern.addFlags(); // new copy
1727
    }
1728

    
1729
    var flags           = flags || "",
1730
        singleline      = flags.indexOf("s") > -1,
1731
        extended        = flags.indexOf("x") > -1,
1732
        hasNamedCapture = false,
1733
        captureNames    = [],
1734
        output          = [],
1735
        part            = lib.part,
1736
        match, cc, len, index, regex;
1737

    
1738
    part.lastIndex = 0; // in case the last XRegExp compilation threw an error (unbalanced character class)
1739

    
1740
    while (match = real.exec.call(part, pattern)) {
1741
        // comment pattern. this check must come before the capturing group check,
1742
        // because both match[1] and match[2] will be non-empty.
1743
        if (match[2]) {
1744
            // keep tokens separated unless the following token is a quantifier
1745
            if (!lib.quantifier.test(pattern.slice(part.lastIndex)))
1746
                output.push("(?:)");
1747
        // capturing group
1748
        } else if (match[1]) {
1749
            captureNames.push(match[3] || null);
1750
            if (match[3])
1751
                hasNamedCapture = true;
1752
            output.push("(");
1753
        // named backreference
1754
        } else if (match[4]) {
1755
            index = indexOf(captureNames, match[4]);
1756
            // keep backreferences separate from subsequent literal numbers
1757
            // preserve backreferences to named groups that are undefined at this point as literal strings
1758
            output.push(index > -1 ?
1759
                "\\" + (index + 1) + (isNaN(pattern.charAt(part.lastIndex)) ? "" : "(?:)") :
1760
                match[0]
1761
            );
1762
        // unicode element (requires plugin)
1763
        } else if (match[5]) {
1764
            output.push(plugins.unicode ?
1765
                plugins.unicode.get(match[5], match[0].charAt(1) === "P") :
1766
                match[0]
1767
            );
1768
        // character class opening delimiter ("[" or "[^")
1769
        // (non-native unicode elements are not supported within character classes)
1770
        } else if (match[6]) {
1771
            if (pattern.charAt(part.lastIndex) === "]") {
1772
                // for cross-browser compatibility with ECMA-262 v3 behavior,
1773
                // convert [] to (?!) and [^] to [\S\s].
1774
                output.push(match[6] === "[" ? "(?!)" : "[\\S\\s]");
1775
                part.lastIndex++;
1776
            } else {
1777
                // parse the character class with support for inner escapes and
1778
                // ES4's infinitely nesting intersection syntax ([&&[^&&[]]]).
1779
                cc = XRegExp.matchRecursive("&&" + pattern.slice(match.index), lib.classLeft, lib.classRight, "", {escapeChar: "\\"})[0];
1780
                output.push(match[6] + cc + "]");
1781
                part.lastIndex += cc.length + 1;
1782
            }
1783
        // dot ("."), pound sign ("#"), or whitespace character
1784
        } else if (match[7]) {
1785
            if (singleline && match[7] === ".") {
1786
                output.push("[\\S\\s]");
1787
            } else if (extended && lib.extended.test(match[7])) {
1788
                len = real.exec.call(lib.extended, pattern.slice(part.lastIndex - 1))[0].length;
1789
                // keep tokens separated unless the following token is a quantifier
1790
                if (!lib.quantifier.test(pattern.slice(part.lastIndex - 1 + len)))
1791
                    output.push("(?:)");
1792
                part.lastIndex += len - 1;
1793
            } else {
1794
                output.push(match[7]);
1795
            }
1796
        } else {
1797
            output.push(match[0]);
1798
        }
1799
    }
1800

    
1801
    regex = RegExp(output.join(""), real.replace.call(flags, /[sx]+/g, ""));
1802
    regex._x = {
1803
        source:       pattern,
1804
        captureNames: hasNamedCapture ? captureNames : null
1805
    };
1806
    return regex;
1807
};
1808

    
1809
/**
1810
 * Barebones plugin support for now (intentionally undocumented)
1811
 * @ignore
1812
 * @param {Object} name
1813
 * @param {Object} o
1814
 */
1815
XRegExp.addPlugin = function (name, o) {
1816
    plugins[name] = o;
1817
};
1818

    
1819
/**
1820
 * Adds named capture support, with values returned as ``result.name``.
1821
 * 
1822
 * Also fixes two cross-browser issues, following the ECMA-262 v3 spec:
1823
 *  - captured values for non-participating capturing groups should be returned
1824
 *    as ``undefined``, rather than the empty string.
1825
 *  - the regex's ``lastIndex`` should not be incremented after zero-length
1826
 *    matches.
1827
 * @ignore
1828
 */
1829
RegExp.prototype.exec = function (str) {
1830
    var match = real.exec.call(this, str),
1831
        name, i, r2;
1832
    if (match) {
1833
        // fix browsers whose exec methods don't consistently return
1834
        // undefined for non-participating capturing groups
1835
        if (brokenExecUndef && match.length > 1) {
1836
            // r2 doesn't need /g or /y, but they shouldn't hurt
1837
            r2 = new RegExp("^" + this.source + "$(?!\\s)", this.getNativeFlags());
1838
            real.replace.call(match[0], r2, function () {
1839
                for (i = 1; i < arguments.length - 2; i++) {
1840
                    if (arguments[i] === undefined) match[i] = undefined;
1841
                }
1842
            });
1843
        }
1844
        // attach named capture properties
1845
        if (this._x && this._x.captureNames) {
1846
            for (i = 1; i < match.length; i++) {
1847
                name = this._x.captureNames[i - 1];
1848
                if (name) match[name] = match[i];
1849
            }
1850
        }
1851
        // fix browsers that increment lastIndex after zero-length matches
1852
        if (this.global && this.lastIndex > (match.index + match[0].length))
1853
            this.lastIndex--;
1854
    }
1855
    return match;
1856
};
1857
})(); // end anonymous function
1858
} // end if(!window.XRegExp)
1859

    
1860
/**
1861
 * intentionally undocumented
1862
 * @ignore
1863
 */
1864
RegExp.prototype.getNativeFlags = function () {
1865
    return (this.global     ? "g" : "") +
1866
           (this.ignoreCase ? "i" : "") +
1867
           (this.multiline  ? "m" : "") +
1868
           (this.extended   ? "x" : "") +
1869
           (this.sticky     ? "y" : "");
1870
};
1871

    
1872
/**
1873
 * Accepts flags; returns a new XRegExp object generated by recompiling
1874
 * the regex with the additional flags (may include non-native flags).
1875
 * The original regex object is not altered.
1876
 * @ignore
1877
 */
1878
RegExp.prototype.addFlags = function (flags) {
1879
    var regex = new XRegExp(this.source, (flags || "") + this.getNativeFlags());
1880
    if (this._x) {
1881
        regex._x = {
1882
            source:       this._x.source,
1883
            captureNames: this._x.captureNames ? this._x.captureNames.slice(0) : null
1884
        };
1885
    }
1886
    return regex;
1887
};
1888

    
1889
/**
1890
 * Accepts a context object and string; returns the result of calling
1891
 * ``exec`` with the provided string. the context is ignored but is
1892
 * accepted for congruity with ``Function.prototype.call``.
1893
 * @ignore
1894
 */
1895
RegExp.prototype.call = function (context, str) {
1896
    return this.exec(str);
1897
};
1898

    
1899
/**
1900
 * Accepts a context object and arguments array; returns the result of
1901
 * calling ``exec`` with the first value in the arguments array. the context
1902
 * is ignored but is accepted for congruity with ``Function.prototype.apply``.
1903
 * @ignore
1904
 */
1905
RegExp.prototype.apply = function (context, args) {
1906
    return this.exec(args[0]);
1907
};
1908

    
1909
/**
1910
 * Accepts a pattern and flags; returns an XRegExp object. if the pattern
1911
 * and flag combination has previously been cached, the cached copy is
1912
 * returned, otherwise the new object is cached.
1913
 * @ignore
1914
 */
1915
XRegExp.cache = function (pattern, flags) {
1916
    var key = "/" + pattern + "/" + (flags || "");
1917
    return XRegExp.cache[key] || (XRegExp.cache[key] = new XRegExp(pattern, flags));
1918
};
1919

    
1920
/**
1921
 * Accepts a string; returns the string with regex metacharacters escaped.
1922
 * the returned string can safely be used within a regex to match a literal
1923
 * string. escaped characters are [, ], {, }, (, ), -, *, +, ?, ., \, ^, $,
1924
 * |, #, [comma], and whitespace.
1925
 * @ignore
1926
 */
1927
XRegExp.escape = function (str) {
1928
    return str.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, "\\$&");
1929
};
1930

    
1931
/**
1932
 * Accepts a string to search, left and right delimiters as regex pattern
1933
 * strings, optional regex flags (may include non-native s, x, and y flags),
1934
 * and an options object which allows setting an escape character and changing
1935
 * the return format from an array of matches to a two-dimensional array of
1936
 * string parts with extended position data. returns an array of matches
1937
 * (optionally with extended data), allowing nested instances of left and right
1938
 * delimiters. use the g flag to return all matches, otherwise only the first
1939
 * is returned. if delimiters are unbalanced within the subject data, an error
1940
 * is thrown.
1941
 * 
1942
 * This function admittedly pushes the boundaries of what can be accomplished
1943
 * sensibly without a "real" parser. however, by doing so it provides flexible
1944
 * and powerful recursive parsing capabilities with minimal code weight.
1945
 * 
1946
 * Warning: the ``escapeChar`` option is considered experimental and might be
1947
 * changed or removed in future versions of XRegExp.
1948
 * 
1949
 * unsupported features:
1950
 *  - backreferences within delimiter patterns when using ``escapeChar``.
1951
 *  - although providing delimiters as regex objects adds the minor feature of
1952
 *    independent delimiter flags, it introduces other limitations and is only
1953
 *    intended to be done by the ``XRegExp`` constructor (which can't call
1954
 *    itself while building a regex).
1955
 * 
1956
 * @ignore
1957
 */
1958
XRegExp.matchRecursive = function (str, left, right, flags, options) {
1959
    var options      = options || {},
1960
        escapeChar   = options.escapeChar,
1961
        vN           = options.valueNames,
1962
        flags        = flags || "",
1963
        global       = flags.indexOf("g") > -1,
1964
        ignoreCase   = flags.indexOf("i") > -1,
1965
        multiline    = flags.indexOf("m") > -1,
1966
        sticky       = flags.indexOf("y") > -1,
1967
        /* sticky mode has its own handling in this function, which means you
1968
           can use flag "y" even in browsers which don't support it natively */
1969
        flags        = flags.replace(/y/g, ""),
1970
        left         = left  instanceof RegExp ? (left.global  ? left  : left.addFlags("g"))  : new XRegExp(left,  "g" + flags),
1971
        right        = right instanceof RegExp ? (right.global ? right : right.addFlags("g")) : new XRegExp(right, "g" + flags),
1972
        output       = [],
1973
        openTokens   = 0,
1974
        delimStart   = 0,
1975
        delimEnd     = 0,
1976
        lastOuterEnd = 0,
1977
        outerStart, innerStart, leftMatch, rightMatch, escaped, esc;
1978

    
1979
    if (escapeChar) {
1980
        if (escapeChar.length > 1) throw SyntaxError("can't supply more than one escape character");
1981
        if (multiline)             throw TypeError("can't supply escape character when using the multiline flag");
1982
        escaped = XRegExp.escape(escapeChar);
1983
        /* Escape pattern modifiers:
1984
            /g - not needed here
1985
            /i - included
1986
            /m - **unsupported**, throws error
1987
            /s - handled by XRegExp when delimiters are provided as strings
1988
            /x - handled by XRegExp when delimiters are provided as strings
1989
            /y - not needed here; supported by other handling in this function
1990
        */
1991
        esc = new RegExp(
1992
            "^(?:" + escaped + "[\\S\\s]|(?:(?!" + left.source + "|" + right.source + ")[^" + escaped + "])+)+",
1993
            ignoreCase ? "i" : ""
1994
        );
1995
    }
1996

    
1997
    while (true) {
1998
        /* advance the starting search position to the end of the last delimiter match.
1999
           a couple special cases are also covered:
2000
            - if using an escape character, advance to the next delimiter's starting position,
2001
              skipping any escaped characters
2002
            - first time through, reset lastIndex in case delimiters were provided as regexes
2003
        */
2004
        left.lastIndex = right.lastIndex = delimEnd +
2005
            (escapeChar ? (esc.exec(str.slice(delimEnd)) || [""])[0].length : 0);
2006

    
2007
        leftMatch  = left.exec(str);
2008
        rightMatch = right.exec(str);
2009

    
2010
        // only keep the result which matched earlier in the string
2011
        if (leftMatch && rightMatch) {
2012
            if (leftMatch.index <= rightMatch.index)
2013
                 rightMatch = null;
2014
            else leftMatch  = null;
2015
        }
2016

    
2017
        /* paths*:
2018
        leftMatch | rightMatch | openTokens | result
2019
        1         | 0          | 1          | ...
2020
        1         | 0          | 0          | ...
2021
        0         | 1          | 1          | ...
2022
        0         | 1          | 0          | throw
2023
        0         | 0          | 1          | throw
2024
        0         | 0          | 0          | break
2025
        * - does not include the sticky mode special case
2026
          - the loop ends after the first completed match if not in global mode
2027
        */
2028

    
2029
        if (leftMatch || rightMatch) {
2030
            delimStart = (leftMatch || rightMatch).index;
2031
            delimEnd   = (leftMatch ? left : right).lastIndex;
2032
        } else if (!openTokens) {
2033
            break;
2034
        }
2035

    
2036
        if (sticky && !openTokens && delimStart > lastOuterEnd)
2037
            break;
2038

    
2039
        if (leftMatch) {
2040
            if (!openTokens++) {
2041
                outerStart = delimStart;
2042
                innerStart = delimEnd;
2043
            }
2044
        } else if (rightMatch && openTokens) {
2045
            if (!--openTokens) {
2046
                if (vN) {
2047
                    if (vN[0] && outerStart > lastOuterEnd)
2048
                               output.push([vN[0], str.slice(lastOuterEnd, outerStart), lastOuterEnd, outerStart]);
2049
                    if (vN[1]) output.push([vN[1], str.slice(outerStart,   innerStart), outerStart,   innerStart]);
2050
                    if (vN[2]) output.push([vN[2], str.slice(innerStart,   delimStart), innerStart,   delimStart]);
2051
                    if (vN[3]) output.push([vN[3], str.slice(delimStart,   delimEnd),   delimStart,   delimEnd]);
2052
                } else {
2053
                    output.push(str.slice(innerStart, delimStart));
2054
                }
2055
                lastOuterEnd = delimEnd;
2056
                if (!global)
2057
                    break;
2058
            }
2059
        } else {
2060
            // reset lastIndex in case delimiters were provided as regexes
2061
            left.lastIndex = right.lastIndex = 0;
2062
            throw Error("subject data contains unbalanced delimiters");
2063
        }
2064

    
2065
        // if the delimiter matched an empty string, advance delimEnd to avoid an infinite loop
2066
        if (delimStart === delimEnd)
2067
            delimEnd++;
2068
    }
2069

    
2070
    if (global && !sticky && vN && vN[0] && str.length > lastOuterEnd)
2071
        output.push([vN[0], str.slice(lastOuterEnd), lastOuterEnd, str.length]);
2072

    
2073
    // reset lastIndex in case delimiters were provided as regexes
2074
    left.lastIndex = right.lastIndex = 0;
2075

    
2076
    return output;
2077
};
2078
/**
2079
 * SyntaxHighlighter
2080
 * http://alexgorbatchev.com/
2081
 *
2082
 * SyntaxHighlighter is donationware. If you are using it, please donate.
2083
 * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate
2084
 *
2085
 * @version
2086
 * 2.0.320 (May 03 2009)
2087
 * 
2088
 * @copyright
2089
 * Copyright (C) 2004-2009 Alex Gorbatchev.
2090
 *
2091
 * @license
2092
 * This file is part of SyntaxHighlighter.
2093
 * 
2094
 * SyntaxHighlighter is free software: you can redistribute it and/or modify
2095
 * it under the terms of the GNU Lesser General Public License as published by
2096
 * the Free Software Foundation, either version 3 of the License, or
2097
 * (at your option) any later version.
2098
 * 
2099
 * SyntaxHighlighter is distributed in the hope that it will be useful,
2100
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
2101
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2102
 * GNU General Public License for more details.
2103
 * 
2104
 * You should have received a copy of the GNU General Public License
2105
 * along with SyntaxHighlighter.  If not, see <http://www.gnu.org/copyleft/lesser.html>.
2106
 */
2107
SyntaxHighlighter.brushes.Xml = function()
2108
{
2109
	function process(match, regexInfo)
2110
	{
2111
		var constructor = SyntaxHighlighter.Match,
2112
			code = match[0],
2113
			tag = new XRegExp('(&lt;|<)[\\s\\/\\?]*(?<name>[:\\w-\\.]+)', 'xg').exec(code),
2114
			result = []
2115
			;
2116
		
2117
		if (match.attributes != null) 
2118
		{
2119
			var attributes,
2120
				regex = new XRegExp('(?<name> [\\w:\\-\\.]+)' +
2121
									'\\s*=\\s*' +
2122
									'(?<value> ".*?"|\'.*?\'|\\w+)',
2123
									'xg');
2124

    
2125
			while ((attributes = regex.exec(code)) != null) 
2126
			{
2127
				result.push(new constructor(attributes.name, match.index + attributes.index, 'color1'));
2128
				result.push(new constructor(attributes.value, match.index + attributes.index + attributes[0].indexOf(attributes.value), 'string'));
2129
			}
2130
		}
2131

    
2132
		if (tag != null)
2133
			result.push(
2134
				new constructor(tag.name, match.index + tag[0].indexOf(tag.name), 'keyword')
2135
			);
2136

    
2137
		return result;
2138
	}
2139
	
2140
	this.regexList = [
2141
		{ regex: new XRegExp('(\\&lt;|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\\&gt;|>)', 'gm'),			css: 'color2' },	// <![ ... [ ... ]]>
2142
		{ regex: new XRegExp('(\\&lt;|<)!--\\s*.*?\\s*--(\\&gt;|>)', 'gm'),								css: 'comments' },	// <!-- ... -->
2143
		{ regex: new XRegExp('(&lt;|<)[\\s\\/\\?]*(\\w+)(?<attributes>.*?)[\\s\\/\\?]*(&gt;|>)', 'sg'), func: process }
2144
	];
2145
};
2146

    
2147
SyntaxHighlighter.brushes.Xml.prototype	= new SyntaxHighlighter.Highlighter();
2148
SyntaxHighlighter.brushes.Xml.aliases	= ['xml', 'xhtml', 'xslt', 'html', 'xhtml'];
2149
/**
2150
 * SyntaxHighlighter
2151
 * http://alexgorbatchev.com/
2152
 *
2153
 * SyntaxHighlighter is donationware. If you are using it, please donate.
2154
 * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate
2155
 *
2156
 * @version
2157
 * 2.0.320 (May 03 2009)
2158
 * 
2159
 * @copyright
2160
 * Copyright (C) 2004-2009 Alex Gorbatchev.
2161
 *
2162
 * @license
2163
 * This file is part of SyntaxHighlighter.
2164
 * 
2165
 * SyntaxHighlighter is free software: you can redistribute it and/or modify
2166
 * it under the terms of the GNU Lesser General Public License as published by
2167
 * the Free Software Foundation, either version 3 of the License, or
2168
 * (at your option) any later version.
2169
 * 
2170
 * SyntaxHighlighter is distributed in the hope that it will be useful,
2171
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
2172
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2173
 * GNU General Public License for more details.
2174
 * 
2175
 * You should have received a copy of the GNU General Public License
2176
 * along with SyntaxHighlighter.  If not, see <http://www.gnu.org/copyleft/lesser.html>.
2177
 */
2178
SyntaxHighlighter.brushes.JScript = function()
2179
{
2180
	var keywords =	'break case catch continue ' +
2181
					'default delete do else false  ' +
2182
					'for function if in instanceof ' +
2183
					'new null return super switch ' +
2184
					'this throw true try typeof var while with'
2185
					;
2186

    
2187
	this.regexList = [
2188
		{ regex: SyntaxHighlighter.regexLib.singleLineCComments,	css: 'comments' },			// one line comments
2189
		{ regex: SyntaxHighlighter.regexLib.multiLineCComments,		css: 'comments' },			// multiline comments
2190
		{ regex: SyntaxHighlighter.regexLib.doubleQuotedString,		css: 'string' },			// double quoted strings
2191
		{ regex: SyntaxHighlighter.regexLib.singleQuotedString,		css: 'string' },			// single quoted strings
2192
		{ regex: /\s*#.*/gm,										css: 'preprocessor' },		// preprocessor tags like #region and #endregion
2193
		{ regex: new RegExp(this.getKeywords(keywords), 'gm'),		css: 'keyword' }			// keywords
2194
		];
2195
	
2196
	this.forHtmlScript(SyntaxHighlighter.regexLib.scriptScriptTags);
2197
};
2198

    
2199
SyntaxHighlighter.brushes.JScript.prototype	= new SyntaxHighlighter.Highlighter();
2200
SyntaxHighlighter.brushes.JScript.aliases	= ['js', 'jscript', 'javascript'];
2201

    
2202

    
2203
SyntaxHighlighter.config.clipboardSwf = 'syntax/clipboard.swf';
2204
$(function () {
2205
	var divs = $([]);
2206
	$("#container .source").each(function () {
2207
		var code = $(this).html().replace(/</g,'&lt;').replace(/>/g,'&gt;'),
2208
			div  = $('<div class="code"><pre class="brush:' + ( $(this).is("script") ? 'js' : 'xml' ) + ';">' + code + '</pre></div>'),
2209
			demo = $(this).prevAll(".demo:eq(0)");
2210
		$(this).after(div);
2211
		divs = divs.add(div);
2212
	});
2213
	SyntaxHighlighter.all();
2214

    
2215
	setTimeout((function (divs) { 
2216
		return function () {
2217
			divs.each(function () {
2218
				var div		= $(this),
2219
					demo	= $(this).prevAll(".demo:eq(0)"),
2220
					h		= false;
2221
				var h = Math.max(demo[0].offsetHeight, div[0].offsetHeight);
2222
				if(h) {
2223
					if(h < 198) h = 198;
2224
					div.height(h);
2225
					demo.height(h);
2226
				}
2227
			});
2228
		}
2229
	})(divs), 500);
2230

    
2231
	// $(".panel").hide().prev().click(function () { $(this).next().toggle(); }).css("cursor","pointer");
2232
});
(1-1/9)