XML editor was replaced by codemirror thridparty library and other improvements such as dynaform editor load time

This commit is contained in:
Erik Amaru Ortiz
2011-01-20 22:47:25 +00:00
parent 4336274430
commit 3a6a045aa4
101 changed files with 18918 additions and 81 deletions

View File

@@ -0,0 +1,20 @@
Copyright (c) 2010 Patrick Wied
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must
not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.

View File

@@ -0,0 +1,64 @@
html {
cursor: text;
}
.editbox {
margin: .4em;
padding: 0;
font-family: monospace;
font-size: 10pt;
color: black;
}
pre.code, .editbox {
color: #666666;
}
.editbox p {
margin: 0;
}
span.java-punctuation {
color: black;
}
span.java-operator {
color: purple;
}
span.java-keyword {
color: #7f0055;
font-weight:bold;
}
span.java-atom {
color: brown;
}
span.java-variable {
color: black;
}
span.java-property {
color: black;
}
span.java-comment {
color: green;
}
span.javadoc-comment {
color: #3e5797;
font-weight:bold;
}
span.java-string {
color: blue;
}
span.java-annotation{
color: gray;
}

View File

@@ -0,0 +1,66 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Demonstration of CodeMirrors Java highlighter written by Patrick Wied</title>
<script src="../../js/codemirror.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="../../css/docs.css" />
</head>
<body>
<p>Demonstration of <a href="http://www.codemirror.net">CodeMirror</a>'s Java highlighter.</p>
<p>Written by <a href="http://www.patrick-wied.at/">Patrick Wied</a>.</p>
<div style="border-top: 1px solid black; border-bottom: 1px solid black;">
<textarea id="code">
package example;
import java.awt.*;
/**
* This class subclasses DrawableRect and adds colors to the rectangle it draws
**/
public class ColoredRect extends DrawableRect {
// These are new fields defined by this class.
// x1, y1, x2, and y2 are inherited from our super-superclass, Rect.
@AnnotationTest
protected Color border, fill;
private String name;
/**
* This constructor uses super() to invoke the superclass constructor, and
* also does some initialization of its own.
**/
public ColoredRect(int x1, int y1, int x2, int y2, Color border, Color fill){
super(x1, y1, x2, y2);
/* This
is a block comment */
this.border = border;
this.fill = fill;
this.name = "This is a string";
}
/**
* This method overrides the draw() method of our superclass so that it
* can make use of the colors that have been specified.
**/
public void draw(Graphics g) {
g.setColor(fill);
g.fillRect(x1, y1, x2, y2);
g.setColor(border);
g.drawRect(x1, y1, x2, y2);
}
}
</textarea>
</div>
<script type="text/javascript">
var editor = CodeMirror.fromTextArea('code', {
height: "650px",
parserfile: ["../contrib/java/js/tokenizejava.js","../contrib/java/js/parsejava.js"],
stylesheet: "css/javacolors.css",
path: "../../js/",
tabMode : "shift"
});
</script>
</body>
</html>

View File

