Project

General

Profile

1 5703 leinfelder
/**
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
});