Everyone is making one
of
these.
So, I thought I'd make one too using jquery.
First step in making something is to give it a name.
I chose Jyntaxer because google didn't return a result (now, it will).
With JQuery, I can easily select $(".jyntaxer") and get .html() or
.val() of the element.
Then create a new element with .css("white-space", "pre") to make it
look nice.
Since code usually contains <, > stuff,
<textarea class="jyntaxer">some code with < > stuff</textarea>
would be how normal user would use Jyntaxer.
Then I hit the wall: browser will render <textarea>&</textarea>
as &. If I query for that textarea.value, I get &.
That means user has to preprocess their code before they can wrap their code in
my magic <textarea class="jyntaxer">preprocessed code with &
properly escaped like & => &amp;</textarea>.
So, if user has to preprocess it, why not make the preprocessor
highlight the syntax all together?
Parsing strings in Javascript isn't fun.
So, Jyntaxer dies now
var KEYWORDS = ["abstract", "bool", "break", "case", "catch"
, "char", "class", "const", "const_cast", "continue", "default"
, "delete", "deprecated", "dllexport", "dllimport", "do", "double"
, "dynamic_cast", "else", "enum", "explicit", "extern", "false", "float"
, "for", "friend", "goto", "if", "inline", "int", "long", "mutable"
, "naked", "namespace", "new", "noinline", "noreturn", "nothrow"
, "novtable", "operator", "private", "property", "protected", "public"
, "register", "reinterpret_cast", "return", "selectany", "short"
, "signed", "sizeof", "static", "static_cast", "struct", "switch"
, "template", "this", "thread", "throw", "true", "try", "typedef"
, "typeid", "typename", "union", "unsigned", "using", "declaration"
, "directive", "uuid", "virtual", "void", "volatile", "while", "typeof"
, "as", "base", "by", "byte", "checked", "decimal", "delegate"
, "descending", "event", "finally", "fixed", "foreach", "from", "group"
, "implicit", "in", "interface", "internal", "into", "is", "lock"
, "null", "object", "out", "override", "orderby", "params", "readonly"
, "ref", "sbyte", "sealed", "stackalloc", "string", "select", "uint"
, "ulong", "unchecked", "unsafe", "ushort", "var", "package"
, "synchronized", "boolean", "implements", "import", "throws"
, "instanceof", "transient", "extends", "final", "strictfp", "native"
, "super", "debugger", "export", "function", "with", "NaN", "Infinity"
, "require", "sub", "unless", "until", "use", "elsif", "BEGIN", "END"
, "and", "assert", "def", "del", "elif", "except", "exec", "global"
, "lambda", "not", "or", "pass", "print", "raise", "yield", "False"
, "True", "Non", "e", "then", "end", "begin", "rescue", "ensure"
, "module", "when", "undef", "next", "redo", "retry", "alias"
, "defined", "done", "fi"];
function randint(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
//returns background style information of the node.
//if not defined, return parent's background style.
function getbg(node) {
var bg = node.css("background-color");
if(bg && bg != "transparent") {
return bg;
}
return getbg(node.parent());
}
function getfg(bg) {
var rgb = bg.match(/\d+/g);
var fg = "rgb(";
$.each(rgb, function (key, val) {
fg += (Math.abs(randint(0, randint(0, 255) - Number(val, 10) + randint(0, 100))) + ',');
});
return fg.substring(0, fg.length - 1) + ')';
}
var JYN_STR_BEG = "0000JyntaxerStrBegin" + randint(1000, 9999);
var JYN_STR_END = "0000JyntaxerStrEnd" + randint(1000, 9999);
//node has raw code. converts it to html
function mkhtml(code) {
var html = code.html();
//html = html.replace(/(["'].*["'])/g
// , " " + JYN_STR_BEG + " $1 " + JYN_STR_END + " ");
html = html.replace(/([a-zA-Z_]\w+)/g,
function (str, p1, offset, s) {
for(var i=0; i<KEYWORDS.length; i++) {
if(p1 === KEYWORDS[i]) {
return "<span class=\"keyword\">"+p1+"</span>";
}
}
return p1;
});
//html = html.replace(/\b(\d+)/g, "<span class=\"number\">$1</span>");
//html = html.replace(new RegExp(JYN_STR_BEG, "g"), "<span class=\"string\">")
// .replace(new RegExp(JYN_STR_END, "g"), "</span>");
//html = html.replace(/([^\w<>'" \s])/g, "<span class=\"operator\">$1</span>");
//html = html.replace(/\n/g, "<br/>");
//html = html.replace(/<.*\s(?!.*>)/g, " ");
var fg = getfg(getbg(code));
html = $("<div class=\"jyntaxered\">" + html + "</div>");
html.css("color", fg);
$("#msg").append('<p>' + new Date() + ' : ' + code.attr("id") + '</p>');
$("#msg").append($(html).each(function() { do_style($(this)); }));
return html;
}
function do_style(node) {
node.css("white-space", "pre");
node.children(".keyword").css("color", "#ff0");
node.children(".number").css("color", "#0ff");
node.children(".string").css("color", "#f0f");
node.children(".operator").css("color", "#00f");
}
//generates syntax highlighted code
function button_click(button, code) {
if(button.attr("value") === "Jyntaxer") {
code.css("display", "none");
code.siblings(".jyntaxered:eq(0)").remove();
mkhtml(code)
.each(function () { do_style($(this)); }).insertAfter(code);
button.attr("value", "Back");
} else {
code.css("display", "inline");
code.siblings(".jyntaxered:eq(0)").css("display", "none");
button.attr("value", "Jyntaxer");
}
}
function show_code(button) {
var code = button.siblings(".jyntaxer:eq(0)");
var html = button.siblings(".jyntaxered:eq(0)");
code.css("display", "inline");
html.css("display", "none");
}
function show_html(button) {
var code = button.siblings(".jyntaxer:eq(0)");
var html = button.siblings(".jyntaxered:eq(0)");
code.css("display", "none");
html.css("display", "inline");
}
function attach_button(code) {
$('<input type="button" class="jyntaxer_widget" value="Jyntaxer"/><br/>')
.toggle(function() { show_html($(this)); }
, function() { show_code($(this)); })
.insertBefore(code);
}
function prepare_html(code) {
code.wrap('<div class="jyntaxered_wrap"></div>');
mkhtml(code).css("display", "none")
.each(function () { do_style($(this)); }).insertAfter(code);
}
function is_outermost(node) {
var parents = node.parents();
var outermost = true;
$.each(node.parents(), function (key, val) {
if($(val).attr("class") === "jyntaxer") {
outermost = false;
return false;
}});
return outermost;
}
function jyntaxer() {
$(".jyntaxer").filter(function () {
return is_outermost($(this));
}).each(function () {
var code = $(this);
prepare_html(code);
attach_button(code);
});
}
$(document).ready(function(){
jyntaxer();
});
Html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-us" xml:lang="en-us" >
<head>
<title>
Jyntaxer : Javascript Syntax Highlight Thingy
</title>
<script type="text/javascript" src="jquery-latest.js"></script>
<script type="text/javascript" src="jyntaxer.js"></script>
</head>
<body style="background: #aaa;">
<div id="container">
<p>
Hi this is some text.
</p>
<textarea id="python" class="jyntaxer" style="background-color: #fff;" cols="80" rows="20">
import sys
def html_escape(text
, html_entities = {
'&':'&'
, '<':'<'
, '>':'>'
#, "'":'''
#, '"':'"e;'
, ' ':' '
, '\t':' ' } ):
"replaces possible html entities in the text"
l = []
for c in text:
l.append(html_entities.get(c,c))
return "".join(l)
def main(argv=None):
if argv is None:
argv = sys.argv
f = open(argv[1], 'r')
print html_escape(f.read())
if __name__ == "__main__":
main()
</textarea>
<p>
Hi this is some text.
</p>
<textarea id="cpp" class="jyntaxer" cols="80" rows="20">
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
int blah12 = 3435.453;
struct ScopeGuard: boost::function<void ()>, boost::noncopyable
{
typedef boost::function<void ()> F;
ScopeGuard () {}
template <typename T> explicit ScopeGuard (T const & f) : F (f) {}
~ScopeGuard () { try { if (*this) operator()(); } catch (...) {} }
};
</textarea>
<p>
Hi this is some text.
</p>
</div>
<div id="msg"></div>
</body>
</html>