@@ -0,0 +1,285 @@
/**
* Java parser for codemirror
*
* @author Patrick Wied
*/
var JavaParser = Editor.Parser = (function() {
// Token types that can be considered to be atoms.
var atomicTypes = {"atom": true, "number": true, "string": true, "regexp": true};
// Setting that can be used to have JSON data indent properly.
var json = false;
// Constructor for the lexical context objects.
function JavaLexical(indented, column, type, align, prev, info) {
// indentation at start of this line
this.indented = indented;
// column at which this scope was opened
this.column = column;
// type of scope ( 'stat' (statement), 'form' (special form), '[', '{', or '(')
this.type = type;
// '[', '{', or '(' blocks that have any text after their opening
// character are said to be 'aligned' -- any lines below are
// indented all the way to the opening character.
if (align != null)
this.align = align;
// Parent scope, if any.
this.prev = prev;
this.info = info;
}
// java indentation rules.
function indentJava(lexical) {
return function(firstChars) {
var firstChar = firstChars && firstChars.charAt(0), type = lexical.type;
var closing = firstChar == type;
if (type == "form" && firstChar == "{")
return lexical.indented;
else if (type == "stat" || type == "form")
return lexical.indented + indentUnit;
else if (lexical.info == "switch" && !closing)
return lexical.indented + (/^(?:case|default)\b/.test(firstChars) ? indentUnit : 2 * indentUnit);
else if (lexical.align)
return lexical.column - (closing ? 1 : 0);
else
return lexical.indented + (closing ? 0 : indentUnit);
};
}
// The parser-iterator-producing function itself.
function parseJava(input, basecolumn) {
// Wrap the input in a token stream
var tokens = tokenizeJava(input);
// The parser state. cc is a stack of actions that have to be
// performed to finish the current statement. For example we might
// know that we still need to find a closing parenthesis and a
// semicolon. Actions at the end of the stack go first. It is
// initialized with an infinitely looping action that consumes
// whole statements.
var cc = [statements];
// The lexical scope, used mostly for indentation.
var lexical = new JavaLexical(basecolumn || 0, 0, "block", false);
// Current column, and the indentation at the start of the current
// line. Used to create lexical scope objects.
var column = 0;
var indented = 0;
// Variables which are used by the mark, cont, and pass functions
// below to communicate with the driver loop in the 'next'
// function.
var consume, marked;
// The iterator object.
var parser = {next: next, copy: copy};
function next(){
// Start by performing any 'lexical' actions (adjusting the
// lexical variable), or the operations below will be working
// with the wrong lexical state.
while(cc[cc.length - 1].lex)
cc.pop()();
// Fetch a token.
var token = tokens.next();
// Adjust column and indented.
if (token.type == "whitespace" && column == 0)
indented = token.value.length;
column += token.value.length;
if (token.content == "\n"){
indented = column = 0;
// If the lexical scope's align property is still undefined at
// the end of the line, it is an un-aligned scope.
if (!("align" in lexical))
lexical.align = false;
// Newline tokens get an indentation function associated with
// them.
token.indentation = indentJava(lexical);
}
// No more processing for meaningless tokens.
if (token.type == "whitespace" || token.type == "comment" || token.type == "javadoc" || token.type == "annotation")
return token;
// When a meaningful token is found and the lexical scope's
// align is undefined, it is an aligned scope.
if (!("align" in lexical))
lexical.align = true;
// Execute actions until one 'consumes' the token and we can
// return it.
while(true) {
consume = marked = false;
// Take and execute the topmost action.
cc.pop()(token.type, token.content);
if (consume){
// Marked is used to change the style of the current token.
if (marked)
token.style = marked;
return token;
}
}
}
// This makes a copy of the parser state. It stores all the
// stateful variables in a closure, and returns a function that
// will restore them when called with a new input stream. Note
// that the cc array has to be copied, because it is contantly
// being modified. Lexical objects are not mutated, and context
// objects are not mutated in a harmful way, so they can be shared
// between runs of the parser.
function copy(){
var _lexical = lexical, _cc = cc.concat([]), _tokenState = tokens.state;
return function copyParser(input){
lexical = _lexical;
cc = _cc.concat([]); // copies the array
column = indented = 0;
tokens = tokenizeJava(input, _tokenState);
return parser;
};
}
// Helper function for pushing a number of actions onto the cc
// stack in reverse order.
function push(fs){
for (var i = fs.length - 1; i >= 0; i--)
cc.push(fs[i]);
}
// cont and pass are used by the action functions to add other
// actions to the stack. cont will cause the current token to be
// consumed, pass will leave it for the next action.
function cont(){
push(arguments);
consume = true;
}
function pass(){
push(arguments);
consume = false;
}
// Used to change the style of the current token.
function mark(style){
marked = style;
}
// Push a new lexical context of the given type.
function pushlex(type, info) {
var result = function(){
lexical = new JavaLexical(indented, column, type, null, lexical, info)
};
result.lex = true;
return result;
}
// Pop off the current lexical context.
function poplex(){
lexical = lexical.prev;
}
poplex.lex = true;
// The 'lex' flag on these actions is used by the 'next' function
// to know they can (and have to) be ran before moving on to the
// next token.
// Creates an action that discards tokens until it finds one of
// the given type.
function expect(wanted){
return function expecting(type){
if (type == wanted) cont();
else cont(arguments.callee);
};
}
// Looks for a statement, and then calls itself.
function statements(type){
return pass(statement, statements);
}
// Dispatches various types of statements based on the type of the
// current token.
function statement(type){
if (type == "keyword a") cont(pushlex("form"), expression, statement, poplex);
else if (type == "keyword b") cont(pushlex("form"), statement, poplex);
else if (type == "{") cont(pushlex("}"), block, poplex);
else if (type == "for") cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"), poplex, statement, poplex);
else if (type == "variable") cont(pushlex("stat"), maybelabel);
else if (type == "switch") cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), block, poplex, poplex);
else if (type == "case") cont(expression, expect(":"));
else if (type == "default") cont(expect(":"));
else if (type == "catch") cont(pushlex("form"), expect("("), function(){}, expect(")"), statement, poplex);
else if (type == "class") cont();
else if (type == "interface") cont();
else if (type == "keyword c") cont(statement);
else pass(pushlex("stat"), expression, expect(";"), poplex);
}
// Dispatch expression types.
function expression(type){
if (atomicTypes.hasOwnProperty(type)) cont(maybeoperator);
//else if (type == "function") cont(functiondef);
else if (type == "keyword c") cont(expression);
else if (type == "(") cont(pushlex(")"), expression, expect(")"), poplex, maybeoperator);
else if (type == "operator") cont(expression);
else if (type == "[") cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
}
// Called for places where operators, function calls, or
// subscripts are valid. Will skip on to the next action if none
// is found.
function maybeoperator(type){
if (type == "operator") cont(expression);
else if (type == "(") cont(pushlex(")"), expression, commasep(expression, ")"), poplex, maybeoperator);
else if (type == "[") cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
}
// When a statement starts with a variable name, it might be a
// label. If no colon follows, it's a regular statement.
function maybelabel(type){
if (type == "(") cont(commasep(function(){}, ")"), poplex, statement); // method definition
else if (type == "{") cont(poplex, pushlex("}"), block, poplex); // property definition
else pass(maybeoperator, expect(";"), poplex);
}
// Parses a comma-separated list of the things that are recognized
// by the 'what' argument.
function commasep(what, end){
function proceed(type) {
if (type == ",") cont(what, proceed);
else if (type == end) cont();
else cont(expect(end));
};
return function commaSeparated(type) {
if (type == end) cont();
else pass(what, proceed);
};
}
// Look for statements until a closing brace is found.
function block(type){
if (type == "}") cont();
else pass(statement, block);
}
// For loops.
function forspec1(type){
if (type == ";") pass(forspec2);
else pass(forspec2);
}
function formaybein(type, value){
if (value == "in") cont(expression);
else cont(maybeoperator, forspec2);
}
function forspec2(type, value){
if (type == ";") cont(forspec3);
else if (value == "in") cont(expression);
else cont(expression, expect(";"), forspec3);
}
function forspec3(type) {
if (type == ")") pass();
else cont(expression);
}
return parser;
}
return {
make: parseJava,
electricChars: "{}:",
configure: function(obj) {
if (obj.json != null) json = obj.json;
}
};
})();

