diff options
author | Leif Johansson <leifj@sunet.se> | 2012-10-02 22:23:54 +0200 |
---|---|---|
committer | Leif Johansson <leifj@sunet.se> | 2012-10-02 22:23:54 +0200 |
commit | ec839d583fff6b279c7cdec2fdf87762f81f9aa5 (patch) | |
tree | 912507bfc3353ba076ae225a8d40ba14f57d2972 /src/static/js/shCore.js | |
parent | 2346efdb58afff79fcfc1d581b0091f32ee6fac1 (diff) |
- bootstrap
- cleanup
- bugfixes
Diffstat (limited to 'src/static/js/shCore.js')
-rw-r--r-- | src/static/js/shCore.js | 1721 |
1 files changed, 0 insertions, 1721 deletions
diff --git a/src/static/js/shCore.js b/src/static/js/shCore.js deleted file mode 100644 index 4214763..0000000 --- a/src/static/js/shCore.js +++ /dev/null @@ -1,1721 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/SyntaxHighlighter - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/SyntaxHighlighter/donate.html - * - * @version - * 3.0.83 (July 02 2010) - * - * @copyright - * Copyright (C) 2004-2010 Alex Gorbatchev. - * - * @license - * Dual licensed under the MIT and GPL licenses. - */ -// -// Begin anonymous function. This is used to contain local scope variables without polutting global scope. -// -var SyntaxHighlighter = function() { - -// CommonJS -if (typeof(require) != 'undefined' && typeof(XRegExp) == 'undefined') -{ - XRegExp = require('XRegExp').XRegExp; -} - -// 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' : false, - - /** Lines to highlight. */ - 'highlight' : null, - - /** Title to be displayed above the code block. */ - 'title' : 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, - - /** Enables quick code copy and paste from double click. */ - 'quick-code' : 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, - - 'html-script' : false - }, - - config : { - space : ' ', - - /** Enables use of <SCRIPT type="syntaxhighlighter" /> tags. */ - useScriptTags : true, - - /** Blogger mode flag. */ - bloggerMode : false, - - stripBrs : false, - - /** Name of the tag that SyntaxHighlighter will automatically look for. */ - tagName : 'pre', - - strings : { - expandSource : 'expand source', - 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:1.5em;"><div style="font-size:xx-large;">SyntaxHighlighter</div><div style="font-size:.75em;margin-bottom:3em;"><div>version 3.0.83 (July 02 2010)</div><div><a href="http://alexgorbatchev.com/SyntaxHighlighter" target="_blank" style="color:#005896">http://alexgorbatchev.com/SyntaxHighlighter</a></div><div>JavaScript code syntax highlighter.</div><div>Copyright 2004-2010 Alex Gorbatchev.</div></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:#005896">donate</a> to <br/>keep development active!</div></div></body></html>' - } - }, - - /** Internal 'global' variables. */ - vars : { - discoveredBrushes : 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 : new XRegExp('"([^\\\\"]|\\\\.)*"', 'gs'), - multiLineSingleQuotedString : new XRegExp("'([^\\\\']|\\\\.)*'", 'gs'), - xmlComments : /(<|<)!--[\s\S]*?--(>|>)/gm, - url : /\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: { - /** - * Generates HTML markup for the toolbar. - * @param {Highlighter} highlighter Highlighter instance. - * @return {String} Returns HTML markup. - */ - getHtml: function(highlighter) - { - var html = '<div class="toolbar">', - items = sh.toolbar.items, - list = items.list - ; - - function defaultGetHtml(highlighter, name) - { - return sh.toolbar.getButtonHtml(highlighter, name, sh.config.strings[name]); - }; - - for (var i = 0; i < list.length; i++) - html += (items[list[i]].getHtml || defaultGetHtml)(highlighter, list[i]); - - html += '</div>'; - - return html; - }, - - /** - * Generates HTML markup for a regular button in the toolbar. - * @param {Highlighter} highlighter Highlighter instance. - * @param {String} commandName Command name that would be executed. - * @param {String} label Label text to display. - * @return {String} Returns HTML markup. - */ - getButtonHtml: function(highlighter, commandName, label) - { - return '<span><a href="#" class="toolbar_item' - + ' command_' + commandName - + ' ' + commandName - + '">' + label + '</a></span>' - ; - }, - - /** - * Event handler for a toolbar anchor. - */ - handler: function(e) - { - var target = e.target, - className = target.className || '' - ; - - function getValue(name) - { - var r = new RegExp(name + '_(\\w+)'), - match = r.exec(className) - ; - - return match ? match[1] : null; - }; - - var highlighter = getHighlighterById(findParentElement(target, '.syntaxhighlighter').id), - commandName = getValue('command') - ; - - // execute the toolbar command - if (highlighter && commandName) - sh.toolbar.items[commandName].execute(highlighter); - - // disable default A click behaviour - e.preventDefault(); - }, - - /** Collection of toolbar items. */ - items : { - // Ordered lis of items in the toolbar. Can't expect `for (var n in items)` to be consistent. - list: ['expandSource', 'help'], - - expandSource: { - getHtml: function(highlighter) - { - if (highlighter.getParam('collapse') != true) - return ''; - - var title = highlighter.getParam('title'); - return sh.toolbar.getButtonHtml(highlighter, 'expandSource', title ? title : sh.config.strings.expandSource); - }, - - execute: function(highlighter) - { - var div = getHighlighterDivById(highlighter.id); - removeClass(div, 'collapsed'); - } - }, - - /** Command to display the about dialog window. */ - help: { - execute: function(highlighter) - { - var wnd = popup('', '_blank', 500, 250, 'scrollbars=0'), - doc = wnd.document - ; - - doc.write(sh.config.strings.aboutDialog); - doc.close(); - wnd.focus(); - } - } - } - }, - - /** - * Finds all elements on the page which should be processes by SyntaxHighlighter. - * - * @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 returned which qualify. - * - * @return {Array} Returns list of <code>{ target: DOMElement, params: Object }</code> objects. - */ - findElements: function(globalParams, element) - { - var elements = element ? [element] : toArray(document.getElementsByTagName(sh.config.tagName)), - conf = sh.config, - result = [] - ; - - // support for <SCRIPT TYPE="syntaxhighlighter" /> feature - if (conf.useScriptTags) - elements = elements.concat(getSyntaxHighlighterScriptTags()); - - if (elements.length === 0) - return result; - - for (var i = 0; i < elements.length; i++) - { - var item = { - target: elements[i], - // local params take precedence over globals - params: merge(globalParams, parseParams(elements[i].className)) - }; - - if (item.params['brush'] == null) - continue; - - result.push(item); - } - - return result; - }, - - /** - * 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) - { - var elements = this.findElements(globalParams, element), - propertyName = 'innerHTML', - highlighter = null, - conf = sh.config - ; - - if (elements.length === 0) - return; - - for (var i = 0; i < elements.length; i++) - { - var element = elements[i], - target = element.target, - params = element.params, - brushName = params.brush, - code - ; - - 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 = findBrush(brushName); - - if (brush) - highlighter = new brush(); - else - continue; - } - - code = target[propertyName]; - - // remove CDATA from <SCRIPT/> tags if it's present - if (conf.useScriptTags) - code = stripCData(code); - - // Inject title if the attribute is present - if ((target.title || '') != '') - params.title = target.title; - - params['brush'] = brushName; - highlighter.init(params); - element = highlighter.getDiv(code); - - // carry over ID - if ((target.id || '') != '') - element.id = target.id; - - target.parentNode.replaceChild(element, target); - } - }, - - /** - * Main entry point for the SyntaxHighlighter. - * @param {Object} params Optional params to apply to all highlighted elements. - */ - all: function(params) - { - attachEvent( - window, - 'load', - function() { sh.highlight(params); } - ); - } -}; // end of sh - -sh['all'] = sh.all; -sh['highlight'] = sh.highlight; - -/** - * Checks if target DOM elements has specified CSS class. - * @param {DOMElement} target Target DOM element to check. - * @param {String} className Name of the CSS class to check for. - * @return {Boolean} Returns true if class name is present, false otherwise. - */ -function hasClass(target, className) -{ - return target.className.indexOf(className) != -1; -}; - -/** - * Adds CSS class name to the target DOM element. - * @param {DOMElement} target Target DOM element. - * @param {String} className New CSS class to add. - */ -function addClass(target, className) -{ - if (!hasClass(target, className)) - target.className += ' ' + className; -}; - -/** - * Removes CSS class name from the target DOM element. - * @param {DOMElement} target Target DOM element. - * @param {String} className CSS class to remove. - */ -function removeClass(target, className) -{ - target.className = target.className.replace(className, ''); -}; - -/** - * Converts the source to array object. Mostly used for function arguments and - * lists returned by getElementsByTagName() which aren't Array objects. - * @param {List} source Source list. - * @return {Array} Returns array. - */ -function toArray(source) -{ - var result = []; - - for (var i = 0; i < source.length; i++) - result.push(source[i]); - - return result; -}; - -/** - * Splits block of text into lines. - * @param {String} block Block of text. - * @return {Array} Returns array of lines. - */ -function splitLines(block) -{ - return block.split('\n'); -} - -/** - * Generates HTML ID for the highlighter. - * @param {String} highlighterId Highlighter ID. - * @return {String} Returns HTML ID. - */ -function getHighlighterId(id) -{ - var prefix = 'highlighter_'; - return id.indexOf(prefix) == 0 ? id : prefix + id; -}; - -/** - * Finds Highlighter instance by ID. - * @param {String} highlighterId Highlighter ID. - * @return {Highlighter} Returns instance of the highlighter. - */ -function getHighlighterById(id) -{ - return sh.vars.highlighters[getHighlighterId(id)]; -}; - -/** - * Finds highlighter's DIV container. - * @param {String} highlighterId Highlighter ID. - * @return {Element} Returns highlighter's DIV element. - */ -function getHighlighterDivById(id) -{ - return document.getElementById(getHighlighterId(id)); -}; - -/** - * Stores highlighter so that getHighlighterById() can do its thing. Each - * highlighter must call this method to preserve itself. - * @param {Highilghter} highlighter Highlighter instance. - */ -function storeHighlighter(highlighter) -{ - sh.vars.highlighters[getHighlighterId(highlighter.id)] = highlighter; -}; - -/** - * Looks for a child or parent node which has specified classname. - * Equivalent to jQuery's $(container).find(".className") - * @param {Element} target Target element. - * @param {String} search Class name or node name to look for. - * @param {Boolean} reverse If set to true, will go up the node tree instead of down. - * @return {Element} Returns found child or parent element on null. - */ -function findElement(target, search, reverse /* optional */) -{ - if (target == null) - return null; - - var nodes = reverse != true ? target.childNodes : [ target.parentNode ], - propertyToFind = { '#' : 'id', '.' : 'className' }[search.substr(0, 1)] || 'nodeName', - expectedValue, - found - ; - - expectedValue = propertyToFind != 'nodeName' - ? search.substr(1) - : search.toUpperCase() - ; - - // main return of the found node - if ((target[propertyToFind] || '').indexOf(expectedValue) != -1) - return target; - - for (var i = 0; nodes && i < nodes.length && found == null; i++) - found = findElement(nodes[i], search, reverse); - - return found; -}; - -/** - * Looks for a parent node which has specified classname. - * This is an alias to <code>findElement(container, className, true)</code>. - * @param {Element} target Target element. - * @param {String} className Class name to look for. - * @return {Element} Returns found parent element on null. - */ -function findParentElement(target, className) -{ - return findElement(target, className, true); -}; - -/** - * 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. - */ -function indexOf(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. - */ -function guid(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. - */ -function merge(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. - */ -function toBoolean(value) -{ - var result = { "true" : true, "false" : false }[value]; - return result == null ? value : result; -}; - -/** - * 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. - */ -function popup(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. - */ -function attachEvent(obj, type, func, scope) -{ - function handler(e) - { - e = e || window.event; - - if (!e.target) - { - e.target = e.srcElement; - e.preventDefault = function() - { - this.returnValue = false; - }; - } - - func.call(scope || window, e); - }; - - if (obj.attachEvent) - { - obj.attachEvent('on' + type, handler); - } - else - { - obj.addEventListener(type, handler, false); - } -}; - -/** - * Displays an alert. - * @param {String} str String to display. - */ -function alert(str) -{ - window.alert(sh.config.strings.alert + str); -}; - -/** - * Finds a brush by its alias. - * - * @param {String} alias Brush alias. - * @param {Boolean} showAlert Suppresses the alert if false. - * @return {Brush} Returns bursh constructor if found, null otherwise. - */ -function findBrush(alias, showAlert) -{ - var brushes = sh.vars.discoveredBrushes, - result = null - ; - - if (brushes == null) - { - brushes = {}; - - // Find all brushes - for (var brush in sh.brushes) - { - var info = sh.brushes[brush], - aliases = info.aliases - ; - - if (aliases == null) - continue; - - // keep the brush name - info.brushName = 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 && showAlert != false) - 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. - */ -function eachLine(str, callback) -{ - var lines = splitLines(str); - - for (var i = 0; i < lines.length; i++) - lines[i] = callback(lines[i], 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. - */ -function trimFirstAndLastLines(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. - */ -function parseParams(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. - */ -function wrapLinesWithCode(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 += sh.config.space; - - return spaces + ' '; - }); - - // Split each line and apply <span class="...">...</span> to them so that - // leading spaces aren't included. - if (css != null) - str = 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'. - */ -function padNumber(number, length) -{ - var result = number.toString(); - - while (result.length < length) - result = '0' + result; - - 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. - */ -function processTabs(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. - */ -function processSmartTabs(code, tabSize) -{ - var lines = splitLines(code), - 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 = 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. - */ -function fixInputString(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. - */ -function trim(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. - */ -function unindent(str) -{ - var lines = splitLines(fixInputString(str)), - 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 (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. - */ -function matchesSortCallback(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. - */ -function getMatches(code, regexInfo) -{ - function defaultAdd(match, regexInfo) - { - return match[0]; - }; - - var index = 0, - match = null, - matches = [], - func = regexInfo.func ? regexInfo.func : defaultAdd - ; - - while((match = regexInfo.regex.exec(code)) != null) - { - var resultMatch = func(match, regexInfo); - - if (typeof(resultMatch) == 'string') - resultMatch = [new sh.Match(resultMatch, match.index, regexInfo.css)]; - - matches = matches.concat(resultMatch); - } - - return matches; -}; - -/** - * Turns all URLs in the code into <a/> tags. - * @param {String} code Input code. - * @return {String} Returns code with </a> tags. - */ -function processUrls(code) -{ - var gt = /(.*)((>|<).*)/; - - return code.replace(sh.regexLib.url, function(m) - { - var suffix = '', - match = null - ; - - // 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 (match = gt.exec(m)) - { - m = match[1]; - suffix = match[2]; - } - - return '<a href="' + m + '">' + m + '</a>' + suffix; - }); -}; - -/** - * Finds all <SCRIPT TYPE="syntaxhighlighter" /> elementss. - * @return {Array} Returns array of all found SyntaxHighlighter tags. - */ -function getSyntaxHighlighterScriptTags() -{ - 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. - */ -function stripCData(original) -{ - var left = '<![CDATA[', - right = ']]>', - // for some reason IE inserts some leading blanks here - copy = trim(original), - changed = false, - leftLength = left.length, - rightLength = right.length - ; - - if (copy.indexOf(left) == 0) - { - copy = copy.substring(leftLength); - changed = true; - } - - var copyLength = copy.length; - - if (copy.indexOf(right) == copyLength - rightLength) - { - copy = copy.substring(0, copyLength - rightLength); - changed = true; - } - - return changed ? copy : original; -}; - - -/** - * Quick code mouse double click handler. - */ -function quickCodeHandler(e) -{ - var target = e.target, - highlighterDiv = findParentElement(target, '.syntaxhighlighter'), - container = findParentElement(target, '.container'), - textarea = document.createElement('textarea'), - highlighter - ; - - if (!container || !highlighterDiv || findElement(container, 'textarea')) - return; - - highlighter = getHighlighterById(highlighterDiv.id); - - // add source class name - addClass(highlighterDiv, 'source'); - - // Have to go over each line and grab it's text, can't just do it on the - // container because Firefox loses all \n where as Webkit doesn't. - var lines = container.childNodes, - code = [] - ; - - for (var i = 0; i < lines.length; i++) - code.push(lines[i].innerText || lines[i].textContent); - - // using \r instead of \r or \r\n makes this work equally well on IE, FF and Webkit - code = code.join('\r'); - - // inject <textarea/> tag - textarea.appendChild(document.createTextNode(code)); - container.appendChild(textarea); - - // preselect all text - textarea.focus(); - textarea.select(); - - // set up handler for lost focus - attachEvent(textarea, 'blur', function(e) - { - textarea.parentNode.removeChild(textarea); - removeClass(highlighterDiv, 'source'); - }); -}; - -/** - * 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 = findBrush(scriptBrushName), - scriptBrush, - xmlBrush = new sh.brushes.Xml(), - bracketsRegex = null, - ref = this, - methodsToExpose = 'getDiv getHtml init'.split(' ') - ; - - if (brushClass == null) - return; - - scriptBrush = new brushClass(); - - for(var i = 0; i < methodsToExpose.length; i++) - // make a closure so we don't lose the name after i changes - (function() { - var name = methodsToExpose[i]; - - ref[name] = function() - { - return xmlBrush[name].apply(xmlBrush, arguments); - }; - })(); - - if (scriptBrush.htmlScript == null) - { - 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 = getMatches(code, regexList[i]); - offsetMatches(result, offset); - matches = matches.concat(result); - } - - // add left script bracket - if (htmlScript.left != null && match.left != null) - { - result = 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 = 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.brushName; - - return matches; - } -}; - -/** - * Main Highlither class. - * @constructor - */ -sh.Highlighter = function() -{ - // not putting any code in here because of the prototype inheritance -}; - -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 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(getMatches(code, regexList[i])); - - // sort and remove nested the matches - return this.removeNestedMatches(result.sort(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(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) - matches[i] = null; - else if (itemJ.index >= itemI.index && itemJ.index < itemIEndPos) - matches[j] = null; - } - } - - return matches; - }, - - /** - * Creates an array containing integer line numbers starting from the 'first-line' param. - * @return {Array} Returns array of integers. - */ - figureOutLineNumbers: function(code) - { - var lines = [], - firstLine = parseInt(this.getParam('first-line')) - ; - - eachLine(code, function(line, index) - { - lines.push(index + firstLine); - }); - - return lines; - }, - - /** - * Determines if specified line number is in the highlighted list. - */ - isLineHighlighted: function(lineNumber) - { - var list = this.getParam('highlight', []); - - if (typeof(list) != 'object' && list.push == null) - list = [ list ]; - - return indexOf(list, lineNumber.toString()) != -1; - }, - - /** - * Generates HTML markup for a single line of code while determining alternating line style. - * @param {Integer} lineNumber Line number. - * @param {String} code Line HTML markup. - * @return {String} Returns HTML markup. - */ - getLineHtml: function(lineIndex, lineNumber, code) - { - var classes = [ - 'line', - 'number' + lineNumber, - 'index' + lineIndex, - 'alt' + (lineNumber % 2 == 0 ? 1 : 2).toString() - ]; - - if (this.isLineHighlighted(lineNumber)) - classes.push('highlighted'); - - if (lineNumber == 0) - classes.push('break'); - - return '<div class="' + classes.join(' ') + '">' + code + '</div>'; - }, - - /** - * Generates HTML markup for line number column. - * @param {String} code Complete code HTML markup. - * @param {Array} lineNumbers Calculated line numbers. - * @return {String} Returns HTML markup. - */ - getLineNumbersHtml: function(code, lineNumbers) - { - var html = '', - count = splitLines(code).length, - firstLine = parseInt(this.getParam('first-line')), - pad = this.getParam('pad-line-numbers') - ; - - if (pad == true) - pad = (firstLine + count - 1).toString().length; - else if (isNaN(pad) == true) - pad = 0; - - for (var i = 0; i < count; i++) - { - var lineNumber = lineNumbers ? lineNumbers[i] : firstLine + i, - code = lineNumber == 0 ? sh.config.space : padNumber(lineNumber, pad) - ; - - html += this.getLineHtml(i, lineNumber, code); - } - - return html; - }, - - /** - * Splits block of text into individual DIV lines. - * @param {String} code Code to highlight. - * @param {Array} lineNumbers Calculated line numbers. - * @return {String} Returns highlighted code in HTML form. - */ - getCodeLinesHtml: function(html, lineNumbers) - { - html = trim(html); - - var lines = splitLines(html), - padLength = this.getParam('pad-line-numbers'), - firstLine = parseInt(this.getParam('first-line')), - html = '', - brushName = this.getParam('brush') - ; - - for (var i = 0; i < lines.length; i++) - { - var line = lines[i], - indent = /^( |\s)+/.exec(line), - spaces = null, - lineNumber = lineNumbers ? lineNumbers[i] : firstLine + i; - ; - - if (indent != null) - { - spaces = indent[0].toString(); - line = line.substr(spaces.length); - spaces = spaces.replace(' ', sh.config.space); - } - - line = trim(line); - - if (line.length == 0) - line = sh.config.space; - - html += this.getLineHtml( - i, - lineNumber, - (spaces != null ? '<code class="' + brushName + ' spaces">' + spaces + '</code>' : '') + line - ); - } - - return html; - }, - - /** - * Returns HTML for the table title or empty string if title is null. - */ - getTitleHtml: function(title) - { - return title ? '<caption>' + title + '</caption>' : ''; - }, - - /** - * 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. - */ - getMatchesHtml: function(code, matches) - { - var pos = 0, - result = '', - brushName = this.getParam('brush', '') - ; - - 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 += wrapLinesWithCode(code.substr(pos, match.index - pos), matchBrushName + 'plain') - + wrapLinesWithCode(match.value, matchBrushName + match.css) - ; - - pos = match.index + match.length + (match.offset || 0); - } - - // don't forget to add whatever's remaining in the string - result += wrapLinesWithCode(code.substr(pos), getBrushNameCss() + 'plain'); - - return result; - }, - - /** - * Generates HTML markup for the whole syntax highlighter. - * @param {String} code Source code. - * @return {String} Returns HTML markup. - */ - getHtml: function(code) - { - var html = '', - classes = [ 'syntaxhighlighter' ], - tabSize, - matches, - lineNumbers - ; - - // process light mode - if (this.getParam('light') == true) - this.params.toolbar = this.params.gutter = false; - - className = 'syntaxhighlighter'; - - if (this.getParam('collapse') == true) - classes.push('collapsed'); - - if ((gutter = this.getParam('gutter')) == false) - classes.push('nogutter'); - - // add custom user style name - classes.push(this.getParam('class-name')); - - // add brush alias to the class name for custom CSS - classes.push(this.getParam('brush')); - - code = trimFirstAndLastLines(code) - .replace(/\r/g, ' ') // IE lets these buggers through - ; - - tabSize = this.getParam('tab-size'); - - // replace tabs with spaces - code = this.getParam('smart-tabs') == true - ? processSmartTabs(code, tabSize) - : processTabs(code, tabSize) - ; - - // unindent code by the common indentation - code = unindent(code); - - if (gutter) - lineNumbers = this.figureOutLineNumbers(code); - - // find matches in the code using brushes regex list - matches = this.findMatches(this.regexList, code); - // processes found matches into the html - html = this.getMatchesHtml(code, matches); - // finally, split all lines so that they wrap well - html = this.getCodeLinesHtml(html, lineNumbers); - - // finally, process the links - if (this.getParam('auto-links')) - html = processUrls(html); - - if (typeof(navigator) != 'undefined' && navigator.userAgent && navigator.userAgent.match(/MSIE/)) - classes.push('ie'); - - html = - '<div id="' + getHighlighterId(this.id) + '" class="' + classes.join(' ') + '">' - + (this.getParam('toolbar') ? sh.toolbar.getHtml(this) : '') - + '<table border="0" cellpadding="0" cellspacing="0">' - + this.getTitleHtml(this.getParam('title')) - + '<tbody>' - + '<tr>' - + (gutter ? '<td class="gutter">' + this.getLineNumbersHtml(code) + '</td>' : '') - + '<td class="code">' - + '<div class="container">' - + html - + '</div>' - + '</td>' - + '</tr>' - + '</tbody>' - + '</table>' - + '</div>' - ; - - return html; - }, - - /** - * Highlights the code and returns complete HTML. - * @param {String} code Code to highlight. - * @return {Element} Returns container DIV element with all markup. - */ - getDiv: function(code) - { - if (code === null) - code = ''; - - this.code = code; - - var div = this.create('div'); - - // create main HTML - div.innerHTML = this.getHtml(code); - - // set up click handlers - if (this.getParam('toolbar')) - attachEvent(findElement(div, '.toolbar'), 'click', sh.toolbar.handler); - - if (this.getParam('quick-code')) - attachEvent(findElement(div, '.code'), 'dblclick', quickCodeHandler); - - return div; - }, - - /** - * Initializes the highlighter/brush. - * - * Constructor isn't used for initialization so that nothing executes during necessary - * `new SyntaxHighlighter.Highlighter()` call when setting up brush inheritence. - * - * @param {Hash} params Highlighter parameters. - */ - init: function(params) - { - this.id = guid(); - - // register this instance in the highlighters list - storeHighlighter(this); - - // local params take precedence over defaults - this.params = merge(sh.defaults, params || {}) - - // process light mode - if (this.getParam('light') == true) - this.params.toolbar = this.params.gutter = false; - }, - - /** - * 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 - -// CommonJS -typeof(exports) != 'undefined' ? exports['SyntaxHighlighter'] = SyntaxHighlighter : null; |