diff options
author | Leif Johansson <leifj@sunet.se> | 2011-06-02 00:28:36 +0200 |
---|---|---|
committer | Leif Johansson <leifj@sunet.se> | 2011-06-02 00:28:36 +0200 |
commit | a810ad5b2e9bc3debffffde58b0aaeadbf6729d6 (patch) | |
tree | cfe2d8ffdd753c28b61b003c3b0a089f208732c0 /src | |
parent | 04ddf5f258010f88a2778ba54cc01931615e4108 (diff) |
A simple widget-info view using syntaxhighlighter.
Diffstat (limited to 'src')
-rw-r--r-- | src/meetingtools/urls.py | 1 | ||||
-rw-r--r-- | src/site-media/css/shCore.css | 226 | ||||
-rw-r--r-- | src/site-media/css/shThemeDefault.css | 117 | ||||
-rw-r--r-- | src/site-media/js/shAutoloader.js | 130 | ||||
-rw-r--r-- | src/site-media/js/shBrushXml.js | 69 | ||||
-rw-r--r-- | src/site-media/js/shCore.js | 1721 | ||||
-rw-r--r-- | src/site-media/js/shLegacy.js | 157 | ||||
-rw-r--r-- | src/site-media/js/xregexp-min.js | 2 | ||||
-rw-r--r-- | src/templates/apps/room/widget.html | 51 | ||||
-rw-r--r-- | src/templates/base.html | 10 |
10 files changed, 2484 insertions, 0 deletions
diff --git a/src/meetingtools/urls.py b/src/meetingtools/urls.py index 703b49a..bfac344 100644 --- a/src/meetingtools/urls.py +++ b/src/meetingtools/urls.py @@ -37,6 +37,7 @@ urlpatterns = patterns('', (r'^room/(\d+)/recordings\.(?:atom)$',AtomRecordingFeed()), (r'^room/(\d+)/recordings\.(?:rss)$',RSSRecordingField()), (r'^room/\+(.+)$','meetingtools.apps.room.views.list_by_tag'), + (r'^widget/?\+?(.*)$','meetingtools.apps.room.views.widget'), # Uncomment the admin/doc line below to enable admin documentation: # (r'^admin/doc/', include('django.contrib.admindocs.urls')), diff --git a/src/site-media/css/shCore.css b/src/site-media/css/shCore.css new file mode 100644 index 0000000..34f6864 --- /dev/null +++ b/src/site-media/css/shCore.css @@ -0,0 +1,226 @@ +/** + * 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. + */ +.syntaxhighlighter a, +.syntaxhighlighter div, +.syntaxhighlighter code, +.syntaxhighlighter table, +.syntaxhighlighter table td, +.syntaxhighlighter table tr, +.syntaxhighlighter table tbody, +.syntaxhighlighter table thead, +.syntaxhighlighter table caption, +.syntaxhighlighter textarea { + -moz-border-radius: 0 0 0 0 !important; + -webkit-border-radius: 0 0 0 0 !important; + background: none !important; + border: 0 !important; + bottom: auto !important; + float: none !important; + height: auto !important; + left: auto !important; + line-height: 1.1em !important; + margin: 0 !important; + outline: 0 !important; + overflow: visible !important; + padding: 0 !important; + position: static !important; + right: auto !important; + text-align: left !important; + top: auto !important; + vertical-align: baseline !important; + width: auto !important; + box-sizing: content-box !important; + font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; + font-weight: normal !important; + font-style: normal !important; + font-size: 1em !important; + min-height: inherit !important; + min-height: auto !important; +} + +.syntaxhighlighter { + width: 100% !important; + margin: 1em 0 1em 0 !important; + position: relative !important; + overflow: auto !important; + font-size: 1em !important; +} +.syntaxhighlighter.source { + overflow: hidden !important; +} +.syntaxhighlighter .bold { + font-weight: bold !important; +} +.syntaxhighlighter .italic { + font-style: italic !important; +} +.syntaxhighlighter .line { + white-space: pre !important; +} +.syntaxhighlighter table { + width: 100% !important; +} +.syntaxhighlighter table caption { + text-align: left !important; + padding: .5em 0 0.5em 1em !important; +} +.syntaxhighlighter table td.code { + width: 100% !important; +} +.syntaxhighlighter table td.code .container { + position: relative !important; +} +.syntaxhighlighter table td.code .container textarea { + box-sizing: border-box !important; + position: absolute !important; + left: 0 !important; + top: 0 !important; + width: 100% !important; + height: 100% !important; + border: none !important; + background: white !important; + padding-left: 1em !important; + overflow: hidden !important; + white-space: pre !important; +} +.syntaxhighlighter table td.gutter .line { + text-align: right !important; + padding: 0 0.5em 0 1em !important; +} +.syntaxhighlighter table td.code .line { + padding: 0 1em !important; +} +.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { + padding-left: 0em !important; +} +.syntaxhighlighter.show { + display: block !important; +} +.syntaxhighlighter.collapsed table { + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar { + padding: 0.1em 0.8em 0em 0.8em !important; + font-size: 1em !important; + position: static !important; + width: auto !important; + height: auto !important; +} +.syntaxhighlighter.collapsed .toolbar span { + display: inline !important; + margin-right: 1em !important; +} +.syntaxhighlighter.collapsed .toolbar span a { + padding: 0 !important; + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar span a.expandSource { + display: inline !important; +} +.syntaxhighlighter .toolbar { + position: absolute !important; + right: 1px !important; + top: 1px !important; + width: 11px !important; + height: 11px !important; + font-size: 10px !important; + z-index: 10 !important; +} +.syntaxhighlighter .toolbar span.title { + display: inline !important; +} +.syntaxhighlighter .toolbar a { + display: block !important; + text-align: center !important; + text-decoration: none !important; + padding-top: 1px !important; +} +.syntaxhighlighter .toolbar a.expandSource { + display: none !important; +} +.syntaxhighlighter.ie { + font-size: .9em !important; + padding: 1px 0 1px 0 !important; +} +.syntaxhighlighter.ie .toolbar { + line-height: 8px !important; +} +.syntaxhighlighter.ie .toolbar a { + padding-top: 0px !important; +} +.syntaxhighlighter.printing .line.alt1 .content, +.syntaxhighlighter.printing .line.alt2 .content, +.syntaxhighlighter.printing .line.highlighted .number, +.syntaxhighlighter.printing .line.highlighted.alt1 .content, +.syntaxhighlighter.printing .line.highlighted.alt2 .content { + background: none !important; +} +.syntaxhighlighter.printing .line .number { + color: #bbbbbb !important; +} +.syntaxhighlighter.printing .line .content { + color: black !important; +} +.syntaxhighlighter.printing .toolbar { + display: none !important; +} +.syntaxhighlighter.printing a { + text-decoration: none !important; +} +.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { + color: black !important; +} +.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { + color: #008200 !important; +} +.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { + color: blue !important; +} +.syntaxhighlighter.printing .keyword { + color: #006699 !important; + font-weight: bold !important; +} +.syntaxhighlighter.printing .preprocessor { + color: gray !important; +} +.syntaxhighlighter.printing .variable { + color: #aa7700 !important; +} +.syntaxhighlighter.printing .value { + color: #009900 !important; +} +.syntaxhighlighter.printing .functions { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .constants { + color: #0066cc !important; +} +.syntaxhighlighter.printing .script { + font-weight: bold !important; +} +.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { + color: gray !important; +} +.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { + color: red !important; +} +.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { + color: black !important; +} diff --git a/src/site-media/css/shThemeDefault.css b/src/site-media/css/shThemeDefault.css new file mode 100644 index 0000000..1365411 --- /dev/null +++ b/src/site-media/css/shThemeDefault.css @@ -0,0 +1,117 @@ +/** + * 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. + */ +.syntaxhighlighter { + background-color: white !important; +} +.syntaxhighlighter .line.alt1 { + background-color: white !important; +} +.syntaxhighlighter .line.alt2 { + background-color: white !important; +} +.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { + background-color: #e0e0e0 !important; +} +.syntaxhighlighter .line.highlighted.number { + color: black !important; +} +.syntaxhighlighter table caption { + color: black !important; +} +.syntaxhighlighter .gutter { + color: #afafaf !important; +} +.syntaxhighlighter .gutter .line { + border-right: 3px solid #6ce26c !important; +} +.syntaxhighlighter .gutter .line.highlighted { + background-color: #6ce26c !important; + color: white !important; +} +.syntaxhighlighter.printing .line .content { + border: none !important; +} +.syntaxhighlighter.collapsed { + overflow: visible !important; +} +.syntaxhighlighter.collapsed .toolbar { + color: blue !important; + background: white !important; + border: 1px solid #6ce26c !important; +} +.syntaxhighlighter.collapsed .toolbar a { + color: blue !important; +} +.syntaxhighlighter.collapsed .toolbar a:hover { + color: red !important; +} +.syntaxhighlighter .toolbar { + color: white !important; + background: #6ce26c !important; + border: none !important; +} +.syntaxhighlighter .toolbar a { + color: white !important; +} +.syntaxhighlighter .toolbar a:hover { + color: black !important; +} +.syntaxhighlighter .plain, .syntaxhighlighter .plain a { + color: black !important; +} +.syntaxhighlighter .comments, .syntaxhighlighter .comments a { + color: #008200 !important; +} +.syntaxhighlighter .string, .syntaxhighlighter .string a { + color: blue !important; +} +.syntaxhighlighter .keyword { + color: #006699 !important; +} +.syntaxhighlighter .preprocessor { + color: gray !important; +} +.syntaxhighlighter .variable { + color: #aa7700 !important; +} +.syntaxhighlighter .value { + color: #009900 !important; +} +.syntaxhighlighter .functions { + color: #ff1493 !important; +} +.syntaxhighlighter .constants { + color: #0066cc !important; +} +.syntaxhighlighter .script { + font-weight: bold !important; + color: #006699 !important; + background-color: none !important; +} +.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { + color: gray !important; +} +.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { + color: red !important; +} + +.syntaxhighlighter .keyword { + font-weight: bold !important; +} diff --git a/src/site-media/js/shAutoloader.js b/src/site-media/js/shAutoloader.js new file mode 100644 index 0000000..3a95449 --- /dev/null +++ b/src/site-media/js/shAutoloader.js @@ -0,0 +1,130 @@ +/** + * 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. + */ +(function() { + +var sh = SyntaxHighlighter; + +/** + * Provides functionality to dynamically load only the brushes that a needed to render the current page. + * + * There are two syntaxes that autoload understands. For example: + * + * SyntaxHighlighter.autoloader( + * [ 'applescript', 'Scripts/shBrushAppleScript.js' ], + * [ 'actionscript3', 'as3', 'Scripts/shBrushAS3.js' ] + * ); + * + * or a more easily comprehendable one: + * + * SyntaxHighlighter.autoloader( + * 'applescript Scripts/shBrushAppleScript.js', + * 'actionscript3 as3 Scripts/shBrushAS3.js' + * ); + */ +sh.autoloader = function() +{ + var list = arguments, + elements = sh.findElements(), + brushes = {}, + scripts = {}, + all = SyntaxHighlighter.all, + allCalled = false, + allParams = null, + i + ; + + SyntaxHighlighter.all = function(params) + { + allParams = params; + allCalled = true; + }; + + function addBrush(aliases, url) + { + for (var i = 0; i < aliases.length; i++) + brushes[aliases[i]] = url; + }; + + function getAliases(item) + { + return item.pop + ? item + : item.split(/\s+/) + ; + } + + // create table of aliases and script urls + for (i = 0; i < list.length; i++) + { + var aliases = getAliases(list[i]), + url = aliases.pop() + ; + + addBrush(aliases, url); + } + + // dynamically add <script /> tags to the document body + for (i = 0; i < elements.length; i++) + { + var url = brushes[elements[i].params.brush]; + + if (!url) + continue; + + scripts[url] = false; + loadScript(url); + } + + function loadScript(url) + { + var script = document.createElement('script'), + done = false + ; + + script.src = url; + script.type = 'text/javascript'; + script.language = 'javascript'; + script.onload = script.onreadystatechange = function() + { + if (!done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) + { + done = true; + scripts[url] = true; + checkAll(); + + // Handle memory leak in IE + script.onload = script.onreadystatechange = null; + script.parentNode.removeChild(script); + } + }; + + // sync way of adding script tags to the page + document.body.appendChild(script); + }; + + function checkAll() + { + for(var url in scripts) + if (scripts[url] == false) + return; + + if (allCalled) + SyntaxHighlighter.highlight(allParams); + }; +}; + +})(); diff --git a/src/site-media/js/shBrushXml.js b/src/site-media/js/shBrushXml.js new file mode 100644 index 0000000..69d9fd0 --- /dev/null +++ b/src/site-media/js/shBrushXml.js @@ -0,0 +1,69 @@ +/** + * 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. + */ +;(function() +{ + // CommonJS + typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; + + function Brush() + { + 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: SyntaxHighlighter.regexLib.xmlComments, css: 'comments' }, // <!-- ... --> + { regex: new XRegExp('(<|<)[\\s\\/\\?]*(\\w+)(?<attributes>.*?)[\\s\\/\\?]*(>|>)', 'sg'), func: process } + ]; + }; + + Brush.prototype = new SyntaxHighlighter.Highlighter(); + Brush.aliases = ['xml', 'xhtml', 'xslt', 'html']; + + SyntaxHighlighter.brushes.Xml = Brush; + + // CommonJS + typeof(exports) != 'undefined' ? exports.Brush = Brush : null; +})(); diff --git a/src/site-media/js/shCore.js b/src/site-media/js/shCore.js new file mode 100644 index 0000000..4214763 --- /dev/null +++ b/src/site-media/js/shCore.js @@ -0,0 +1,1721 @@ +/** + * 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; diff --git a/src/site-media/js/shLegacy.js b/src/site-media/js/shLegacy.js new file mode 100644 index 0000000..36951c9 --- /dev/null +++ b/src/site-media/js/shLegacy.js @@ -0,0 +1,157 @@ +/** + * 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. + */ +var dp = { + SyntaxHighlighter : {} +}; + +dp.SyntaxHighlighter = { + parseParams: function( + input, + showGutter, + showControls, + collapseAll, + firstLine, + showColumns + ) + { + function getValue(list, name) + { + var regex = new XRegExp('^' + name + '\\[(?<value>\\w+)\\]$', 'gi'), + match = null + ; + + for (var i = 0; i < list.length; i++) + if ((match = regex.exec(list[i])) != null) + return match.value; + + return null; + }; + + function defaultValue(value, def) + { + return value != null ? value : def; + }; + + function asString(value) + { + return value != null ? value.toString() : null; + }; + + var parts = input.split(':'), + brushName = parts[0], + options = {}, + straight = { 'true' : true } + reverse = { 'true' : false }, + result = null, + defaults = SyntaxHighlighter.defaults + ; + + for (var i in parts) + options[parts[i]] = 'true'; + + showGutter = asString(defaultValue(showGutter, defaults.gutter)); + showControls = asString(defaultValue(showControls, defaults.toolbar)); + collapseAll = asString(defaultValue(collapseAll, defaults.collapse)); + showColumns = asString(defaultValue(showColumns, defaults.ruler)); + firstLine = asString(defaultValue(firstLine, defaults['first-line'])); + + return { + brush : brushName, + gutter : defaultValue(reverse[options.nogutter], showGutter), + toolbar : defaultValue(reverse[options.nocontrols], showControls), + collapse : defaultValue(straight[options.collapse], collapseAll), + // ruler : defaultValue(straight[options.showcolumns], showColumns), + 'first-line' : defaultValue(getValue(parts, 'firstline'), firstLine) + }; + }, + + HighlightAll: function( + name, + showGutter /* optional */, + showControls /* optional */, + collapseAll /* optional */, + firstLine /* optional */, + showColumns /* optional */ + ) + { + function findValue() + { + var a = arguments; + + for (var i = 0; i < a.length; i++) + { + if (a[i] === null) + continue; + + if (typeof(a[i]) == 'string' && a[i] != '') + return a[i] + ''; + + if (typeof(a[i]) == 'object' && a[i].value != '') + return a[i].value + ''; + } + + return null; + }; + + function findTagsByName(list, name, tagName) + { + var tags = document.getElementsByTagName(tagName); + + for (var i = 0; i < tags.length; i++) + if (tags[i].getAttribute('name') == name) + list.push(tags[i]); + } + + var elements = [], + highlighter = null, + registered = {}, + propertyName = 'innerHTML' + ; + + // for some reason IE doesn't find <pre/> by name, however it does see them just fine by tag name... + findTagsByName(elements, name, 'pre'); + findTagsByName(elements, name, 'textarea'); + + if (elements.length === 0) + return; + + for (var i = 0; i < elements.length; i++) + { + var element = elements[i], + params = findValue( + element.attributes['class'], element.className, + element.attributes['language'], element.language + ), + language = '' + ; + + if (params === null) + continue; + + params = dp.SyntaxHighlighter.parseParams( + params, + showGutter, + showControls, + collapseAll, + firstLine, + showColumns + ); + + SyntaxHighlighter.highlight(params, element); + } + } +}; diff --git a/src/site-media/js/xregexp-min.js b/src/site-media/js/xregexp-min.js new file mode 100644 index 0000000..611c803 --- /dev/null +++ b/src/site-media/js/xregexp-min.js @@ -0,0 +1,2 @@ +//XRegExp 1.5.0 <xregexp.com> MIT License
+var XRegExp;if(XRegExp){throw Error("can't load XRegExp twice in the same frame")}(function(){XRegExp=function(w,r){var q=[],u=XRegExp.OUTSIDE_CLASS,x=0,p,s,v,t,y;if(XRegExp.isRegExp(w)){if(r!==undefined){throw TypeError("can't supply flags when constructing one RegExp from another")}return j(w)}if(g){throw Error("can't call the XRegExp constructor within token definition functions")}r=r||"";p={hasNamedCapture:false,captureNames:[],hasFlag:function(z){return r.indexOf(z)>-1},setFlag:function(z){r+=z}};while(x<w.length){s=o(w,x,u,p);if(s){q.push(s.output);x+=(s.match[0].length||1)}else{if(v=m.exec.call(i[u],w.slice(x))){q.push(v[0]);x+=v[0].length}else{t=w.charAt(x);if(t==="["){u=XRegExp.INSIDE_CLASS}else{if(t==="]"){u=XRegExp.OUTSIDE_CLASS}}q.push(t);x++}}}y=RegExp(q.join(""),m.replace.call(r,h,""));y._xregexp={source:w,captureNames:p.hasNamedCapture?p.captureNames:null};return y};XRegExp.version="1.5.0";XRegExp.INSIDE_CLASS=1;XRegExp.OUTSIDE_CLASS=2;var c=/\$(?:(\d\d?|[$&`'])|{([$\w]+)})/g,h=/[^gimy]+|([\s\S])(?=[\s\S]*\1)/g,n=/^(?:[?*+]|{\d+(?:,\d*)?})\??/,g=false,k=[],m={exec:RegExp.prototype.exec,test:RegExp.prototype.test,match:String.prototype.match,replace:String.prototype.replace,split:String.prototype.split},a=m.exec.call(/()??/,"")[1]===undefined,e=function(){var p=/^/g;m.test.call(p,"");return !p.lastIndex}(),f=function(){var p=/x/g;m.replace.call("x",p,"");return !p.lastIndex}(),b=RegExp.prototype.sticky!==undefined,i={};i[XRegExp.INSIDE_CLASS]=/^(?:\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S]))/;i[XRegExp.OUTSIDE_CLASS]=/^(?:\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S])|\(\?[:=!]|[?*+]\?|{\d+(?:,\d*)?}\??)/;XRegExp.addToken=function(s,r,q,p){k.push({pattern:j(s,"g"+(b?"y":"")),handler:r,scope:q||XRegExp.OUTSIDE_CLASS,trigger:p||null})};XRegExp.cache=function(r,p){var q=r+"/"+(p||"");return XRegExp.cache[q]||(XRegExp.cache[q]=XRegExp(r,p))};XRegExp.copyAsGlobal=function(p){return j(p,"g")};XRegExp.escape=function(p){return p.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")};XRegExp.execAt=function(s,r,t,q){r=j(r,"g"+((q&&b)?"y":""));r.lastIndex=t=t||0;var p=r.exec(s);if(q){return(p&&p.index===t)?p:null}else{return p}};XRegExp.freezeTokens=function(){XRegExp.addToken=function(){throw Error("can't run addToken after freezeTokens")}};XRegExp.isRegExp=function(p){return Object.prototype.toString.call(p)==="[object RegExp]"};XRegExp.iterate=function(u,p,v,s){var t=j(p,"g"),r=-1,q;while(q=t.exec(u)){v.call(s,q,++r,u,t);if(t.lastIndex===q.index){t.lastIndex++}}if(p.global){p.lastIndex=0}};XRegExp.matchChain=function(q,p){return function r(s,x){var v=p[x].regex?p[x]:{regex:p[x]},u=j(v.regex,"g"),w=[],t;for(t=0;t<s.length;t++){XRegExp.iterate(s[t],u,function(y){w.push(v.backref?(y[v.backref]||""):y[0])})}return((x===p.length-1)||!w.length)?w:r(w,x+1)}([q],0)};RegExp.prototype.apply=function(q,p){return this.exec(p[0])};RegExp.prototype.call=function(p,q){return this.exec(q)};RegExp.prototype.exec=function(t){var r=m.exec.apply(this,arguments),q,p;if(r){if(!a&&r.length>1&&l(r,"")>-1){p=RegExp(this.source,m.replace.call(d(this),"g",""));m.replace.call(t.slice(r.index),p,function(){for(var u=1;u<arguments.length-2;u++){if(arguments[u]===undefined){r[u]=undefined}}})}if(this._xregexp&&this._xregexp.captureNames){for(var s=1;s<r.length;s++){q=this._xregexp.captureNames[s-1];if(q){r[q]=r[s]}}}if(!e&&this.global&&!r[0].length&&(this.lastIndex>r.index)){this.lastIndex--}}return r};if(!e){RegExp.prototype.test=function(q){var p=m.exec.call(this,q);if(p&&this.global&&!p[0].length&&(this.lastIndex>p.index)){this.lastIndex--}return !!p}}String.prototype.match=function(q){if(!XRegExp.isRegExp(q)){q=RegExp(q)}if(q.global){var p=m.match.apply(this,arguments);q.lastIndex=0;return p}return q.exec(this)};String.prototype.replace=function(r,s){var t=XRegExp.isRegExp(r),q,p,u;if(t&&typeof s.valueOf()==="string"&&s.indexOf("${")===-1&&f){return m.replace.apply(this,arguments)}if(!t){r=r+""}else{if(r._xregexp){q=r._xregexp.captureNames}}if(typeof s==="function"){p=m.replace.call(this,r,function(){if(q){arguments[0]=new String(arguments[0]);for(var v=0;v<q.length;v++){if(q[v]){arguments[0][q[v]]=arguments[v+1]}}}if(t&&r.global){r.lastIndex=arguments[arguments.length-2]+arguments[0].length}return s.apply(null,arguments)})}else{u=this+"";p=m.replace.call(u,r,function(){var v=arguments;return m.replace.call(s,c,function(x,w,A){if(w){switch(w){case"$":return"$";case"&":return v[0];case"`":return v[v.length-1].slice(0,v[v.length-2]);case"'":return v[v.length-1].slice(v[v.length-2]+v[0].length);default:var y="";w=+w;if(!w){return x}while(w>v.length-3){y=String.prototype.slice.call(w,-1)+y;w=Math.floor(w/10)}return(w?v[w]||"":"$")+y}}else{var z=+A;if(z<=v.length-3){return v[z]}z=q?l(q,A):-1;return z>-1?v[z+1]:x}})})}if(t&&r.global){r.lastIndex=0}return p};String.prototype.split=function(u,p){if(!XRegExp.isRegExp(u)){return m.split.apply(this,arguments)}var w=this+"",r=[],v=0,t,q;if(p===undefined||+p<0){p=Infinity}else{p=Math.floor(+p);if(!p){return[]}}u=XRegExp.copyAsGlobal(u);while(t=u.exec(w)){if(u.lastIndex>v){r.push(w.slice(v,t.index));if(t.length>1&&t.index<w.length){Array.prototype.push.apply(r,t.slice(1))}q=t[0].length;v=u.lastIndex;if(r.length>=p){break}}if(u.lastIndex===t.index){u.lastIndex++}}if(v===w.length){if(!m.test.call(u,"")||q){r.push("")}}else{r.push(w.slice(v))}return r.length>p?r.slice(0,p):r};function j(r,q){if(!XRegExp.isRegExp(r)){throw TypeError("type RegExp expected")}var p=r._xregexp;r=XRegExp(r.source,d(r)+(q||""));if(p){r._xregexp={source:p.source,captureNames:p.captureNames?p.captureNames.slice(0):null}}return r}function d(p){return(p.global?"g":"")+(p.ignoreCase?"i":"")+(p.multiline?"m":"")+(p.extended?"x":"")+(p.sticky?"y":"")}function o(v,u,w,p){var r=k.length,y,s,x;g=true;try{while(r--){x=k[r];if((w&x.scope)&&(!x.trigger||x.trigger.call(p))){x.pattern.lastIndex=u;s=x.pattern.exec(v);if(s&&s.index===u){y={output:x.handler.call(p,s,w),match:s};break}}}}catch(q){throw q}finally{g=false}return y}function l(s,q,r){if(Array.prototype.indexOf){return s.indexOf(q,r)}for(var p=r||0;p<s.length;p++){if(s[p]===q){return p}}return -1}XRegExp.addToken(/\(\?#[^)]*\)/,function(p){return m.test.call(n,p.input.slice(p.index+p[0].length))?"":"(?:)"});XRegExp.addToken(/\((?!\?)/,function(){this.captureNames.push(null);return"("});XRegExp.addToken(/\(\?<([$\w]+)>/,function(p){this.captureNames.push(p[1]);this.hasNamedCapture=true;return"("});XRegExp.addToken(/\\k<([\w$]+)>/,function(q){var p=l(this.captureNames,q[1]);return p>-1?"\\"+(p+1)+(isNaN(q.input.charAt(q.index+q[0].length))?"":"(?:)"):q[0]});XRegExp.addToken(/\[\^?]/,function(p){return p[0]==="[]"?"\\b\\B":"[\\s\\S]"});XRegExp.addToken(/^\(\?([imsx]+)\)/,function(p){this.setFlag(p[1]);return""});XRegExp.addToken(/(?:\s+|#.*)+/,function(p){return m.test.call(n,p.input.slice(p.index+p[0].length))?"":"(?:)"},XRegExp.OUTSIDE_CLASS,function(){return this.hasFlag("x")});XRegExp.addToken(/\./,function(){return"[\\s\\S]"},XRegExp.OUTSIDE_CLASS,function(){return this.hasFlag("s")})})();
diff --git a/src/templates/apps/room/widget.html b/src/templates/apps/room/widget.html new file mode 100644 index 0000000..de37e97 --- /dev/null +++ b/src/templates/apps/room/widget.html @@ -0,0 +1,51 @@ +{% extends "base.html" %} +{% load prefix %} +{% block widgets %} + SyntaxHighlighter.all() +{% endblock %} +{% block meta %} +<script type="text/javascript" src="{% prefix %}/site-media/js/xregexp-min.js"></script> +<script type="text/javascript" src="{% prefix %}/site-media/js/shCore.js"></script> +<script type="text/javascript" src="{% prefix %}/site-media/js/shAutoloader.js"></script> +<script type="text/javascript" src="{% prefix %}/site-media/js/shLegacy.js"></script> +<script type="text/javascript" src="{% prefix %}/site-media/js/shBrushXml.js"></script> +<link href="{% prefix %}/site-media/css/shCore.css" rel="stylesheet" type="text/css" /> +<link href="{% prefix %}/site-media/css/shThemeDefault.css" rel="stylesheet" type="text/css" /> +{% endblock %} +{% block content %} +<h1>{{title}}</h1> + +<div class="ui-widget"> + <div class="ui-state-highlight ui-corner-all" style="margin-top: 20px; padding: 0 .7em;"> + <p><span class="ui-icon ui-icon-info" style="float: left; margin-right: .3em;"></span> + The meetingtools jquery widget allows you to easily embed lists of meetings in your own + web page using the popular <a href="http://jquery.com">jQuery javascript library</a>. + </div> +</div> + +<p>Copy the sample html below in order to list rooms tagged with <em>{{tags}}</em>.</p> + +<pre class="brush: xml"> +<html> + <head> + <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script> + <script type="text/javascript" src="{% baseurl %}/{% prefix %}js/jquery.meetingtools.js"></script> + <link href="{% baseurl %}/{% prefix %}css/jquery.meetingtools.css" rel="stylesheet" type="text/css" /> + <script type="text/javascript"> + $(function() { + $("#meetings").meetingtools({tags: '{{tags}}',url: '{% baseurl %}/{% prefix %}'}); + }); + </script> + </head> + <body> + <h1>Meetings...</h1> + <div id="meetings"/> + </body> +</html> +</pre> + +<p> + Change the tags option in the call to 'meetingtools' in order to list other rooms. Override + the CSS elements in jquery.meetingtools.css in order to apply your own skin to the generated html. +</p> +{% endblock %}
\ No newline at end of file diff --git a/src/templates/base.html b/src/templates/base.html index 61a9b7b..818e137 100644 --- a/src/templates/base.html +++ b/src/templates/base.html @@ -88,6 +88,16 @@ <li><a class="tip" title="SUNET Community Support" href="http://community.sunet.se">SUNET Community Support</a></li> </ul> </li> + <li> + <ul> + <li><h3>Developers</h3></li> + {% if tags %} + <li><a href="{% prefix %}/widget/+{{tags}}">Meetingtools jQuery widget</a></li> + {% else %} + <li><a href="{% prefix %}/widget/+example">Meetingtools jQuery widget</a></li> + {% endif %} + </ul> + </li> </ul> <div style="float: right; margin-top: 10px;"> {% block validators %}{% endblock %} |