mirror of https://github.com/lukechilds/node.git
Ryan
16 years ago
6 changed files with 816 additions and 185 deletions
@ -1,7 +1,7 @@ |
|||
new node.http.Server(function (req, res) { |
|||
setTimeout(function () { |
|||
res.sendHeader(200, [["Content-Type", "text/plain"]]); |
|||
res.sendBody("Hello World"); |
|||
res.sendBody(JSON.stringify(req.uri)); |
|||
res.finish(); |
|||
}, 1000); |
|||
}, 1); |
|||
}).listen(8000, "localhost"); |
|||
|
@ -0,0 +1,545 @@ |
|||
/* |
|||
SHJS - Syntax Highlighting in JavaScript |
|||
Copyright (C) 2007, 2008 gnombat@users.sourceforge.net |
|||
License: http://shjs.sourceforge.net/doc/gplv3.html
|
|||
*/ |
|||
|
|||
if (! this.sh_languages) { |
|||
this.sh_languages = {}; |
|||
} |
|||
var sh_requests = {}; |
|||
|
|||
function sh_isEmailAddress(url) { |
|||
if (/^mailto:/.test(url)) { |
|||
return false; |
|||
} |
|||
return url.indexOf('@') !== -1; |
|||
} |
|||
|
|||
function sh_setHref(tags, numTags, inputString) { |
|||
var url = inputString.substring(tags[numTags - 2].pos, tags[numTags - 1].pos); |
|||
if (url.length >= 2 && url.charAt(0) === '<' && url.charAt(url.length - 1) === '>') { |
|||
url = url.substr(1, url.length - 2); |
|||
} |
|||
if (sh_isEmailAddress(url)) { |
|||
url = 'mailto:' + url; |
|||
} |
|||
tags[numTags - 2].node.href = url; |
|||
} |
|||
|
|||
/* |
|||
Konqueror has a bug where the regular expression /$/g will not match at the end |
|||
of a line more than once: |
|||
|
|||
var regex = /$/g; |
|||
var match; |
|||
|
|||
var line = '1234567890'; |
|||
regex.lastIndex = 10; |
|||
match = regex.exec(line); |
|||
|
|||
var line2 = 'abcde'; |
|||
regex.lastIndex = 5; |
|||
match = regex.exec(line2); // fails
|
|||
*/ |
|||
function sh_konquerorExec(s) { |
|||
var result = ['']; |
|||
result.index = s.length; |
|||
result.input = s; |
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
Highlights all elements containing source code in a text string. The return |
|||
value is an array of objects, each representing an HTML start or end tag. Each |
|||
object has a property named pos, which is an integer representing the text |
|||
offset of the tag. Every start tag also has a property named node, which is the |
|||
DOM element started by the tag. End tags do not have this property. |
|||
@param inputString a text string |
|||
@param language a language definition object |
|||
@return an array of tag objects |
|||
*/ |
|||
function sh_highlightString(inputString, language) { |
|||
if (/Konqueror/.test(navigator.userAgent)) { |
|||
if (! language.konquered) { |
|||
for (var s = 0; s < language.length; s++) { |
|||
for (var p = 0; p < language[s].length; p++) { |
|||
var r = language[s][p][0]; |
|||
if (r.source === '$') { |
|||
r.exec = sh_konquerorExec; |
|||
} |
|||
} |
|||
} |
|||
language.konquered = true; |
|||
} |
|||
} |
|||
|
|||
var a = document.createElement('a'); |
|||
var span = document.createElement('span'); |
|||
|
|||
// the result
|
|||
var tags = []; |
|||
var numTags = 0; |
|||
|
|||
// each element is a pattern object from language
|
|||
var patternStack = []; |
|||
|
|||
// the current position within inputString
|
|||
var pos = 0; |
|||
|
|||
// the name of the current style, or null if there is no current style
|
|||
var currentStyle = null; |
|||
|
|||
var output = function(s, style) { |
|||
var length = s.length; |
|||
// this is more than just an optimization - we don't want to output empty <span></span> elements
|
|||
if (length === 0) { |
|||
return; |
|||
} |
|||
if (! style) { |
|||
var stackLength = patternStack.length; |
|||
if (stackLength !== 0) { |
|||
var pattern = patternStack[stackLength - 1]; |
|||
// check whether this is a state or an environment
|
|||
if (! pattern[3]) { |
|||
// it's not a state - it's an environment; use the style for this environment
|
|||
style = pattern[1]; |
|||
} |
|||
} |
|||
} |
|||
if (currentStyle !== style) { |
|||
if (currentStyle) { |
|||
tags[numTags++] = {pos: pos}; |
|||
if (currentStyle === 'sh_url') { |
|||
sh_setHref(tags, numTags, inputString); |
|||
} |
|||
} |
|||
if (style) { |
|||
var clone; |
|||
if (style === 'sh_url') { |
|||
clone = a.cloneNode(false); |
|||
} |
|||
else { |
|||
clone = span.cloneNode(false); |
|||
} |
|||
clone.className = style; |
|||
tags[numTags++] = {node: clone, pos: pos}; |
|||
} |
|||
} |
|||
pos += length; |
|||
currentStyle = style; |
|||
}; |
|||
|
|||
var endOfLinePattern = /\r\n|\r|\n/g; |
|||
endOfLinePattern.lastIndex = 0; |
|||
var inputStringLength = inputString.length; |
|||
while (pos < inputStringLength) { |
|||
var start = pos; |
|||
var end; |
|||
var startOfNextLine; |
|||
var endOfLineMatch = endOfLinePattern.exec(inputString); |
|||
if (endOfLineMatch === null) { |
|||
end = inputStringLength; |
|||
startOfNextLine = inputStringLength; |
|||
} |
|||
else { |
|||
end = endOfLineMatch.index; |
|||
startOfNextLine = endOfLinePattern.lastIndex; |
|||
} |
|||
|
|||
var line = inputString.substring(start, end); |
|||
|
|||
var matchCache = []; |
|||
for (;;) { |
|||
var posWithinLine = pos - start; |
|||
|
|||
var stateIndex; |
|||
var stackLength = patternStack.length; |
|||
if (stackLength === 0) { |
|||
stateIndex = 0; |
|||
} |
|||
else { |
|||
// get the next state
|
|||
stateIndex = patternStack[stackLength - 1][2]; |
|||
} |
|||
|
|||
var state = language[stateIndex]; |
|||
var numPatterns = state.length; |
|||
var mc = matchCache[stateIndex]; |
|||
if (! mc) { |
|||
mc = matchCache[stateIndex] = []; |
|||
} |
|||
var bestMatch = null; |
|||
var bestPatternIndex = -1; |
|||
for (var i = 0; i < numPatterns; i++) { |
|||
var match; |
|||
if (i < mc.length && (mc[i] === null || posWithinLine <= mc[i].index)) { |
|||
match = mc[i]; |
|||
} |
|||
else { |
|||
var regex = state[i][0]; |
|||
regex.lastIndex = posWithinLine; |
|||
match = regex.exec(line); |
|||
mc[i] = match; |
|||
} |
|||
if (match !== null && (bestMatch === null || match.index < bestMatch.index)) { |
|||
bestMatch = match; |
|||
bestPatternIndex = i; |
|||
if (match.index === posWithinLine) { |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (bestMatch === null) { |
|||
output(line.substring(posWithinLine), null); |
|||
break; |
|||
} |
|||
else { |
|||
// got a match
|
|||
if (bestMatch.index > posWithinLine) { |
|||
output(line.substring(posWithinLine, bestMatch.index), null); |
|||
} |
|||
|
|||
var pattern = state[bestPatternIndex]; |
|||
|
|||
var newStyle = pattern[1]; |
|||
var matchedString; |
|||
if (newStyle instanceof Array) { |
|||
for (var subexpression = 0; subexpression < newStyle.length; subexpression++) { |
|||
matchedString = bestMatch[subexpression + 1]; |
|||
output(matchedString, newStyle[subexpression]); |
|||
} |
|||
} |
|||
else { |
|||
matchedString = bestMatch[0]; |
|||
output(matchedString, newStyle); |
|||
} |
|||
|
|||
switch (pattern[2]) { |
|||
case -1: |
|||
// do nothing
|
|||
break; |
|||
case -2: |
|||
// exit
|
|||
patternStack.pop(); |
|||
break; |
|||
case -3: |
|||
// exitall
|
|||
patternStack.length = 0; |
|||
break; |
|||
default: |
|||
// this was the start of a delimited pattern or a state/environment
|
|||
patternStack.push(pattern); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// end of the line
|
|||
if (currentStyle) { |
|||
tags[numTags++] = {pos: pos}; |
|||
if (currentStyle === 'sh_url') { |
|||
sh_setHref(tags, numTags, inputString); |
|||
} |
|||
currentStyle = null; |
|||
} |
|||
pos = startOfNextLine; |
|||
} |
|||
|
|||
return tags; |
|||
} |
|||
|
|||
////////////////////////////////////////////////////////////////////////////////
|
|||
// DOM-dependent functions
|
|||
|
|||
function sh_getClasses(element) { |
|||
var result = []; |
|||
var htmlClass = element.className; |
|||
if (htmlClass && htmlClass.length > 0) { |
|||
var htmlClasses = htmlClass.split(' '); |
|||
for (var i = 0; i < htmlClasses.length; i++) { |
|||
if (htmlClasses[i].length > 0) { |
|||
result.push(htmlClasses[i]); |
|||
} |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
function sh_addClass(element, name) { |
|||
var htmlClasses = sh_getClasses(element); |
|||
for (var i = 0; i < htmlClasses.length; i++) { |
|||
if (name.toLowerCase() === htmlClasses[i].toLowerCase()) { |
|||
return; |
|||
} |
|||
} |
|||
htmlClasses.push(name); |
|||
element.className = htmlClasses.join(' '); |
|||
} |
|||
|
|||
/** |
|||
Extracts the tags from an HTML DOM NodeList. |
|||
@param nodeList a DOM NodeList |
|||
@param result an object with text, tags and pos properties |
|||
*/ |
|||
function sh_extractTagsFromNodeList(nodeList, result) { |
|||
var length = nodeList.length; |
|||
for (var i = 0; i < length; i++) { |
|||
var node = nodeList.item(i); |
|||
switch (node.nodeType) { |
|||
case 1: |
|||
if (node.nodeName.toLowerCase() === 'br') { |
|||
var terminator; |
|||
if (/MSIE/.test(navigator.userAgent)) { |
|||
terminator = '\r'; |
|||
} |
|||
else { |
|||
terminator = '\n'; |
|||
} |
|||
result.text.push(terminator); |
|||
result.pos++; |
|||
} |
|||
else { |
|||
result.tags.push({node: node.cloneNode(false), pos: result.pos}); |
|||
sh_extractTagsFromNodeList(node.childNodes, result); |
|||
result.tags.push({pos: result.pos}); |
|||
} |
|||
break; |
|||
case 3: |
|||
case 4: |
|||
result.text.push(node.data); |
|||
result.pos += node.length; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
Extracts the tags from the text of an HTML element. The extracted tags will be |
|||
returned as an array of tag objects. See sh_highlightString for the format of |
|||
the tag objects. |
|||
@param element a DOM element |
|||
@param tags an empty array; the extracted tag objects will be returned in it |
|||
@return the text of the element |
|||
@see sh_highlightString |
|||
*/ |
|||
function sh_extractTags(element, tags) { |
|||
var result = {}; |
|||
result.text = []; |
|||
result.tags = tags; |
|||
result.pos = 0; |
|||
sh_extractTagsFromNodeList(element.childNodes, result); |
|||
return result.text.join(''); |
|||
} |
|||
|
|||
/** |
|||
Merges the original tags from an element with the tags produced by highlighting. |
|||
@param originalTags an array containing the original tags |
|||
@param highlightTags an array containing the highlighting tags - these must not overlap |
|||
@result an array containing the merged tags |
|||
*/ |
|||
function sh_mergeTags(originalTags, highlightTags) { |
|||
var numOriginalTags = originalTags.length; |
|||
if (numOriginalTags === 0) { |
|||
return highlightTags; |
|||
} |
|||
|
|||
var numHighlightTags = highlightTags.length; |
|||
if (numHighlightTags === 0) { |
|||
return originalTags; |
|||
} |
|||
|
|||
var result = []; |
|||
var originalIndex = 0; |
|||
var highlightIndex = 0; |
|||
|
|||
while (originalIndex < numOriginalTags && highlightIndex < numHighlightTags) { |
|||
var originalTag = originalTags[originalIndex]; |
|||
var highlightTag = highlightTags[highlightIndex]; |
|||
|
|||
if (originalTag.pos <= highlightTag.pos) { |
|||
result.push(originalTag); |
|||
originalIndex++; |
|||
} |
|||
else { |
|||
result.push(highlightTag); |
|||
if (highlightTags[highlightIndex + 1].pos <= originalTag.pos) { |
|||
highlightIndex++; |
|||
result.push(highlightTags[highlightIndex]); |
|||
highlightIndex++; |
|||
} |
|||
else { |
|||
// new end tag
|
|||
result.push({pos: originalTag.pos}); |
|||
|
|||
// new start tag
|
|||
highlightTags[highlightIndex] = {node: highlightTag.node.cloneNode(false), pos: originalTag.pos}; |
|||
} |
|||
} |
|||
} |
|||
|
|||
while (originalIndex < numOriginalTags) { |
|||
result.push(originalTags[originalIndex]); |
|||
originalIndex++; |
|||
} |
|||
|
|||
while (highlightIndex < numHighlightTags) { |
|||
result.push(highlightTags[highlightIndex]); |
|||
highlightIndex++; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
Inserts tags into text. |
|||
@param tags an array of tag objects |
|||
@param text a string representing the text |
|||
@return a DOM DocumentFragment representing the resulting HTML |
|||
*/ |
|||
function sh_insertTags(tags, text) { |
|||
var doc = document; |
|||
|
|||
var result = document.createDocumentFragment(); |
|||
var tagIndex = 0; |
|||
var numTags = tags.length; |
|||
var textPos = 0; |
|||
var textLength = text.length; |
|||
var currentNode = result; |
|||
|
|||
// output one tag or text node every iteration
|
|||
while (textPos < textLength || tagIndex < numTags) { |
|||
var tag; |
|||
var tagPos; |
|||
if (tagIndex < numTags) { |
|||
tag = tags[tagIndex]; |
|||
tagPos = tag.pos; |
|||
} |
|||
else { |
|||
tagPos = textLength; |
|||
} |
|||
|
|||
if (tagPos <= textPos) { |
|||
// output the tag
|
|||
if (tag.node) { |
|||
// start tag
|
|||
var newNode = tag.node; |
|||
currentNode.appendChild(newNode); |
|||
currentNode = newNode; |
|||
} |
|||
else { |
|||
// end tag
|
|||
currentNode = currentNode.parentNode; |
|||
} |
|||
tagIndex++; |
|||
} |
|||
else { |
|||
// output text
|
|||
currentNode.appendChild(doc.createTextNode(text.substring(textPos, tagPos))); |
|||
textPos = tagPos; |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
Highlights an element containing source code. Upon completion of this function, |
|||
the element will have been placed in the "sh_sourceCode" class. |
|||
@param element a DOM <pre> element containing the source code to be highlighted |
|||
@param language a language definition object |
|||
*/ |
|||
function sh_highlightElement(element, language) { |
|||
sh_addClass(element, 'sh_sourceCode'); |
|||
var originalTags = []; |
|||
var inputString = sh_extractTags(element, originalTags); |
|||
var highlightTags = sh_highlightString(inputString, language); |
|||
var tags = sh_mergeTags(originalTags, highlightTags); |
|||
var documentFragment = sh_insertTags(tags, inputString); |
|||
while (element.hasChildNodes()) { |
|||
element.removeChild(element.firstChild); |
|||
} |
|||
element.appendChild(documentFragment); |
|||
} |
|||
|
|||
function sh_getXMLHttpRequest() { |
|||
if (window.ActiveXObject) { |
|||
return new ActiveXObject('Msxml2.XMLHTTP'); |
|||
} |
|||
else if (window.XMLHttpRequest) { |
|||
return new XMLHttpRequest(); |
|||
} |
|||
throw 'No XMLHttpRequest implementation available'; |
|||
} |
|||
|
|||
function sh_load(language, element, prefix, suffix) { |
|||
if (language in sh_requests) { |
|||
sh_requests[language].push(element); |
|||
return; |
|||
} |
|||
sh_requests[language] = [element]; |
|||
var request = sh_getXMLHttpRequest(); |
|||
var url = prefix + 'sh_' + language + suffix; |
|||
request.open('GET', url, true); |
|||
request.onreadystatechange = function () { |
|||
if (request.readyState === 4) { |
|||
try { |
|||
if (! request.status || request.status === 200) { |
|||
eval(request.responseText); |
|||
var elements = sh_requests[language]; |
|||
for (var i = 0; i < elements.length; i++) { |
|||
sh_highlightElement(elements[i], sh_languages[language]); |
|||
} |
|||
} |
|||
else { |
|||
throw 'HTTP error: status ' + request.status; |
|||
} |
|||
} |
|||
finally { |
|||
request = null; |
|||
} |
|||
} |
|||
}; |
|||
request.send(null); |
|||
} |
|||
|
|||
/** |
|||
Highlights all elements containing source code on the current page. Elements |
|||
containing source code must be "pre" elements with a "class" attribute of |
|||
"sh_LANGUAGE", where LANGUAGE is a valid language identifier; e.g., "sh_java" |
|||
identifies the element as containing "java" language source code. |
|||
*/ |
|||
function highlight(prefix, suffix, tag) { |
|||
var nodeList = document.getElementsByTagName(tag); |
|||
for (var i = 0; i < nodeList.length; i++) { |
|||
var element = nodeList.item(i); |
|||
var htmlClasses = sh_getClasses(element); |
|||
for (var j = 0; j < htmlClasses.length; j++) { |
|||
var htmlClass = htmlClasses[j].toLowerCase(); |
|||
if (htmlClass === 'sh_sourcecode') { |
|||
continue; |
|||
} |
|||
if (htmlClass.substr(0, 3) === 'sh_') { |
|||
var language = htmlClass.substring(3); |
|||
if (language in sh_languages) { |
|||
sh_highlightElement(element, sh_languages[language]); |
|||
} |
|||
else if (typeof(prefix) === 'string' && typeof(suffix) === 'string') { |
|||
sh_load(language, element, prefix, suffix); |
|||
} |
|||
else { |
|||
throw 'Found <' + tag + '> element with class="' + htmlClass + '", but no such language exists'; |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
function sh_highlightDocument(prefix, suffix) { |
|||
highlight(prefix, suffix, 'code'); |
|||
highlight(prefix, suffix, 'pre'); |
|||
} |
Loading…
Reference in new issue