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>
No comments:
Post a Comment