You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2232 lines
64 KiB
2232 lines
64 KiB
/** |
|
* SyntaxHighlighter |
|
* http://alexgorbatchev.com/ |
|
* |
|
* SyntaxHighlighter is donationware. If you are using it, please donate. |
|
* http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate |
|
* |
|
* @version |
|
* 2.1.364 (October 15 2009) |
|
* |
|
* @copyright |
|
* Copyright (C) 2004-2009 Alex Gorbatchev. |
|
* |
|
* @license |
|
* This file is part of SyntaxHighlighter. |
|
* |
|
* SyntaxHighlighter is free software: you can redistribute it and/or modify |
|
* it under the terms of the GNU Lesser General Public License as published by |
|
* the Free Software Foundation, either version 3 of the License, or |
|
* (at your option) any later version. |
|
* |
|
* SyntaxHighlighter is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with SyntaxHighlighter. If not, see <http://www.gnu.org/copyleft/lesser.html>. |
|
*/ |
|
// |
|
// Begin anonymous function. This is used to contain local scope variables without polutting global scope. |
|
// |
|
if (!window.SyntaxHighlighter) var SyntaxHighlighter = function() { |
|
|
|
// Shortcut object which will be assigned to the SyntaxHighlighter variable. |
|
// This is a shorthand for local reference in order to avoid long namespace |
|
// references to SyntaxHighlighter.whatever... |
|
var sh = { |
|
defaults : { |
|
/** Additional CSS class names to be added to highlighter elements. */ |
|
'class-name' : '', |
|
|
|
/** First line number. */ |
|
'first-line' : 1, |
|
|
|
/** |
|
* Pads line numbers. Possible values are: |
|
* |
|
* false - don't pad line numbers. |
|
* true - automaticaly pad numbers with minimum required number of leading zeroes. |
|
* [int] - length up to which pad line numbers. |
|
*/ |
|
'pad-line-numbers' : true, |
|
|
|
/** Lines to highlight. */ |
|
'highlight' : null, |
|
|
|
/** Enables or disables smart tabs. */ |
|
'smart-tabs' : true, |
|
|
|
/** Gets or sets tab size. */ |
|
'tab-size' : 4, |
|
|
|
/** Enables or disables gutter. */ |
|
'gutter' : true, |
|
|
|
/** Enables or disables toolbar. */ |
|
'toolbar' : true, |
|
|
|
/** Forces code view to be collapsed. */ |
|
'collapse' : false, |
|
|
|
/** Enables or disables automatic links. */ |
|
'auto-links' : true, |
|
|
|
/** Gets or sets light mode. Equavalent to turning off gutter and toolbar. */ |
|
'light' : false, |
|
|
|
/** Enables or disables automatic line wrapping. */ |
|
'wrap-lines' : true, |
|
|
|
'html-script' : false |
|
}, |
|
|
|
config : { |
|
/** Enables use of <SCRIPT type="syntaxhighlighter" /> tags. */ |
|
useScriptTags : true, |
|
|
|
/** Path to the copy to clipboard SWF file. */ |
|
clipboardSwf : null, |
|
|
|
/** Width of an item in the toolbar. */ |
|
toolbarItemWidth : 16, |
|
|
|
/** Height of an item in the toolbar. */ |
|
toolbarItemHeight : 16, |
|
|
|
/** Blogger mode flag. */ |
|
bloggerMode : false, |
|
|
|
stripBrs : false, |
|
|
|
/** Name of the tag that SyntaxHighlighter will automatically look for. */ |
|
tagName : 'pre', |
|
|
|
strings : { |
|
expandSource : 'show source', |
|
viewSource : 'view source', |
|
copyToClipboard : 'copy to clipboard', |
|
copyToClipboardConfirmation : 'The code is in your clipboard now', |
|
print : 'print', |
|
help : '?', |
|
alert: 'SyntaxHighlighter\n\n', |
|
noBrush : 'Can\'t find brush for: ', |
|
brushNotHtmlScript : 'Brush wasn\'t configured for html-script option: ', |
|
|
|
// this is populated by the build script |
|
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>' |
|
}, |
|
|
|
/** If true, output will show HTML produces instead. */ |
|
debug : false |
|
}, |
|
|
|
/** Internal 'global' variables. */ |
|
vars : { |
|
discoveredBrushes : null, |
|
spaceWidth : null, |
|
printFrame : null, |
|
highlighters : {} |
|
}, |
|
|
|
/** This object is populated by user included external brush files. */ |
|
brushes : {}, |
|
|
|
/** Common regular expressions. */ |
|
regexLib : { |
|
multiLineCComments : /\/\*[\s\S]*?\*\//gm, |
|
singleLineCComments : /\/\/.*$/gm, |
|
singleLinePerlComments : /#.*$/gm, |
|
doubleQuotedString : /"([^\\"\n]|\\.)*"/g, |
|
singleQuotedString : /'([^\\'\n]|\\.)*'/g, |
|
multiLineDoubleQuotedString : /"([^\\"]|\\.)*"/g, |
|
multiLineSingleQuotedString : /'([^\\']|\\.)*'/g, |
|
xmlComments : /(<|<)!--[\s\S]*?--(>|>)/gm, |
|
url : /<\w+:\/\/[\w-.\/?%&=@:;]*>|\w+:\/\/[\w-.\/?%&=@:;]*/g, |
|
|
|
/** <?= ?> tags. */ |
|
phpScriptTags : { left: /(<|<)\?=?/g, right: /\?(>|>)/g }, |
|
|
|
/** <%= %> tags. */ |
|
aspScriptTags : { left: /(<|<)%=?/g, right: /%(>|>)/g }, |
|
|
|
/** <script></script> tags. */ |
|
scriptScriptTags : { left: /(<|<)\s*script.*?(>|>)/gi, right: /(<|<)\/\s*script\s*(>|>)/gi } |
|
}, |
|
|
|
toolbar : { |
|
/** |
|
* Creates new toolbar for a highlighter. |
|
* @param {Highlighter} highlighter Target highlighter. |
|
*/ |
|
create : function(highlighter) |
|
{ |
|
var div = document.createElement('DIV'), |
|
items = sh.toolbar.items |
|
; |
|
|
|
div.className = 'toolbar'; |
|
|
|
for (var name in items) |
|
{ |
|
var constructor = items[name], |
|
command = new constructor(highlighter), |
|
element = command.create() |
|
; |
|
|
|
highlighter.toolbarCommands[name] = command; |
|
|
|
if (element == null) |
|
continue; |
|
|
|
if (typeof(element) == 'string') |
|
element = sh.toolbar.createButton(element, highlighter.id, name); |
|
|
|
element.className += 'item ' + name; |
|
div.appendChild(element); |
|
} |
|
|
|
return div; |
|
}, |
|
|
|
/** |
|
* Create a standard anchor button for the toolbar. |
|
* @param {String} label Label text to display. |
|
* @param {String} highlighterId Highlighter ID that this button would belong to. |
|
* @param {String} commandName Command name that would be executed. |
|
* @return {Element} Returns an 'A' element. |
|
*/ |
|
createButton : function(label, highlighterId, commandName) |
|
{ |
|
var a = document.createElement('a'), |
|
style = a.style, |
|
config = sh.config, |
|
width = config.toolbarItemWidth, |
|
height = config.toolbarItemHeight |
|
; |
|
|
|
a.href = '#' + commandName; |
|
a.title = label; |
|
a.highlighterId = highlighterId; |
|
a.commandName = commandName; |
|
a.innerHTML = label; |
|
|
|
if (isNaN(width) == false) |
|
style.width = width + 'px'; |
|
|
|
if (isNaN(height) == false) |
|
style.height = height + 'px'; |
|
|
|
a.onclick = function(e) |
|
{ |
|
try |
|
{ |
|
sh.toolbar.executeCommand( |
|
this, |
|
e || window.event, |
|
this.highlighterId, |
|
this.commandName |
|
); |
|
} |
|
catch(e) |
|
{ |
|
sh.utils.alert(e.message); |
|
} |
|
|
|
return false; |
|
}; |
|
|
|
return a; |
|
}, |
|
|
|
/** |
|
* Executes a toolbar command. |
|
* @param {Element} sender Sender element. |
|
* @param {MouseEvent} event Original mouse event object. |
|
* @param {String} highlighterId Highlighter DIV element ID. |
|
* @param {String} commandName Name of the command to execute. |
|
* @return {Object} Passes out return value from command execution. |
|
*/ |
|
executeCommand : function(sender, event, highlighterId, commandName, args) |
|
{ |
|
var highlighter = sh.vars.highlighters[highlighterId], |
|
command |
|
; |
|
|
|
if (highlighter == null || (command = highlighter.toolbarCommands[commandName]) == null) |
|
return null; |
|
|
|
return command.execute(sender, event, args); |
|
}, |
|
|
|
/** Collection of toolbar items. */ |
|
items : { |
|
expandSource : function(highlighter) |
|
{ |
|
this.create = function() |
|
{ |
|
if (highlighter.getParam('collapse') != true) |
|
return; |
|
|
|
return sh.config.strings.expandSource; |
|
}; |
|
|
|
this.execute = function(sender, event, args) |
|
{ |
|
var div = highlighter.div; |
|
|
|
sender.parentNode.removeChild(sender); |
|
div.className = div.className.replace('collapsed', ''); |
|
}; |
|
}, |
|
|
|
/** |
|
* Command to open a new window and display the original unformatted source code inside. |
|
*/ |
|
viewSource : function(highlighter) |
|
{ |
|
this.create = function() |
|
{ |
|
return sh.config.strings.viewSource; |
|
}; |
|
|
|
this.execute = function(sender, event, args) |
|
{ |
|
var code = sh.utils.fixInputString(highlighter.originalCode).replace(/</g, '<'), |
|
wnd = sh.utils.popup('', '_blank', 750, 400, 'location=0, resizable=1, menubar=0, scrollbars=1') |
|
; |
|
|
|
code = sh.utils.unindent(code); |
|
|
|
wnd.document.write('<pre>' + code + '</pre>'); |
|
wnd.document.close(); |
|
}; |
|
}, |
|
|
|
/** |
|
* Command to copy the original source code in to the clipboard. |
|
* Uses Flash method if <code>clipboardSwf</code> is configured. |
|
*/ |
|
copyToClipboard : function(highlighter) |
|
{ |
|
var flashDiv, flashSwf, |
|
highlighterId = highlighter.id |
|
; |
|
|
|
this.create = function() |
|
{ |
|
var config = sh.config; |
|
|
|
// disable functionality if running locally |
|
if (config.clipboardSwf == null) |
|
return null; |
|
|
|
function params(list) |
|
{ |
|
var result = ''; |
|
|
|
for (var name in list) |
|
result += "<param name='" + name + "' value='" + list[name] + "'/>"; |
|
|
|
return result; |
|
}; |
|
|
|
function attributes(list) |
|
{ |
|
var result = ''; |
|
|
|
for (var name in list) |
|
result += " " + name + "='" + list[name] + "'"; |
|
|
|
return result; |
|
}; |
|
|
|
var args1 = { |
|
width : config.toolbarItemWidth, |
|
height : config.toolbarItemHeight, |
|
id : highlighterId + '_clipboard', |
|
type : 'application/x-shockwave-flash', |
|
title : sh.config.strings.copyToClipboard |
|
}, |
|
|
|
// these arguments are used in IE's <param /> collection |
|
args2 = { |
|
allowScriptAccess : 'always', |
|
wmode : 'transparent', |
|
flashVars : 'highlighterId=' + highlighterId, |
|
menu : 'false' |
|
}, |
|
swf = config.clipboardSwf, |
|
html |
|
; |
|
|
|
if (/msie/i.test(navigator.userAgent)) |
|
{ |
|
html = '<object' |
|
+ attributes({ |
|
classid : 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000', |
|
codebase : 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0' |
|
}) |
|
+ attributes(args1) |
|
+ '>' |
|
+ params(args2) |
|
+ params({ movie : swf }) |
|
+ '</object>' |
|
; |
|
} |
|
else |
|
{ |
|
html = '<embed' |
|
+ attributes(args1) |
|
+ attributes(args2) |
|
+ attributes({ src : swf }) |
|
+ '/>' |
|
; |
|
} |
|
|
|
flashDiv = document.createElement('div'); |
|
flashDiv.innerHTML = html; |
|
|
|
return flashDiv; |
|
}; |
|
|
|
this.execute = function(sender, event, args) |
|
{ |
|
var command = args.command; |
|
|
|
switch (command) |
|
{ |
|
case 'get': |
|
var code = sh.utils.unindent( |
|
sh.utils.fixInputString(highlighter.originalCode) |
|
.replace(/</g, '<') |
|
.replace(/>/g, '>') |
|
.replace(/&/g, '&') |
|
); |
|
|
|
if(window.clipboardData) |
|
// will fall through to the confirmation because there isn't a break |
|
window.clipboardData.setData('text', code); |
|
else |
|
return sh.utils.unindent(code); |
|
|
|
case 'ok': |
|
sh.utils.alert(sh.config.strings.copyToClipboardConfirmation); |
|
break; |
|
|
|
case 'error': |
|
sh.utils.alert(args.message); |
|
break; |
|
} |
|
}; |
|
}, |
|
|
|
/** Command to print the colored source code. */ |
|
printSource : function(highlighter) |
|
{ |
|
this.create = function() |
|
{ |
|
return sh.config.strings.print; |
|
}; |
|
|
|
this.execute = function(sender, event, args) |
|
{ |
|
var iframe = document.createElement('IFRAME'), |
|
doc = null |
|
; |
|
|
|
// make sure there is never more than one hidden iframe created by SH |
|
if (sh.vars.printFrame != null) |
|
document.body.removeChild(sh.vars.printFrame); |
|
|
|
sh.vars.printFrame = iframe; |
|
|
|
// this hides the iframe |
|
iframe.style.cssText = 'position:absolute;width:0px;height:0px;left:-500px;top:-500px;'; |
|
|
|
document.body.appendChild(iframe); |
|
doc = iframe.contentWindow.document; |
|
|
|
copyStyles(doc, window.document); |
|
doc.write('<div class="' + highlighter.div.className.replace('collapsed', '') + ' printing">' + highlighter.div.innerHTML + '</div>'); |
|
doc.close(); |
|
|
|
iframe.contentWindow.focus(); |
|
iframe.contentWindow.print(); |
|
|
|
function copyStyles(destDoc, sourceDoc) |
|
{ |
|
var links = sourceDoc.getElementsByTagName('link'); |
|
|
|
for(var i = 0; i < links.length; i++) |
|
if(links[i].rel.toLowerCase() == 'stylesheet' && /shCore\.css$/.test(links[i].href)) |
|
destDoc.write('<link type="text/css" rel="stylesheet" href="' + links[i].href + '"></link>'); |
|
}; |
|
}; |
|
}, |
|
|
|
/** Command to display the about dialog window. */ |
|
about : function(highlighter) |
|
{ |
|
this.create = function() |
|
{ |
|
return sh.config.strings.help; |
|
}; |
|
|
|
this.execute = function(sender, event) |
|
{ |
|
var wnd = sh.utils.popup('', '_blank', 500, 250, 'scrollbars=0'), |
|
doc = wnd.document |
|
; |
|
|
|
doc.write(sh.config.strings.aboutDialog); |
|
doc.close(); |
|
wnd.focus(); |
|
}; |
|
} |
|
} |
|
}, |
|
|
|
utils : { |
|
/** |
|
* Finds an index of element in the array. |
|
* @ignore |
|
* @param {Object} searchElement |
|
* @param {Number} fromIndex |
|
* @return {Number} Returns index of element if found; -1 otherwise. |
|
*/ |
|
indexOf : function(array, searchElement, fromIndex) |
|
{ |
|
fromIndex = Math.max(fromIndex || 0, 0); |
|
|
|
for (var i = fromIndex; i < array.length; i++) |
|
if(array[i] == searchElement) |
|
return i; |
|
|
|
return -1; |
|
}, |
|
|
|
/** |
|
* Generates a unique element ID. |
|
*/ |
|
guid : function(prefix) |
|
{ |
|
return prefix + Math.round(Math.random() * 1000000).toString(); |
|
}, |
|
|
|
/** |
|
* Merges two objects. Values from obj2 override values in obj1. |
|
* Function is NOT recursive and works only for one dimensional objects. |
|
* @param {Object} obj1 First object. |
|
* @param {Object} obj2 Second object. |
|
* @return {Object} Returns combination of both objects. |
|
*/ |
|
merge: function(obj1, obj2) |
|
{ |
|
var result = {}, name; |
|
|
|
for (name in obj1) |
|
result[name] = obj1[name]; |
|
|
|
for (name in obj2) |
|
result[name] = obj2[name]; |
|
|
|
return result; |
|
}, |
|
|
|
/** |
|
* Attempts to convert string to boolean. |
|
* @param {String} value Input string. |
|
* @return {Boolean} Returns true if input was "true", false if input was "false" and value otherwise. |
|
*/ |
|
toBoolean: function(value) |
|
{ |
|
switch (value) |
|
{ |
|
case "true": |
|
return true; |
|
|
|
case "false": |
|
return false; |
|
} |
|
|
|
return value; |
|
}, |
|
|
|
/** |
|
* Opens up a centered popup window. |
|
* @param {String} url URL to open in the window. |
|
* @param {String} name Popup name. |
|
* @param {int} width Popup width. |
|
* @param {int} height Popup height. |
|
* @param {String} options window.open() options. |
|
* @return {Window} Returns window instance. |
|
*/ |
|
popup: function(url, name, width, height, options) |
|
{ |
|
var x = (screen.width - width) / 2, |
|
y = (screen.height - height) / 2 |
|
; |
|
|
|
options += ', left=' + x + |
|
', top=' + y + |
|
', width=' + width + |
|
', height=' + height |
|
; |
|
options = options.replace(/^,/, ''); |
|
|
|
var win = window.open(url, name, options); |
|
win.focus(); |
|
return win; |
|
}, |
|
|
|
/** |
|
* Adds event handler to the target object. |
|
* @param {Object} obj Target object. |
|
* @param {String} type Name of the event. |
|
* @param {Function} func Handling function. |
|
*/ |
|
addEvent: function(obj, type, func) |
|
{ |
|
if (obj.attachEvent) |
|
{ |
|
obj['e' + type + func] = func; |
|
obj[type + func] = function() |
|
{ |
|
obj['e' + type + func](window.event); |
|
} |
|
obj.attachEvent('on' + type, obj[type + func]); |
|
} |
|
else |
|
{ |
|
obj.addEventListener(type, func, false); |
|
} |
|
}, |
|
|
|
/** |
|
* Displays an alert. |
|
* @param {String} str String to display. |
|
*/ |
|
alert: function(str) |
|
{ |
|
alert(sh.config.strings.alert + str) |
|
}, |
|
|
|
/** |
|
* Finds a brush by its alias. |
|
* |
|
* @param {String} alias Brush alias. |
|
* @param {Boolean} alert Suppresses the alert if false. |
|
* @return {Brush} Returns bursh constructor if found, null otherwise. |
|
*/ |
|
findBrush: function(alias, alert) |
|
{ |
|
var brushes = sh.vars.discoveredBrushes, |
|
result = null |
|
; |
|
|
|
if (brushes == null) |
|
{ |
|
brushes = {}; |
|
|
|
// Find all brushes |
|
for (var brush in sh.brushes) |
|
{ |
|
var aliases = sh.brushes[brush].aliases; |
|
|
|
if (aliases == null) |
|
continue; |
|
|
|
// keep the brush name |
|
sh.brushes[brush].name = brush.toLowerCase(); |
|
|
|
for (var i = 0; i < aliases.length; i++) |
|
brushes[aliases[i]] = brush; |
|
} |
|
|
|
sh.vars.discoveredBrushes = brushes; |
|
} |
|
|
|
result = sh.brushes[brushes[alias]]; |
|
|
|
if (result == null && alert != false) |
|
sh.utils.alert(sh.config.strings.noBrush + alias); |
|
|
|
return result; |
|
}, |
|
|
|
/** |
|
* Executes a callback on each line and replaces each line with result from the callback. |
|
* @param {Object} str Input string. |
|
* @param {Object} callback Callback function taking one string argument and returning a string. |
|
*/ |
|
eachLine: function(str, callback) |
|
{ |
|
var lines = str.split('\n'); |
|
|
|
for (var i = 0; i < lines.length; i++) |
|
lines[i] = callback(lines[i]); |
|
|
|
return lines.join('\n'); |
|
}, |
|
|
|
/** |
|
* This is a special trim which only removes first and last empty lines |
|
* and doesn't affect valid leading space on the first line. |
|
* |
|
* @param {String} str Input string |
|
* @return {String} Returns string without empty first and last lines. |
|
*/ |
|
trimFirstAndLastLines: function(str) |
|
{ |
|
return str.replace(/^[ ]*[\n]+|[\n]*[ ]*$/g, ''); |
|
}, |
|
|
|
/** |
|
* Parses key/value pairs into hash object. |
|
* |
|
* Understands the following formats: |
|
* - name: word; |
|
* - name: [word, word]; |
|
* - name: "string"; |
|
* - name: 'string'; |
|
* |
|
* For example: |
|
* name1: value; name2: [value, value]; name3: 'value' |
|
* |
|
* @param {String} str Input string. |
|
* @return {Object} Returns deserialized object. |
|
*/ |
|
parseParams: function(str) |
|
{ |
|
var match, |
|
result = {}, |
|
arrayRegex = new XRegExp("^\\[(?<values>(.*?))\\]$"), |
|
regex = new XRegExp( |
|
"(?<name>[\\w-]+)" + |
|
"\\s*:\\s*" + |
|
"(?<value>" + |
|
"[\\w-%#]+|" + // word |
|
"\\[.*?\\]|" + // [] array |
|
'".*?"|' + // "" string |
|
"'.*?'" + // '' string |
|
")\\s*;?", |
|
"g" |
|
) |
|
; |
|
|
|
while ((match = regex.exec(str)) != null) |
|
{ |
|
var value = match.value |
|
.replace(/^['"]|['"]$/g, '') // strip quotes from end of strings |
|
; |
|
|
|
// try to parse array value |
|
if (value != null && arrayRegex.test(value)) |
|
{ |
|
var m = arrayRegex.exec(value); |
|
value = m.values.length > 0 ? m.values.split(/\s*,\s*/) : []; |
|
} |
|
|
|
result[match.name] = value; |
|
} |
|
|
|
return result; |
|
}, |
|
|
|
/** |
|
* Wraps each line of the string into <code/> tag with given style applied to it. |
|
* |
|
* @param {String} str Input string. |
|
* @param {String} css Style name to apply to the string. |
|
* @return {String} Returns input string with each line surrounded by <span/> tag. |
|
*/ |
|
decorate: function(str, css) |
|
{ |
|
if (str == null || str.length == 0 || str == '\n') |
|
return str; |
|
|
|
str = str.replace(/</g, '<'); |
|
|
|
// Replace two or more sequential spaces with leaving last space untouched. |
|
str = str.replace(/ {2,}/g, function(m) |
|
{ |
|
var spaces = ''; |
|
|
|
for (var i = 0; i < m.length - 1; i++) |
|
spaces += ' '; |
|
|
|
return spaces + ' '; |
|
}); |
|
|
|
// Split each line and apply <span class="...">...</span> to them so that |
|
// leading spaces aren't included. |
|
if (css != null) |
|
str = sh.utils.eachLine(str, function(line) |
|
{ |
|
if (line.length == 0) |
|
return ''; |
|
|
|
var spaces = ''; |
|
|
|
line = line.replace(/^( | )+/, function(s) |
|
{ |
|
spaces = s; |
|
return ''; |
|
}); |
|
|
|
if (line.length == 0) |
|
return spaces; |
|
|
|
return spaces + '<code class="' + css + '">' + line + '</code>'; |
|
}); |
|
|
|
return str; |
|
}, |
|
|
|
/** |
|
* Pads number with zeros until it's length is the same as given length. |
|
* |
|
* @param {Number} number Number to pad. |
|
* @param {Number} length Max string length with. |
|
* @return {String} Returns a string padded with proper amount of '0'. |
|
*/ |
|
padNumber : function(number, length) |
|
{ |
|
var result = number.toString(); |
|
|
|
while (result.length < length) |
|
result = '0' + result; |
|
|
|
return result; |
|
}, |
|
|
|
/** |
|
* Measures width of a single space character. |
|
* @return {Number} Returns width of a single space character. |
|
*/ |
|
measureSpace : function() |
|
{ |
|
var container = document.createElement('div'), |
|
span, |
|
result = 0, |
|
body = document.body, |
|
id = sh.utils.guid('measureSpace'), |
|
|
|
// variable names will be compressed, so it's better than a plain string |
|
divOpen = '<div class="', |
|
closeDiv = '</div>', |
|
closeSpan = '</span>' |
|
; |
|
|
|
// we have to duplicate highlighter nested structure in order to get an acurate space measurment |
|
container.innerHTML = |
|
divOpen + 'syntaxhighlighter">' |
|
+ divOpen + 'lines">' |
|
+ divOpen + 'line">' |
|
+ divOpen + 'content' |
|
+ '"><span class="block"><span id="' + id + '"> ' + closeSpan + closeSpan |
|
+ closeDiv |
|
+ closeDiv |
|
+ closeDiv |
|
+ closeDiv |
|
; |
|
|
|
body.appendChild(container); |
|
span = document.getElementById(id); |
|
|
|
if (/opera/i.test(navigator.userAgent)) |
|
{ |
|
var style = window.getComputedStyle(span, null); |
|
result = parseInt(style.getPropertyValue("width")); |
|
} |
|
else |
|
{ |
|
result = span.offsetWidth; |
|
} |
|
|
|
body.removeChild(container); |
|
|
|
return result; |
|
}, |
|
|
|
/** |
|
* Replaces tabs with spaces. |
|
* |
|
* @param {String} code Source code. |
|
* @param {Number} tabSize Size of the tab. |
|
* @return {String} Returns code with all tabs replaces by spaces. |
|
*/ |
|
processTabs : function(code, tabSize) |
|
{ |
|
var tab = ''; |
|
|
|
for (var i = 0; i < tabSize; i++) |
|
tab += ' '; |
|
|
|
return code.replace(/\t/g, tab); |
|
}, |
|
|
|
/** |
|
* Replaces tabs with smart spaces. |
|
* |
|
* @param {String} code Code to fix the tabs in. |
|
* @param {Number} tabSize Number of spaces in a column. |
|
* @return {String} Returns code with all tabs replaces with roper amount of spaces. |
|
*/ |
|
processSmartTabs : function(code, tabSize) |
|
{ |
|
var lines = code.split('\n'), |
|
tab = '\t', |
|
spaces = '' |
|
; |
|
|
|
// Create a string with 1000 spaces to copy spaces from... |
|
// It's assumed that there would be no indentation longer than that. |
|
for (var i = 0; i < 50; i++) |
|
spaces += ' '; // 20 spaces * 50 |
|
|
|
// This function inserts specified amount of spaces in the string |
|
// where a tab is while removing that given tab. |
|
function insertSpaces(line, pos, count) |
|
{ |
|
return line.substr(0, pos) |
|
+ spaces.substr(0, count) |
|
+ line.substr(pos + 1, line.length) // pos + 1 will get rid of the tab |
|
; |
|
}; |
|
|
|
// Go through all the lines and do the 'smart tabs' magic. |
|
code = sh.utils.eachLine(code, function(line) |
|
{ |
|
if (line.indexOf(tab) == -1) |
|
return line; |
|
|
|
var pos = 0; |
|
|
|
while ((pos = line.indexOf(tab)) != -1) |
|
{ |
|
// This is pretty much all there is to the 'smart tabs' logic. |
|
// Based on the position within the line and size of a tab, |
|
// calculate the amount of spaces we need to insert. |
|
var spaces = tabSize - pos % tabSize; |
|
line = insertSpaces(line, pos, spaces); |
|
} |
|
|
|
return line; |
|
}); |
|
|
|
return code; |
|
}, |
|
|
|
/** |
|
* Performs various string fixes based on configuration. |
|
*/ |
|
fixInputString : function(str) |
|
{ |
|
var br = /<br\s*\/?>|<br\s*\/?>/gi; |
|
|
|
if (sh.config.bloggerMode == true) |
|
str = str.replace(br, '\n'); |
|
|
|
if (sh.config.stripBrs == true) |
|
str = str.replace(br, ''); |
|
|
|
return str; |
|
}, |
|
|
|
/** |
|
* Removes all white space at the begining and end of a string. |
|
* |
|
* @param {String} str String to trim. |
|
* @return {String} Returns string without leading and following white space characters. |
|
*/ |
|
trim: function(str) |
|
{ |
|
return str.replace(/^\s+|\s+$/g, ''); |
|
}, |
|
|
|
/** |
|
* Unindents a block of text by the lowest common indent amount. |
|
* @param {String} str Text to unindent. |
|
* @return {String} Returns unindented text block. |
|
*/ |
|
unindent: function(str) |
|
{ |
|
var lines = sh.utils.fixInputString(str).split('\n'), |
|
indents = new Array(), |
|
regex = /^\s*/, |
|
min = 1000 |
|
; |
|
|
|
// go through every line and check for common number of indents |
|
for (var i = 0; i < lines.length && min > 0; i++) |
|
{ |
|
var line = lines[i]; |
|
|
|
if (sh.utils.trim(line).length == 0) |
|
continue; |
|
|
|
var matches = regex.exec(line); |
|
|
|
// In the event that just one line doesn't have leading white space |
|
// we can't unindent anything, so bail completely. |
|
if (matches == null) |
|
return str; |
|
|
|
min = Math.min(matches[0].length, min); |
|
} |
|
|
|
// trim minimum common number of white space from the begining of every line |
|
if (min > 0) |
|
for (var i = 0; i < lines.length; i++) |
|
lines[i] = lines[i].substr(min); |
|
|
|
return lines.join('\n'); |
|
}, |
|
|
|
/** |
|
* Callback method for Array.sort() which sorts matches by |
|
* index position and then by length. |
|
* |
|
* @param {Match} m1 Left object. |
|
* @param {Match} m2 Right object. |
|
* @return {Number} Returns -1, 0 or -1 as a comparison result. |
|
*/ |
|
matchesSortCallback: function(m1, m2) |
|
{ |
|
// sort matches by index first |
|
if(m1.index < m2.index) |
|
return -1; |
|
else if(m1.index > m2.index) |
|
return 1; |
|
else |
|
{ |
|
// if index is the same, sort by length |
|
if(m1.length < m2.length) |
|
return -1; |
|
else if(m1.length > m2.length) |
|
return 1; |
|
} |
|
|
|
return 0; |
|
}, |
|
|
|
/** |
|
* Executes given regular expression on provided code and returns all |
|
* matches that are found. |
|
* |
|
* @param {String} code Code to execute regular expression on. |
|
* @param {Object} regex Regular expression item info from <code>regexList</code> collection. |
|
* @return {Array} Returns a list of Match objects. |
|
*/ |
|
getMatches: function(code, regexInfo) |
|
{ |
|
function defaultAdd(match, regexInfo) |
|
{ |
|
return [new sh.Match(match[0], match.index, regexInfo.css)]; |
|
}; |
|
|
|
var index = 0, |
|
match = null, |
|
result = [], |
|
func = regexInfo.func ? regexInfo.func : defaultAdd |
|
; |
|
|
|
while((match = regexInfo.regex.exec(code)) != null) |
|
result = result.concat(func(match, regexInfo)); |
|
|
|
return result; |
|
}, |
|
|
|
processUrls: function(code) |
|
{ |
|
var lt = '<', |
|
gt = '>' |
|
; |
|
|
|
return code.replace(sh.regexLib.url, function(m) |
|
{ |
|
var suffix = '', prefix = ''; |
|
|
|
// We include < and > in the URL for the common cases like <http://google.com> |
|
// The problem is that they get transformed into <http://google.com> |
|
// Where as > easily looks like part of the URL string. |
|
|
|
if (m.indexOf(lt) == 0) |
|
{ |
|
prefix = lt; |
|
m = m.substring(lt.length); |
|
} |
|
|
|
if (m.indexOf(gt) == m.length - gt.length) |
|
{ |
|
m = m.substring(0, m.length - gt.length); |
|
suffix = gt; |
|
} |
|
|
|
return prefix + '<a href="' + m + '">' + m + '</a>' + suffix; |
|
}); |
|
}, |
|
|
|
/** |
|
* Finds all <SCRIPT TYPE="syntaxhighlighter" /> elements. |
|
* @return {Array} Returns array of all found SyntaxHighlighter tags. |
|
*/ |
|
getSyntaxHighlighterScriptTags: function() |
|
{ |
|
var tags = document.getElementsByTagName('script'), |
|
result = [] |
|
; |
|
|
|
for (var i = 0; i < tags.length; i++) |
|
if (tags[i].type == 'syntaxhighlighter') |
|
result.push(tags[i]); |
|
|
|
return result; |
|
}, |
|
|
|
/** |
|
* Strips <![CDATA[]]> from <SCRIPT /> content because it should be used |
|
* there in most cases for XHTML compliance. |
|
* @param {String} original Input code. |
|
* @return {String} Returns code without leading <![CDATA[]]> tags. |
|
*/ |
|
stripCData: function(original) |
|
{ |
|
var left = '<![CDATA[', |
|
right = ']]>', |
|
// for some reason IE inserts some leading blanks here |
|
copy = sh.utils.trim(original), |
|
changed = false |
|
; |
|
|
|
if (copy.indexOf(left) == 0) |
|
{ |
|
copy = copy.substring(left.length); |
|
changed = true; |
|
} |
|
|
|
if (copy.indexOf(right) == copy.length - right.length) |
|
{ |
|
copy = copy.substring(0, copy.length - right.length); |
|
changed = true; |
|
} |
|
|
|
return changed ? copy : original; |
|
} |
|
}, // end of utils |
|
|
|
/** |
|
* Shorthand to highlight all elements on the page that are marked as |
|
* SyntaxHighlighter source code. |
|
* |
|
* @param {Object} globalParams Optional parameters which override element's |
|
* parameters. Only used if element is specified. |
|
* |
|
* @param {Object} element Optional element to highlight. If none is |
|
* provided, all elements in the current document |
|
* are highlighted. |
|
*/ |
|
highlight : function(globalParams, element) |
|
{ |
|
function toArray(source) |
|
{ |
|
var result = []; |
|
|
|
for (var i = 0; i < source.length; i++) |
|
result.push(source[i]); |
|
|
|
return result; |
|
}; |
|
|
|
var elements = element ? [element] : toArray(document.getElementsByTagName(sh.config.tagName)), |
|
propertyName = 'innerHTML', |
|
highlighter = null, |
|
conf = sh.config |
|
; |
|
|
|
// support for <SCRIPT TYPE="syntaxhighlighter" /> feature |
|
if (conf.useScriptTags) |
|
elements = elements.concat(sh.utils.getSyntaxHighlighterScriptTags()); |
|
|
|
if (elements.length === 0) |
|
return; |
|
|
|
for (var i = 0; i < elements.length; i++) |
|
{ |
|
var target = elements[i], |
|
params = sh.utils.parseParams(target.className), |
|
brushName, |
|
code, |
|
result |
|
; |
|
|
|
// local params take precedence over globals |
|
params = sh.utils.merge(globalParams, params); |
|
brushName = params['brush']; |
|
|
|
if (brushName == null) |
|
continue; |
|
|
|
// Instantiate a brush |
|
if (params['html-script'] == 'true' || sh.defaults['html-script'] == true) |
|
{ |
|
highlighter = new sh.HtmlScript(brushName); |
|
brushName = 'htmlscript'; |
|
} |
|
else |
|
{ |
|
var brush = sh.utils.findBrush(brushName); |
|
|
|
if (brush) |
|
{ |
|
brushName = brush.name; |
|
highlighter = new brush(); |
|
} |
|
else |
|
{ |
|
continue; |
|
} |
|
} |
|
|
|
code = target[propertyName]; |
|
|
|
// remove CDATA from <SCRIPT/> tags if it's present |
|
if (conf.useScriptTags) |
|
code = sh.utils.stripCData(code); |
|
|
|
params['brush-name'] = brushName; |
|
highlighter.highlight(code, params); |
|
|
|
result = highlighter.div; |
|
|
|
if (sh.config.debug) |
|
{ |
|
result = document.createElement('textarea'); |
|
result.value = highlighter.div.innerHTML; |
|
result.style.width = '70em'; |
|
result.style.height = '30em'; |
|
} |
|
|
|
target.parentNode.replaceChild(result, target); |
|
} |
|
}, |
|
|
|
/** |
|
* Main entry point for the SyntaxHighlighter. |
|
* @param {Object} params Optional params to apply to all highlighted elements. |
|
*/ |
|
all : function(params) |
|
{ |
|
sh.utils.addEvent( |
|
window, |
|
'load', |
|
function() { sh.highlight(params); } |
|
); |
|
} |
|
}; // end of sh |
|
|
|
/** |
|
* Match object. |
|
*/ |
|
sh.Match = function(value, index, css) |
|
{ |
|
this.value = value; |
|
this.index = index; |
|
this.length = value.length; |
|
this.css = css; |
|
this.brushName = null; |
|
}; |
|
|
|
sh.Match.prototype.toString = function() |
|
{ |
|
return this.value; |
|
}; |
|
|
|
/** |
|
* Simulates HTML code with a scripting language embedded. |
|
* |
|
* @param {String} scriptBrushName Brush name of the scripting language. |
|
*/ |
|
sh.HtmlScript = function(scriptBrushName) |
|
{ |
|
var brushClass = sh.utils.findBrush(scriptBrushName), |
|
scriptBrush, |
|
xmlBrush = new sh.brushes.Xml(), |
|
bracketsRegex = null |
|
; |
|
|
|
if (brushClass == null) |
|
return; |
|
|
|
scriptBrush = new brushClass(); |
|
this.xmlBrush = xmlBrush; |
|
|
|
if (scriptBrush.htmlScript == null) |
|
{ |
|
sh.utils.alert(sh.config.strings.brushNotHtmlScript + scriptBrushName); |
|
return; |
|
} |
|
|
|
xmlBrush.regexList.push( |
|
{ regex: scriptBrush.htmlScript.code, func: process } |
|
); |
|
|
|
function offsetMatches(matches, offset) |
|
{ |
|
for (var j = 0; j < matches.length; j++) |
|
matches[j].index += offset; |
|
} |
|
|
|
function process(match, info) |
|
{ |
|
var code = match.code, |
|
matches = [], |
|
regexList = scriptBrush.regexList, |
|
offset = match.index + match.left.length, |
|
htmlScript = scriptBrush.htmlScript, |
|
result |
|
; |
|
|
|
// add all matches from the code |
|
for (var i = 0; i < regexList.length; i++) |
|
{ |
|
result = sh.utils.getMatches(code, regexList[i]); |
|
offsetMatches(result, offset); |
|
matches = matches.concat(result); |
|
} |
|
|
|
// add left script bracket |
|
if (htmlScript.left != null && match.left != null) |
|
{ |
|
result = sh.utils.getMatches(match.left, htmlScript.left); |
|
offsetMatches(result, match.index); |
|
matches = matches.concat(result); |
|
} |
|
|
|
// add right script bracket |
|
if (htmlScript.right != null && match.right != null) |
|
{ |
|
result = sh.utils.getMatches(match.right, htmlScript.right); |
|
offsetMatches(result, match.index + match[0].lastIndexOf(match.right)); |
|
matches = matches.concat(result); |
|
} |
|
|
|
for (var j = 0; j < matches.length; j++) |
|
matches[j].brushName = brushClass.name; |
|
|
|
return matches; |
|
} |
|
}; |
|
|
|
sh.HtmlScript.prototype.highlight = function(code, params) |
|
{ |
|
this.xmlBrush.highlight(code, params); |
|
this.div = this.xmlBrush.div; |
|
} |
|
|
|
/** |
|
* Main Highlither class. |
|
* @constructor |
|
*/ |
|
sh.Highlighter = function() |
|
{ |
|
}; |
|
|
|
sh.Highlighter.prototype = { |
|
/** |
|
* Returns value of the parameter passed to the highlighter. |
|
* @param {String} name Name of the parameter. |
|
* @param {Object} defaultValue Default value. |
|
* @return {Object} Returns found value or default value otherwise. |
|
*/ |
|
getParam : function(name, defaultValue) |
|
{ |
|
var result = this.params[name]; |
|
return sh.utils.toBoolean(result == null ? defaultValue : result); |
|
}, |
|
|
|
/** |
|
* Shortcut to document.createElement(). |
|
* @param {String} name Name of the element to create (DIV, A, etc). |
|
* @return {HTMLElement} Returns new HTML element. |
|
*/ |
|
create: function(name) |
|
{ |
|
return document.createElement(name); |
|
}, |
|
|
|
/** |
|
* Applies all regular expression to the code and stores all found |
|
* matches in the `this.matches` array. |
|
* @param {Array} regexList List of regular expressions. |
|
* @param {String} code Source code. |
|
* @return {Array} Returns list of matches. |
|
*/ |
|
findMatches: function(regexList, code) |
|
{ |
|
var result = []; |
|
|
|
if (regexList != null) |
|
for (var i = 0; i < regexList.length; i++) |
|
// BUG: length returns len+1 for array if methods added to prototype chain (oising@gmail.com) |
|
if (typeof (regexList[i]) == "object") |
|
result = result.concat(sh.utils.getMatches(code, regexList[i])); |
|
|
|
// sort the matches |
|
return result.sort(sh.utils.matchesSortCallback); |
|
}, |
|
|
|
/** |
|
* Checks to see if any of the matches are inside of other matches. |
|
* This process would get rid of highligted strings inside comments, |
|
* keywords inside strings and so on. |
|
*/ |
|
removeNestedMatches: function() |
|
{ |
|
var matches = this.matches; |
|
|
|
// Optimized by Jose Prado (http://joseprado.com) |
|
for (var i = 0; i < matches.length; i++) |
|
{ |
|
if (matches[i] === null) |
|
continue; |
|
|
|
var itemI = matches[i], |
|
itemIEndPos = itemI.index + itemI.length |
|
; |
|
|
|
for (var j = i + 1; j < matches.length && matches[i] !== null; j++) |
|
{ |
|
var itemJ = matches[j]; |
|
|
|
if (itemJ === null) |
|
continue; |
|
else if (itemJ.index > itemIEndPos) |
|
break; |
|
else if (itemJ.index == itemI.index && itemJ.length > itemI.length) |
|
this.matches[i] = null; |
|
else if (itemJ.index >= itemI.index && itemJ.index < itemIEndPos) |
|
this.matches[j] = null; |
|
} |
|
} |
|
}, |
|
|
|
/** |
|
* Splits block of text into individual DIV lines. |
|
* @param {String} code Code to highlight. |
|
* @return {String} Returns highlighted code in HTML form. |
|
*/ |
|
createDisplayLines : function(code) |
|
{ |
|
var lines = code.split(/\n/g), |
|
firstLine = parseInt(this.getParam('first-line')), |
|
padLength = this.getParam('pad-line-numbers'), |
|
highlightedLines = this.getParam('highlight', []), |
|
hasGutter = this.getParam('gutter') |
|
; |
|
|
|
code = ''; |
|
|
|
if (padLength == true) |
|
padLength = (firstLine + lines.length - 1).toString().length; |
|
else if (isNaN(padLength) == true) |
|
padLength = 0; |
|
|
|
for (var i = 0; i < lines.length; i++) |
|
{ |
|
var line = lines[i], |
|
indent = /^( |\s)+/.exec(line), |
|
lineClass = 'alt' + (i % 2 == 0 ? 1 : 2), |
|
lineNumber = sh.utils.padNumber(firstLine + i, padLength), |
|
highlighted = sh.utils.indexOf(highlightedLines, (firstLine + i).toString()) != -1, |
|
spaces = null |
|
; |
|
|
|
if (indent != null) |
|
{ |
|
spaces = indent[0].toString(); |
|
line = line.substr(spaces.length); |
|
} |
|
|
|
line = sh.utils.trim(line); |
|
|
|
if (line.length == 0) |
|
line = ' '; |
|
|
|
if (highlighted) |
|
lineClass += ' highlighted'; |
|
|
|
code += |
|
'<div class="line ' + lineClass + '">' |
|
+ '<table>' |
|
+ '<tr>' |
|
+ (hasGutter ? '<td class="number"><code>' + lineNumber + '</code></td>' : '') |
|
+ '<td class="content">' |
|
+ (spaces != null ? '<code class="spaces">' + spaces.replace(' ', ' ') + '</code>' : '') |
|
+ line |
|
+ '</td>' |
|
+ '</tr>' |
|
+ '</table>' |
|
+ '</div>' |
|
; |
|
} |
|
|
|
return code; |
|
}, |
|
|
|
/** |
|
* Finds all matches in the source code. |
|
* @param {String} code Source code to process matches in. |
|
* @param {Array} matches Discovered regex matches. |
|
* @return {String} Returns formatted HTML with processed mathes. |
|
*/ |
|
processMatches: function(code, matches) |
|
{ |
|
var pos = 0, |
|
result = '', |
|
decorate = sh.utils.decorate, // make an alias to save some bytes |
|
brushName = this.getParam('brush-name', '') |
|
; |
|
|
|
function getBrushNameCss(match) |
|
{ |
|
var result = match ? (match.brushName || brushName) : brushName; |
|
return result ? result + ' ' : ''; |
|
}; |
|
|
|
// Finally, go through the final list of matches and pull the all |
|
// together adding everything in between that isn't a match. |
|
for (var i = 0; i < matches.length; i++) |
|
{ |
|
var match = matches[i], |
|
matchBrushName |
|
; |
|
|
|
if (match === null || match.length === 0) |
|
continue; |
|
|
|
matchBrushName = getBrushNameCss(match); |
|
|
|
result += decorate(code.substr(pos, match.index - pos), matchBrushName + 'plain') |
|
+ decorate(match.value, matchBrushName + match.css) |
|
; |
|
|
|
pos = match.index + match.length; |
|
} |
|
|
|
// don't forget to add whatever's remaining in the string |
|
result += decorate(code.substr(pos), getBrushNameCss() + 'plain'); |
|
|
|
return result; |
|
}, |
|
|
|
/** |
|
* Highlights the code and returns complete HTML. |
|
* @param {String} code Code to highlight. |
|
* @param {Object} params Parameters object. |
|
*/ |
|
highlight: function(code, params) |
|
{ |
|
// using variables for shortcuts because JS compressor will shorten local variable names |
|
var conf = sh.config, |
|
vars = sh.vars, |
|
div, |
|
divClassName, |
|
tabSize, |
|
important = 'important' |
|
; |
|
|
|
this.params = {}; |
|
this.div = null; |
|
this.lines = null; |
|
this.code = null; |
|
this.bar = null; |
|
this.toolbarCommands = {}; |
|
this.id = sh.utils.guid('highlighter_'); |
|
|
|
// register this instance in the highlighters list |
|
vars.highlighters[this.id] = this; |
|
|
|
if (code === null) |
|
code = ''; |
|
|
|
// local params take precedence over defaults |
|
this.params = sh.utils.merge(sh.defaults, params || {}); |
|
|
|
// process light mode |
|
if (this.getParam('light') == true) |
|
this.params.toolbar = this.params.gutter = false; |
|
|
|
this.div = div = this.create('DIV'); |
|
this.lines = this.create('DIV'); |
|
this.lines.className = 'lines'; |
|
|
|
className = 'syntaxhighlighter'; |
|
div.id = this.id; |
|
|
|
// make collapsed |
|
if (this.getParam('collapse')) |
|
className += ' collapsed'; |
|
|
|
// disable gutter |
|
if (this.getParam('gutter') == false) |
|
className += ' nogutter'; |
|
|
|
// disable line wrapping |
|
if (this.getParam('wrap-lines') == false) |
|
this.lines.className += ' no-wrap'; |
|
|
|
// add custom user style name |
|
className += ' ' + this.getParam('class-name'); |
|
|
|
// add brush alias to the class name for custom CSS |
|
className += ' ' + this.getParam('brush-name'); |
|
|
|
div.className = className; |
|
|
|
this.originalCode = code; |
|
this.code = sh.utils.trimFirstAndLastLines(code) |
|
.replace(/\r/g, ' ') // IE lets these buggers through |
|
; |
|
|
|
tabSize = this.getParam('tab-size'); |
|
|
|
// replace tabs with spaces |
|
this.code = this.getParam('smart-tabs') == true |
|
? sh.utils.processSmartTabs(this.code, tabSize) |
|
: sh.utils.processTabs(this.code, tabSize) |
|
; |
|
|
|
this.code = sh.utils.unindent(this.code); |
|
|
|
// add controls toolbar |
|
if (this.getParam('toolbar')) |
|
{ |
|
this.bar = this.create('DIV'); |
|
this.bar.className = 'bar'; |
|
this.bar.appendChild(sh.toolbar.create(this)); |
|
div.appendChild(this.bar); |
|
|
|
// set up toolbar rollover |
|
var bar = this.bar; |
|
function hide() { bar.className = bar.className.replace('show', ''); } |
|
div.onmouseover = function() { hide(); bar.className += ' show'; }; |
|
div.onmouseout = function() { hide(); } |
|
} |
|
|
|
div.appendChild(this.lines); |
|
|
|
this.matches = this.findMatches(this.regexList, this.code); |
|
this.removeNestedMatches(); |
|
|
|
code = this.processMatches(this.code, this.matches); |
|
|
|
// finally, split all lines so that they wrap well |
|
code = this.createDisplayLines(sh.utils.trim(code)); |
|
|
|
// finally, process the links |
|
if (this.getParam('auto-links')) |
|
code = sh.utils.processUrls(code); |
|
|
|
this.lines.innerHTML = code; |
|
}, |
|
|
|
/** |
|
* Converts space separated list of keywords into a regular expression string. |
|
* @param {String} str Space separated keywords. |
|
* @return {String} Returns regular expression string. |
|
*/ |
|
getKeywords: function(str) |
|
{ |
|
str = str |
|
.replace(/^\s+|\s+$/g, '') |
|
.replace(/\s+/g, '|') |
|
; |
|
|
|
return '\\b(?:' + str + ')\\b'; |
|
}, |
|
|
|
/** |
|
* Makes a brush compatible with the `html-script` functionality. |
|
* @param {Object} regexGroup Object containing `left` and `right` regular expressions. |
|
*/ |
|
forHtmlScript: function(regexGroup) |
|
{ |
|
this.htmlScript = { |
|
left : { regex: regexGroup.left, css: 'script' }, |
|
right : { regex: regexGroup.right, css: 'script' }, |
|
code : new XRegExp( |
|
"(?<left>" + regexGroup.left.source + ")" + |
|
"(?<code>.*?)" + |
|
"(?<right>" + regexGroup.right.source + ")", |
|
"sgi" |
|
) |
|
}; |
|
} |
|
}; // end of Highlighter |
|
|
|
return sh; |
|
}(); // end of anonymous function |
|
|
|
|
|
/** |
|
* XRegExp 0.6.1 |
|
* (c) 2007-2008 Steven Levithan |
|
* <http://stevenlevithan.com/regex/xregexp/> |
|
* MIT License |
|
* |
|
* provides an augmented, cross-browser implementation of regular expressions |
|
* including support for additional modifiers and syntax. several convenience |
|
* methods and a recursive-construct parser are also included. |
|
*/ |
|
|
|
// prevent running twice, which would break references to native globals |
|
if (!window.XRegExp) { |
|
// anonymous function to avoid global variables |
|
(function () { |
|
// copy various native globals for reference. can't use the name ``native`` |
|
// because it's a reserved JavaScript keyword. |
|
var real = { |
|
exec: RegExp.prototype.exec, |
|
match: String.prototype.match, |
|
replace: String.prototype.replace, |
|
split: String.prototype.split |
|
}, |
|
/* regex syntax parsing with support for all the necessary cross- |
|
browser and context issues (escapings, character classes, etc.) */ |
|
lib = { |
|
part: /(?:[^\\([#\s.]+|\\(?!k<[\w$]+>|[pP]{[^}]+})[\S\s]?|\((?=\?(?!#|<[\w$]+>)))+|(\()(?:\?(?:(#)[^)]*\)|<([$\w]+)>))?|\\(?:k<([\w$]+)>|[pP]{([^}]+)})|(\[\^?)|([\S\s])/g, |
|
replaceVar: /(?:[^$]+|\$(?![1-9$&`']|{[$\w]+}))+|\$(?:([1-9]\d*|[$&`'])|{([$\w]+)})/g, |
|
extended: /^(?:\s+|#.*)+/, |
|
quantifier: /^(?:[?*+]|{\d+(?:,\d*)?})/, |
|
classLeft: /&&\[\^?/g, |
|
classRight: /]/g |
|
}, |
|
indexOf = function (array, item, from) { |
|
for (var i = from || 0; i < array.length; i++) |
|
if (array[i] === item) return i; |
|
return -1; |
|
}, |
|
brokenExecUndef = /()??/.exec("")[1] !== undefined, |
|
plugins = {}; |
|
|
|
/** |
|
* Accepts a pattern and flags, returns a new, extended RegExp object. |
|
* differs from a native regex in that additional flags and syntax are |
|
* supported and browser inconsistencies are ameliorated. |
|
* @ignore |
|
*/ |
|
XRegExp = function (pattern, flags) { |
|
if (pattern instanceof RegExp) { |
|
if (flags !== undefined) |
|
throw TypeError("can't supply flags when constructing one RegExp from another"); |
|
return pattern.addFlags(); // new copy |
|
} |
|
|
|
var flags = flags || "", |
|
singleline = flags.indexOf("s") > -1, |
|
extended = flags.indexOf("x") > -1, |
|
hasNamedCapture = false, |
|
captureNames = [], |
|
output = [], |
|
part = lib.part, |
|
match, cc, len, index, regex; |
|
|
|
part.lastIndex = 0; // in case the last XRegExp compilation threw an error (unbalanced character class) |
|
|
|
while (match = real.exec.call(part, pattern)) { |
|
// comment pattern. this check must come before the capturing group check, |
|
// because both match[1] and match[2] will be non-empty. |
|
if (match[2]) { |
|
// keep tokens separated unless the following token is a quantifier |
|
if (!lib.quantifier.test(pattern.slice(part.lastIndex))) |
|
output.push("(?:)"); |
|
// capturing group |
|
} else if (match[1]) { |
|
captureNames.push(match[3] || null); |
|
if (match[3]) |
|
hasNamedCapture = true; |
|
output.push("("); |
|
// named backreference |
|
} else if (match[4]) { |
|
index = indexOf(captureNames, match[4]); |
|
// keep backreferences separate from subsequent literal numbers |
|
// preserve backreferences to named groups that are undefined at this point as literal strings |
|
output.push(index > -1 ? |
|
"\\" + (index + 1) + (isNaN(pattern.charAt(part.lastIndex)) ? "" : "(?:)") : |
|
match[0] |
|
); |
|
// unicode element (requires plugin) |
|
} else if (match[5]) { |
|
output.push(plugins.unicode ? |
|
plugins.unicode.get(match[5], match[0].charAt(1) === "P") : |
|
match[0] |
|
); |
|
// character class opening delimiter ("[" or "[^") |
|
// (non-native unicode elements are not supported within character classes) |
|
} else if (match[6]) { |
|
if (pattern.charAt(part.lastIndex) === "]") { |
|
// for cross-browser compatibility with ECMA-262 v3 behavior, |
|
// convert [] to (?!) and [^] to [\S\s]. |
|
output.push(match[6] === "[" ? "(?!)" : "[\\S\\s]"); |
|
part.lastIndex++; |
|
} else { |
|
// parse the character class with support for inner escapes and |
|
// ES4's infinitely nesting intersection syntax ([&&[^&&[]]]). |
|
cc = XRegExp.matchRecursive("&&" + pattern.slice(match.index), lib.classLeft, lib.classRight, "", {escapeChar: "\\"})[0]; |
|
output.push(match[6] + cc + "]"); |
|
part.lastIndex += cc.length + 1; |
|
} |
|
// dot ("."), pound sign ("#"), or whitespace character |
|
} else if (match[7]) { |
|
if (singleline && match[7] === ".") { |
|
output.push("[\\S\\s]"); |
|
} else if (extended && lib.extended.test(match[7])) { |
|
len = real.exec.call(lib.extended, pattern.slice(part.lastIndex - 1))[0].length; |
|
// keep tokens separated unless the following token is a quantifier |
|
if (!lib.quantifier.test(pattern.slice(part.lastIndex - 1 + len))) |
|
output.push("(?:)"); |
|
part.lastIndex += len - 1; |
|
} else { |
|
output.push(match[7]); |
|
} |
|
} else { |
|
output.push(match[0]); |
|
} |
|
} |
|
|
|
regex = RegExp(output.join(""), real.replace.call(flags, /[sx]+/g, "")); |
|
regex._x = { |
|
source: pattern, |
|
captureNames: hasNamedCapture ? captureNames : null |
|
}; |
|
return regex; |
|
}; |
|
|
|
/** |
|
* Barebones plugin support for now (intentionally undocumented) |
|
* @ignore |
|
* @param {Object} name |
|
* @param {Object} o |
|
*/ |
|
XRegExp.addPlugin = function (name, o) { |
|
plugins[name] = o; |
|
}; |
|
|
|
/** |
|
* Adds named capture support, with values returned as ``result.name``. |
|
* |
|
* Also fixes two cross-browser issues, following the ECMA-262 v3 spec: |
|
* - captured values for non-participating capturing groups should be returned |
|
* as ``undefined``, rather than the empty string. |
|
* - the regex's ``lastIndex`` should not be incremented after zero-length |
|
* matches. |
|
* @ignore |
|
*/ |
|
RegExp.prototype.exec = function (str) { |
|
var match = real.exec.call(this, str), |
|
name, i, r2; |
|
if (match) { |
|
// fix browsers whose exec methods don't consistently return |
|
// undefined for non-participating capturing groups |
|
if (brokenExecUndef && match.length > 1) { |
|
// r2 doesn't need /g or /y, but they shouldn't hurt |
|
r2 = new RegExp("^" + this.source + "$(?!\\s)", this.getNativeFlags()); |
|
real.replace.call(match[0], r2, function () { |
|
for (i = 1; i < arguments.length - 2; i++) { |
|
if (arguments[i] === undefined) match[i] = undefined; |
|
} |
|
}); |
|
} |
|
// attach named capture properties |
|
if (this._x && this._x.captureNames) { |
|
for (i = 1; i < match.length; i++) { |
|
name = this._x.captureNames[i - 1]; |
|
if (name) match[name] = match[i]; |
|
} |
|
} |
|
// fix browsers that increment lastIndex after zero-length matches |
|
if (this.global && this.lastIndex > (match.index + match[0].length)) |
|
this.lastIndex--; |
|
} |
|
return match; |
|
}; |
|
})(); // end anonymous function |
|
} // end if(!window.XRegExp) |
|
|
|
/** |
|
* intentionally undocumented |
|
* @ignore |
|
*/ |
|
RegExp.prototype.getNativeFlags = function () { |
|
return (this.global ? "g" : "") + |
|
(this.ignoreCase ? "i" : "") + |
|
(this.multiline ? "m" : "") + |
|
(this.extended ? "x" : "") + |
|
(this.sticky ? "y" : ""); |
|
}; |
|
|
|
/** |
|
* Accepts flags; returns a new XRegExp object generated by recompiling |
|
* the regex with the additional flags (may include non-native flags). |
|
* The original regex object is not altered. |
|
* @ignore |
|
*/ |
|
RegExp.prototype.addFlags = function (flags) { |
|
var regex = new XRegExp(this.source, (flags || "") + this.getNativeFlags()); |
|
if (this._x) { |
|
regex._x = { |
|
source: this._x.source, |
|
captureNames: this._x.captureNames ? this._x.captureNames.slice(0) : null |
|
}; |
|
} |
|
return regex; |
|
}; |
|
|
|
/** |
|
* Accepts a context object and string; returns the result of calling |
|
* ``exec`` with the provided string. the context is ignored but is |
|
* accepted for congruity with ``Function.prototype.call``. |
|
* @ignore |
|
*/ |
|
RegExp.prototype.call = function (context, str) { |
|
return this.exec(str); |
|
}; |
|
|
|
/** |
|
* Accepts a context object and arguments array; returns the result of |
|
* calling ``exec`` with the first value in the arguments array. the context |
|
* is ignored but is accepted for congruity with ``Function.prototype.apply``. |
|
* @ignore |
|
*/ |
|
RegExp.prototype.apply = function (context, args) { |
|
return this.exec(args[0]); |
|
}; |
|
|
|
/** |
|
* Accepts a pattern and flags; returns an XRegExp object. if the pattern |
|
* and flag combination has previously been cached, the cached copy is |
|
* returned, otherwise the new object is cached. |
|
* @ignore |
|
*/ |
|
XRegExp.cache = function (pattern, flags) { |
|
var key = "/" + pattern + "/" + (flags || ""); |
|
return XRegExp.cache[key] || (XRegExp.cache[key] = new XRegExp(pattern, flags)); |
|
}; |
|
|
|
/** |
|
* Accepts a string; returns the string with regex metacharacters escaped. |
|
* the returned string can safely be used within a regex to match a literal |
|
* string. escaped characters are [, ], {, }, (, ), -, *, +, ?, ., \, ^, $, |
|
* |, #, [comma], and whitespace. |
|
* @ignore |
|
*/ |
|
XRegExp.escape = function (str) { |
|
return str.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, "\\$&"); |
|
}; |
|
|
|
/** |
|
* Accepts a string to search, left and right delimiters as regex pattern |
|
* strings, optional regex flags (may include non-native s, x, and y flags), |
|
* and an options object which allows setting an escape character and changing |
|
* the return format from an array of matches to a two-dimensional array of |
|
* string parts with extended position data. returns an array of matches |
|
* (optionally with extended data), allowing nested instances of left and right |
|
* delimiters. use the g flag to return all matches, otherwise only the first |
|
* is returned. if delimiters are unbalanced within the subject data, an error |
|
* is thrown. |
|
* |
|
* This function admittedly pushes the boundaries of what can be accomplished |
|
* sensibly without a "real" parser. however, by doing so it provides flexible |
|
* and powerful recursive parsing capabilities with minimal code weight. |
|
* |
|
* Warning: the ``escapeChar`` option is considered experimental and might be |
|
* changed or removed in future versions of XRegExp. |
|
* |
|
* unsupported features: |
|
* - backreferences within delimiter patterns when using ``escapeChar``. |
|
* - although providing delimiters as regex objects adds the minor feature of |
|
* independent delimiter flags, it introduces other limitations and is only |
|
* intended to be done by the ``XRegExp`` constructor (which can't call |
|
* itself while building a regex). |
|
* |
|
* @ignore |
|
*/ |
|
XRegExp.matchRecursive = function (str, left, right, flags, options) { |
|
var options = options || {}, |
|
escapeChar = options.escapeChar, |
|
vN = options.valueNames, |
|
flags = flags || "", |
|
global = flags.indexOf("g") > -1, |
|
ignoreCase = flags.indexOf("i") > -1, |
|
multiline = flags.indexOf("m") > -1, |
|
sticky = flags.indexOf("y") > -1, |
|
/* sticky mode has its own handling in this function, which means you |
|
can use flag "y" even in browsers which don't support it natively */ |
|
flags = flags.replace(/y/g, ""), |
|
left = left instanceof RegExp ? (left.global ? left : left.addFlags("g")) : new XRegExp(left, "g" + flags), |
|
right = right instanceof RegExp ? (right.global ? right : right.addFlags("g")) : new XRegExp(right, "g" + flags), |
|
output = [], |
|
openTokens = 0, |
|
delimStart = 0, |
|
delimEnd = 0, |
|
lastOuterEnd = 0, |
|
outerStart, innerStart, leftMatch, rightMatch, escaped, esc; |
|
|
|
if (escapeChar) { |
|
if (escapeChar.length > 1) throw SyntaxError("can't supply more than one escape character"); |
|
if (multiline) throw TypeError("can't supply escape character when using the multiline flag"); |
|
escaped = XRegExp.escape(escapeChar); |
|
/* Escape pattern modifiers: |
|
/g - not needed here |
|
/i - included |
|
/m - **unsupported**, throws error |
|
/s - handled by XRegExp when delimiters are provided as strings |
|
/x - handled by XRegExp when delimiters are provided as strings |
|
/y - not needed here; supported by other handling in this function |
|
*/ |
|
esc = new RegExp( |
|
"^(?:" + escaped + "[\\S\\s]|(?:(?!" + left.source + "|" + right.source + ")[^" + escaped + "])+)+", |
|
ignoreCase ? "i" : "" |
|
); |
|
} |
|
|
|
while (true) { |
|
/* advance the starting search position to the end of the last delimiter match. |
|
a couple special cases are also covered: |
|
- if using an escape character, advance to the next delimiter's starting position, |
|
skipping any escaped characters |
|
- first time through, reset lastIndex in case delimiters were provided as regexes |
|
*/ |
|
left.lastIndex = right.lastIndex = delimEnd + |
|
(escapeChar ? (esc.exec(str.slice(delimEnd)) || [""])[0].length : 0); |
|
|
|
leftMatch = left.exec(str); |
|
rightMatch = right.exec(str); |
|
|
|
// only keep the result which matched earlier in the string |
|
if (leftMatch && rightMatch) { |
|
if (leftMatch.index <= rightMatch.index) |
|
rightMatch = null; |
|
else leftMatch = null; |
|
} |
|
|
|
/* paths*: |
|
leftMatch | rightMatch | openTokens | result |
|
1 | 0 | 1 | ... |
|
1 | 0 | 0 | ... |
|
0 | 1 | 1 | ... |
|
0 | 1 | 0 | throw |
|
0 | 0 | 1 | throw |
|
0 | 0 | 0 | break |
|
* - does not include the sticky mode special case |
|
- the loop ends after the first completed match if not in global mode |
|
*/ |
|
|
|
if (leftMatch || rightMatch) { |
|
delimStart = (leftMatch || rightMatch).index; |
|
delimEnd = (leftMatch ? left : right).lastIndex; |
|
} else if (!openTokens) { |
|
break; |
|
} |
|
|
|
if (sticky && !openTokens && delimStart > lastOuterEnd) |
|
break; |
|
|
|
if (leftMatch) { |
|
if (!openTokens++) { |
|
outerStart = delimStart; |
|
innerStart = delimEnd; |
|
} |
|
} else if (rightMatch && openTokens) { |
|
if (!--openTokens) { |
|
if (vN) { |
|
if (vN[0] && outerStart > lastOuterEnd) |
|
output.push([vN[0], str.slice(lastOuterEnd, outerStart), lastOuterEnd, outerStart]); |
|
if (vN[1]) output.push([vN[1], str.slice(outerStart, innerStart), outerStart, innerStart]); |
|
if (vN[2]) output.push([vN[2], str.slice(innerStart, delimStart), innerStart, delimStart]); |
|
if (vN[3]) output.push([vN[3], str.slice(delimStart, delimEnd), delimStart, delimEnd]); |
|
} else { |
|
output.push(str.slice(innerStart, delimStart)); |
|
} |
|
lastOuterEnd = delimEnd; |
|
if (!global) |
|
break; |
|
} |
|
} else { |
|
// reset lastIndex in case delimiters were provided as regexes |
|
left.lastIndex = right.lastIndex = 0; |
|
throw Error("subject data contains unbalanced delimiters"); |
|
} |
|
|
|
// if the delimiter matched an empty string, advance delimEnd to avoid an infinite loop |
|
if (delimStart === delimEnd) |
|
delimEnd++; |
|
} |
|
|
|
if (global && !sticky && vN && vN[0] && str.length > lastOuterEnd) |
|
output.push([vN[0], str.slice(lastOuterEnd), lastOuterEnd, str.length]); |
|
|
|
// reset lastIndex in case delimiters were provided as regexes |
|
left.lastIndex = right.lastIndex = 0; |
|
|
|
return output; |
|
}; |
|
/** |
|
* SyntaxHighlighter |
|
* http://alexgorbatchev.com/ |
|
* |
|
* SyntaxHighlighter is donationware. If you are using it, please donate. |
|
* http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate |
|
* |
|
* @version |
|
* 2.0.320 (May 03 2009) |
|
* |
|
* @copyright |
|
* Copyright (C) 2004-2009 Alex Gorbatchev. |
|
* |
|
* @license |
|
* This file is part of SyntaxHighlighter. |
|
* |
|
* SyntaxHighlighter is free software: you can redistribute it and/or modify |
|
* it under the terms of the GNU Lesser General Public License as published by |
|
* the Free Software Foundation, either version 3 of the License, or |
|
* (at your option) any later version. |
|
* |
|
* SyntaxHighlighter is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with SyntaxHighlighter. If not, see <http://www.gnu.org/copyleft/lesser.html>. |
|
*/ |
|
SyntaxHighlighter.brushes.Xml = function() |
|
{ |
|
function process(match, regexInfo) |
|
{ |
|
var constructor = SyntaxHighlighter.Match, |
|
code = match[0], |
|
tag = new XRegExp('(<|<)[\\s\\/\\?]*(?<name>[:\\w-\\.]+)', 'xg').exec(code), |
|
result = [] |
|
; |
|
|
|
if (match.attributes != null) |
|
{ |
|
var attributes, |
|
regex = new XRegExp('(?<name> [\\w:\\-\\.]+)' + |
|
'\\s*=\\s*' + |
|
'(?<value> ".*?"|\'.*?\'|\\w+)', |
|
'xg'); |
|
|
|
while ((attributes = regex.exec(code)) != null) |
|
{ |
|
result.push(new constructor(attributes.name, match.index + attributes.index, 'color1')); |
|
result.push(new constructor(attributes.value, match.index + attributes.index + attributes[0].indexOf(attributes.value), 'string')); |
|
} |
|
} |
|
|
|
if (tag != null) |
|
result.push( |
|
new constructor(tag.name, match.index + tag[0].indexOf(tag.name), 'keyword') |
|
); |
|
|
|
return result; |
|
} |
|
|
|
this.regexList = [ |
|
{ regex: new XRegExp('(\\<|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\\>|>)', 'gm'), css: 'color2' }, // <![ ... [ ... ]]> |
|
{ regex: new XRegExp('(\\<|<)!--\\s*.*?\\s*--(\\>|>)', 'gm'), css: 'comments' }, // <!-- ... --> |
|
{ regex: new XRegExp('(<|<)[\\s\\/\\?]*(\\w+)(?<attributes>.*?)[\\s\\/\\?]*(>|>)', 'sg'), func: process } |
|
]; |
|
}; |
|
|
|
SyntaxHighlighter.brushes.Xml.prototype = new SyntaxHighlighter.Highlighter(); |
|
SyntaxHighlighter.brushes.Xml.aliases = ['xml', 'xhtml', 'xslt', 'html', 'xhtml']; |
|
/** |
|
* SyntaxHighlighter |
|
* http://alexgorbatchev.com/ |
|
* |
|
* SyntaxHighlighter is donationware. If you are using it, please donate. |
|
* http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate |
|
* |
|
* @version |
|
* 2.0.320 (May 03 2009) |
|
* |
|
* @copyright |
|
* Copyright (C) 2004-2009 Alex Gorbatchev. |
|
* |
|
* @license |
|
* This file is part of SyntaxHighlighter. |
|
* |
|
* SyntaxHighlighter is free software: you can redistribute it and/or modify |
|
* it under the terms of the GNU Lesser General Public License as published by |
|
* the Free Software Foundation, either version 3 of the License, or |
|
* (at your option) any later version. |
|
* |
|
* SyntaxHighlighter is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with SyntaxHighlighter. If not, see <http://www.gnu.org/copyleft/lesser.html>. |
|
*/ |
|
SyntaxHighlighter.brushes.JScript = function() |
|
{ |
|
var keywords = 'break case catch continue ' + |
|
'default delete do else false ' + |
|
'for function if in instanceof ' + |
|
'new null return super switch ' + |
|
'this throw true try typeof var while with' |
|
; |
|
|
|
this.regexList = [ |
|
{ regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments |
|
{ regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments |
|
{ regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings |
|
{ regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // single quoted strings |
|
{ regex: /\s*#.*/gm, css: 'preprocessor' }, // preprocessor tags like #region and #endregion |
|
{ regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // keywords |
|
]; |
|
|
|
this.forHtmlScript(SyntaxHighlighter.regexLib.scriptScriptTags); |
|
}; |
|
|
|
SyntaxHighlighter.brushes.JScript.prototype = new SyntaxHighlighter.Highlighter(); |
|
SyntaxHighlighter.brushes.JScript.aliases = ['js', 'jscript', 'javascript']; |
|
|
|
|
|
SyntaxHighlighter.config.clipboardSwf = 'syntax/clipboard.swf'; |
|
$(function () { |
|
var divs = $([]); |
|
$("#container .source").each(function () { |
|
var code = $(this).html().replace(/</g,'<').replace(/>/g,'>'), |
|
div = $('<div class="code"><pre class="brush:' + ( $(this).is("script") ? 'js' : 'xml' ) + ';">' + code + '</pre></div>'), |
|
demo = $(this).prevAll(".demo:eq(0)"); |
|
$(this).after(div); |
|
if(!$(this).hasClass("below")) divs = divs.add(div); |
|
}); |
|
SyntaxHighlighter.all(); |
|
|
|
setTimeout((function (divs) { |
|
return function () { |
|
divs.each(function () { |
|
var div = $(this), |
|
demo = $(this).prevAll(".demo:eq(0)"), |
|
h = false; |
|
var h = Math.max(demo[0].offsetHeight, div[0].offsetHeight); |
|
if(h) { |
|
if(h < 198) h = 198; |
|
div.height(h); |
|
demo.height(h); |
|
} |
|
}); |
|
} |
|
})(divs), 500); |
|
|
|
// $(".panel").hide().prev().click(function () { $(this).next().toggle(); }).css("cursor","pointer"); |
|
});
|
|
|