View File

@@ -0,0 +1,222 @@
/**
* Java tokenizer for codemirror
*
* @author Patrick Wied
* @version 2010-10-07
*/
var tokenizeJava = (function() {
// Advance the stream until the given character (not preceded by a
// backslash) is encountered, or the end of the line is reached.
function nextUntilUnescaped(source, end) {
var escaped = false;
var next;
while (!source.endOfLine()) {
var next = source.next();
if (next == end && !escaped)
return false;
escaped = !escaped && next == "\\";
}
return escaped;
}
// A map of Java's keywords. The a/b/c keyword distinction is
// very rough, but it gives the parser enough information to parse
// correct code correctly (we don't care that much how we parse
// incorrect code). The style information included in these objects
// is used by the highlighter to pick the correct CSS style for a
// token.
var keywords = function(){
function result(type, style){
return {type: type, style: "java-" + style};
}
// keywords that take a parenthised expression, and then a
// statement (if)
var keywordA = result("keyword a", "keyword");
// keywords that take just a statement (else)
var keywordB = result("keyword b", "keyword");
// keywords that optionally take an expression, and form a
// statement (return)
var keywordC = result("keyword c", "keyword");
var operator = result("operator", "keyword");
var atom = result("atom", "atom");
return {
"if": keywordA, "while": keywordA, "with": keywordA,
"else": keywordB, "do": keywordB, "try": keywordB, "finally": keywordB,
"return": keywordC, "break": keywordC, "continue": keywordC, "new": keywordC, "throw": keywordC, "throws": keywordB,
"in": operator, "typeof": operator, "instanceof": operator,
"catch": result("catch", "keyword"), "for": result("for", "keyword"), "switch": result("switch", "keyword"),
"case": result("case", "keyword"), "default": result("default", "keyword"),
"true": atom, "false": atom, "null": atom,
"class": result("class", "keyword"), "interface": result("interface", "keyword"), "package": keywordC, "import": keywordC,
"implements": keywordC, "extends": keywordC, "super": keywordC,
"public": keywordC, "private": keywordC, "protected": keywordC, "transient": keywordC, "this": keywordC,
"static": keywordC, "final": keywordC, "const": keywordC, "abstract": keywordC, "static": keywordC,
"int": keywordC, "double": keywordC, "long": keywordC, "boolean": keywordC, "char": keywordC,
"void": keywordC, "byte": keywordC, "float": keywordC, "short": keywordC
};
}();
// Some helper regexps
var isOperatorChar = /[+\-*&%=<>!?|]/;
var isHexDigit = /[0-9A-Fa-f]/;
var isWordChar = /[\w\$_]/;
// Wrapper around javaToken that helps maintain parser state (whether
// we are inside of a multi-line comment and whether the next token
// could be a regular expression).
function javaTokenState(inside, regexp) {
return function(source, setState) {
var newInside = inside;
var type = javaToken(inside, regexp, source, function(c) {newInside = c;});
var newRegexp = type.type == "operator" || type.type == "keyword c" || type.type.match(/^[\[{}\(,;:]$/);
if (newRegexp != regexp || newInside != inside)
setState(javaTokenState(newInside, newRegexp));
return type;
};
}
// The token reader, inteded to be used by the tokenizer from
// tokenize.js (through jsTokenState). Advances the source stream
// over a token, and returns an object containing the type and style
// of that token.
function javaToken(inside, regexp, source, setInside) {
function readHexNumber(){
source.next(); // skip the 'x'
source.nextWhileMatches(isHexDigit);
return {type: "number", style: "java-atom"};
}
function readNumber() {
source.nextWhileMatches(/[0-9]/);
if (source.equals(".")){
source.next();
source.nextWhileMatches(/[0-9]/);
}
if (source.equals("e") || source.equals("E")){
source.next();
if (source.equals("-"))
source.next();
source.nextWhileMatches(/[0-9]/);
}
return {type: "number", style: "java-atom"};
}
// Read a word, look it up in keywords. If not found, it is a
// variable, otherwise it is a keyword of the type found.
function readWord() {
source.nextWhileMatches(isWordChar);
var word = source.get();
var known = keywords.hasOwnProperty(word) && keywords.propertyIsEnumerable(word) && keywords[word];
return known ? {type: known.type, style: known.style, content: word} :
{type: "variable", style: "java-variable", content: word};
}
function readRegexp() {
nextUntilUnescaped(source, "/");
source.nextWhileMatches(/[gi]/);
return {type: "regexp", style: "java-string"};
}
// Mutli-line comments are tricky. We want to return the newlines
// embedded in them as regular newline tokens, and then continue
// returning a comment token for every line of the comment. So
// some state has to be saved (inside) to indicate whether we are
// inside a /* */ sequence.
function readMultilineComment(start){
var newInside = "/*";
var maybeEnd = (start == "*");
while (true) {
if (source.endOfLine())
break;
var next = source.next();
if (next == "/" && maybeEnd){
newInside = null;
break;
}
maybeEnd = (next == "*");
}
setInside(newInside);
return {type: "comment", style: "java-comment"};
}
// for reading javadoc
function readJavaDocComment(start){
var newInside = "/**";
var maybeEnd = (start == "*");
while (true) {
if (source.endOfLine())
break;
var next = source.next();
if (next == "/" && maybeEnd){
newInside = null;
break;
}
maybeEnd = (next == "*");
}
setInside(newInside);
return {type: "javadoc", style: "javadoc-comment"};
}
// for reading annotations (word based)
function readAnnotation(){
source.nextWhileMatches(isWordChar);
var word = source.get();
return {type: "annotation", style: "java-annotation", content:word};
}
function readOperator() {
source.nextWhileMatches(isOperatorChar);
return {type: "operator", style: "java-operator"};
}
function readString(quote) {
var endBackSlash = nextUntilUnescaped(source, quote);
setInside(endBackSlash ? quote : null);
return {type: "string", style: "java-string"};
}
// Fetch the next token. Dispatches on first character in the
// stream, or first two characters when the first is a slash.
if (inside == "\"" || inside == "'")
return readString(inside);
var ch = source.next();
if (inside == "/*")
return readMultilineComment(ch);
else if(inside == "/**")
return readJavaDocComment(ch);
else if (ch == "\"" || ch == "'")
return readString(ch);
// with punctuation, the type of the token is the symbol itself
else if (/[\[\]{}\(\),;\:\.]/.test(ch))
return {type: ch, style: "java-punctuation"};
else if (ch == "0" && (source.equals("x") || source.equals("X")))
return readHexNumber();
else if (/[0-9]/.test(ch))
return readNumber();
else if (ch == "@"){
return readAnnotation();
}else if (ch == "/"){
if (source.equals("*")){
source.next();
if(source.equals("*"))
return readJavaDocComment(ch);
return readMultilineComment(ch);
}
else if (source.equals("/"))
{ nextUntilUnescaped(source, null); return {type: "comment", style: "java-comment"};}
else if (regexp)
return readRegexp();
else
return readOperator();
}
else if (isOperatorChar.test(ch))
return readOperator();
else
return readWord();
}
// The external interface to the tokenizer.
return function(source, startState) {
return tokenizer(source, startState || javaTokenState(false, true));
};
})();