You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lenya.apache.org by an...@apache.org on 2009/01/29 10:49:42 UTC

svn commit: r738808 [2/3] - in /lenya/trunk: legal/ src/modules/editors/config/ src/modules/editors/resources/codemirror/ src/modules/editors/resources/codemirror/0.60/ src/modules/editors/resources/codemirror/0.60/css/ src/modules/editors/resources/co...

Added: lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/parsejavascript.js
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/parsejavascript.js?rev=738808&view=auto
==============================================================================
--- lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/parsejavascript.js (added)
+++ lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/parsejavascript.js Thu Jan 29 09:49:40 2009
@@ -0,0 +1,322 @@
+/* Parse function for JavaScript. Makes use of the tokenizer from
+ * tokenizejavascript.js. Note that your parsers do not have to be
+ * this complicated -- if you don't want to recognize local variables,
+ * in many languages it is enough to just look for braces, semicolons,
+ * parentheses, etc, and know when you are inside a string or comment.
+ *
+ * See manual.html for more info about the parser interface.
+ */
+
+var JSParser = Editor.Parser = (function() {
+  // Token types that can be considered to be atoms.
+  var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
+  // Constructor for the lexical context objects.
+  function JSLexical(indented, column, type, align, prev) {
+    // indentation at start of this line
+    this.indented = indented;
+    // column at which this scope was opened
+    this.column = column;
+    // type of scope ('vardef', '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;
+  }
+  // My favourite JavaScript indentation rules.
+  function indentJS(lexical) {
+    return function(firstChars) {
+      var firstChar = firstChars && firstChars.charAt(0);
+      var closing = firstChar == lexical.type;
+      if (lexical.type == "vardef")
+        return lexical.indented + 4;
+      else if (lexical.type == "form" && firstChar == "{")
+        return lexical.indented;
+      else if (lexical.type == "stat" || lexical.type == "form")
+        return lexical.indented + 2;
+      else if (lexical.align)
+        return lexical.column - (closing ? 1 : 0);
+      else
+        return lexical.indented + (closing ? 0 : 2);
+    };
+  }
+
+  // The parser-iterator-producing function itself.
+  function parseJS(input, basecolumn) {
+    // Wrap the input in a token stream
+    var tokens = tokenizeJavaScript(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];
+    // Context contains information about the current local scope, the
+    // variables defined in that, and the scopes above it.
+    var context = null;
+    // The lexical scope, used mostly for indentation.
+    var lexical = new JSLexical((basecolumn || 0) - 2, 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 = indentJS(lexical);
+      }
+      // No more processing for meaningless tokens.
+      if (token.type == "whitespace" || token.type == "comment")
+        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;
+          // Here we differentiate between local and global variables.
+          else if (token.type == "variable" && inScope(token.content))
+            token.style = "js-localvariable";
+          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 _context = context, _lexical = lexical, _cc = cc.concat([]), _tokenState = tokens.state;
+  
+      return function copyParser(input){
+        context = _context;
+        lexical = _lexical;
+        cc = _cc.concat([]); // copies the array
+        column = indented = 0;
+        tokens = tokenizeJavaScript(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 scope. Will automatically link the current scope.
+    function pushcontext(){
+      context = {prev: context, vars: {"this": true, "arguments": true}};
+    }
+    // Pop off the current scope.
+    function popcontext(){
+      context = context.prev;
+    }
+    // Register a variable in the current scope.
+    function register(varname){
+      if (context){
+        mark("js-variabledef");
+        context.vars[varname] = true;
+      }
+    }
+    // Check whether a variable is defined in the current scope.
+    function inScope(varname){
+      var cursor = context;
+      while (cursor) {
+        if (cursor.vars[varname])
+          return true;
+        cursor = cursor.prev;
+      }
+      return false;
+    }
+  
+    // Push a new lexical context of the given type.
+    function pushlex(type){
+      var result = function(){
+        lexical = new JSLexical(indented, column, type, null, lexical)
+      };
+      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 == "var") cont(pushlex("vardef"), vardef1, expect(";"), poplex);
+      else 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 == "function") cont(functiondef);
+      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 == "case") cont(expression, expect(":"));
+      else if (type == "default") cont(expect(":"));
+      else if (type == "catch") cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), statement, poplex, popcontext);
+      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);
+      else if (type == "operator") cont(expression);
+      else if (type == "[") cont(pushlex("]"), commasep(expression), expect("]"), poplex);
+      else if (type == "{") cont(pushlex("}"), commasep(objprop), expect("}"), poplex);
+    }
+    // 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), expect(")"), poplex, maybeoperator);
+      else if (type == ".") cont(property, 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(poplex, statement);
+      else pass(maybeoperator, expect(";"), poplex);
+    }
+    // Property names need to have their style adjusted -- the
+    // tokenizer thinks they are variables.
+    function property(type){
+      if (type == "variable") {mark("js-property"); cont();}
+    }
+    // This parses a property and its value in an object literal.
+    function objprop(type){
+      if (type == "variable") mark("js-property");
+      if (atomicTypes.hasOwnProperty(type)) cont(expect(":"), expression);
+    }
+    // Parses a comma-separated list of the things that are recognized
+    // by the 'what' argument.
+    function commasep(what){
+      function proceed(type) {
+        if (type == ",") cont(what, proceed);
+      };
+      return function commaSeparated() {
+        pass(what, proceed);
+      };
+    }
+    // Look for statements until a closing brace is found.
+    function block(type){
+      if (type == "}") cont();
+      else pass(statement, block);
+    }
+    // Variable definitions are split into two actions -- 1 looks for
+    // a name or the end of the definition, 2 looks for an '=' sign or
+    // a comma.
+    function vardef1(type, value){
+      if (type == "variable"){register(value); cont(vardef2);}
+      else cont();
+    }
+    function vardef2(type){
+      if (type == "operator") cont(expression, vardef2);
+      else if (type == ",") cont(vardef1);
+    }
+    // For loops.
+    function forspec1(type, value){
+      if (type == "var") cont(vardef1, forspec2);
+      else cont(expression, forspec2);
+    }
+    function forspec2(type){
+      if (type == ",") cont(forspec1);
+      if (type == ";") cont(expression, expect(";"), expression);
+    }
+    // A function definition creates a new context, and the variables
+    // in its argument list have to be added to this context.
+    function functiondef(type, value){
+      if (type == "variable"){register(value); cont(functiondef);}
+      else if (type == "(") cont(pushcontext, commasep(funarg), expect(")"), statement, popcontext);
+    }
+    function funarg(type, value){
+      if (type == "variable"){register(value); cont();}
+    }
+  
+    return parser;
+  }
+
+  return {make: parseJS, electricChars: "{}"};
+})();

Added: lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/parsesparql.js
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/parsesparql.js?rev=738808&view=auto
==============================================================================
--- lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/parsesparql.js (added)
+++ lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/parsesparql.js Thu Jan 29 09:49:40 2009
@@ -0,0 +1,162 @@
+Editor.Parser = (function() {
+  function wordRegexp(words) {
+    return new RegExp("^(?:" + words.join("|") + ")$", "i");
+  }
+  var ops = wordRegexp(["str", "lang", "langmatches", "datatype", "bound", "sameterm", "isiri", "isuri",
+                        "isblank", "isliteral", "union", "a"]);
+  var keywords = wordRegexp(["base", "prefix", "select", "distinct", "reduced", "construct", "describe",
+                             "ask", "from", "named", "where", "order", "limit", "offset", "filter", "optional",
+                             "graph", "by", "asc", "desc", ]);
+  var operatorChars = /[*+\-<>=&|]/;
+
+  var tokenizeSparql = (function() {
+    function normal(source, setState) {
+      var ch = source.next();
+      if (ch == "$" || ch == "?") {
+        source.nextWhile(matcher(/[\w\d]/));
+        return "sp-var";
+      }
+      else if (ch == "<" && !source.applies(matcher(/[\s\u00a0=]/))) {
+        source.nextWhile(matcher(/[^\s\u00a0>]/));
+        if (source.equals(">")) source.next();
+        return "sp-uri";
+      }
+      else if (ch == "\"" || ch == "'") {
+        setState(inLiteral(ch));
+        return null;
+      }
+      else if (/[{}\(\),\.;\[\]]/.test(ch)) {
+        return "sp-punc";
+      }
+      else if (ch == "#") {
+        while (!source.endOfLine()) source.next();
+        return "sp-comment";
+      }
+      else if (operatorChars.test(ch)) {
+        source.nextWhile(matcher(operatorChars));
+        return "sp-operator";
+      }
+      else if (ch == ":") {
+        source.nextWhile(matcher(/[\w\d\._\-]/));
+        return "sp-prefixed";
+      }
+      else {
+        source.nextWhile(matcher(/[_\w\d]/));
+        if (source.equals(":")) {
+          source.next();
+          source.nextWhile(matcher(/[\w\d_\-]/));
+          return "sp-prefixed";
+        }
+        var word = source.get(), type;
+        if (ops.test(word))
+          type = "sp-operator";
+        else if (keywords.test(word))
+          type = "sp-keyword";
+        else
+          type = "sp-word";
+        return {style: type, content: word};
+      }
+    }
+
+    function inLiteral(quote) {
+      return function(source, setState) {
+        var escaped = false;
+        while (!source.endOfLine()) {
+          var ch = source.next();
+          if (ch == quote && !escaped) {
+            setState(normal);
+            break;
+          }
+          escaped = !escaped && ch == "\\";
+        }
+        return "sp-literal";
+      };
+    }
+
+    return function(source, startState) {
+      return tokenizer(source, startState || normal);
+    };
+  })();
+
+  function indentSparql(context) {
+    return function(nextChars) {
+      var firstChar = nextChars && nextChars.charAt(0);
+      if (/[\]\}]/.test(firstChar))
+        while (context && context.type == "pattern") context = context.prev;
+
+      var closing = context && firstChar == matching[context.type];
+      if (!context)
+        return 0;
+      else if (context.type == "pattern")
+        return context.col;
+      else if (context.align)
+        return context.col - (closing ? context.width : 0);
+      else
+        return context.indent + (closing ? 0 : 2);
+    }
+  }
+
+  function parseSparql(source) {
+    var tokens = tokenizeSparql(source);
+    var context = null, indent = 0, col = 0;
+    function pushContext(type, width) {
+      context = {prev: context, indent: indent, col: col, type: type, width: width};
+    }
+    function popContext() {
+      context = context.prev;
+    }
+
+    var iter = {
+      next: function() {
+        var token = tokens.next(), type = token.style, content = token.content, width = token.value.length;
+
+        if (content == "\n") {
+          token.indentation = indentSparql(context);
+          indent = col = 0;
+          if (context && context.align == null) context.align = false;
+        }
+        else if (type == "whitespace" && col == 0) {
+          indent = width;
+        }
+        else if (type != "sp-comment" && context && context.align == null) {
+          context.align = true;
+        }
+
+        if (content != "\n") col += width;
+
+        if (/[\[\{\(]/.test(content)) {
+          pushContext(content, width);
+        }
+        else if (/[\]\}\)]/.test(content)) {
+          while (context && context.type == "pattern")
+            popContext();
+          if (context && content == matching[context.type]) 
+            popContext();
+        }
+        else if (content == "." && context && context.type == "pattern") {
+          popContext();
+        }
+        else if ((type == "sp-word" || type == "sp-prefixed" || type == "sp-uri" || type == "sp-var" || type == "sp-literal") &&
+                 context && /[\{\[]/.test(context.type)) {
+          pushContext("pattern", width);
+        }
+
+        return token;
+      },
+
+      copy: function() {
+        var _context = context, _indent = indent, _col = col, _tokenState = tokens.state;
+        return function(source) {
+          tokens = tokenizeSparql(source, _tokenState);
+          context = _context;
+          indent = _indent;
+          col = _col;
+          return iter;
+        };
+      }
+    };
+    return iter;
+  }
+
+  return {make: parseSparql, electricChars: "}]"};
+})();

Added: lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/parsexml.js
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/parsexml.js?rev=738808&view=auto
==============================================================================
--- lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/parsexml.js (added)
+++ lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/parsexml.js Thu Jan 29 09:49:40 2009
@@ -0,0 +1,286 @@
+/* This file defines an XML parser, with a few kludges to make it
+ * useable for HTML. autoSelfClosers defines a set of tag names that
+ * are expected to not have a closing tag, and doNotIndent specifies
+ * the tags inside of which no indentation should happen (see Config
+ * object). These can be disabled by passing the editor an object like
+ * {useHTMLKludges: false} as parserConfig option.
+ */
+
+var XMLParser = Editor.Parser = (function() {
+  var Kludges = {
+    autoSelfClosers: {"br": true, "img": true, "hr": true, "link": true, "input": true,
+                      "meta": true, "col": true, "frame": true, "base": true, "area": true},
+    doNotIndent: {"pre": true}
+  };
+  var NoKludges = {autoSelfClosers: {}, doNotIndent: {}};
+  var UseKludges = Kludges;
+
+  // Simple stateful tokenizer for XML documents. Returns a
+  // MochiKit-style iterator, with a state property that contains a
+  // function encapsulating the current state. See tokenize.js.
+  var tokenizeXML = (function() {
+    function inText(source, setState) {
+      var ch = source.next();
+      if (ch == "<") {
+        if (source.equals("!")) {
+          source.next();
+          if (source.equals("[")) {
+            if (source.lookAhead("[CDATA[", true)) {
+              setState(inBlock("xml-cdata", "]]>"));
+              return null;
+            }
+            else {
+              return "xml-text";
+            }
+          }
+          else if (source.lookAhead("--", true)) {
+            setState(inBlock("xml-comment", "-->"));
+            return null;
+          }
+          else {
+            return "xml-text";
+          }
+        }
+        else if (source.equals("?")) {
+          source.next();
+          source.nextWhile(matcher(/[\w\._\-]/));
+          setState(inBlock("xml-processing", "?>"));
+          return "xml-processing";
+        }
+        else {
+          if (source.equals("/")) source.next();
+          setState(inTag);
+          return "xml-punctuation";
+        }
+      }
+      else if (ch == "&") {
+        while (!source.endOfLine()) {
+          if (source.next() == ";")
+            break;
+        }
+        return "xml-entity";
+      }
+      else {
+        source.nextWhile(matcher(/[^&<\n]/));
+        return "xml-text";
+      }
+    }
+
+    function inTag(source, setState) {
+      var ch = source.next();
+      if (ch == ">") {
+        setState(inText);
+        return "xml-punctuation";
+      }
+      else if (/[?\/]/.test(ch) && source.equals(">")) {
+        source.next();
+        setState(inText);
+        return "xml-punctuation";
+      }
+      else if (ch == "=") {
+        return "xml-punctuation";
+      }
+      else if (/[\'\"]/.test(ch)) {
+        setState(inAttribute(ch));
+        return null;
+      }
+      else {
+        source.nextWhile(matcher(/[^\s\u00a0=<>\"\'\/?]/));
+        return "xml-name";
+      }
+    }
+
+    function inAttribute(quote) {
+      return function(source, setState) {
+        while (!source.endOfLine()) {
+          if (source.next() == quote) {
+            setState(inTag);
+            break;
+          }
+        }
+        return "xml-attribute";
+      };
+    }
+
+    function inBlock(style, terminator) {
+      return function(source, setState) {
+        while (!source.endOfLine()) {
+          if (source.lookAhead(terminator, true)) {
+            setState(inText);
+            break;
+          }
+          source.next();
+        }
+        return style;
+      };
+    }
+
+    return function(source, startState) {
+      return tokenizer(source, startState || inText);
+    };
+  })();
+
+  // The parser. The structure of this function largely follows that of
+  // parseJavaScript in parsejavascript.js (there is actually a bit more
+  // shared code than I'd like), but it is quite a bit simpler.
+  function parseXML(source) {
+    var tokens = tokenizeXML(source);
+    var cc = [base];
+    var tokenNr = 0, indented = 0;
+    var currentTag = null, context = null;
+    var consume, marked;
+    
+    function push(fs) {
+      for (var i = fs.length - 1; i >= 0; i--)
+        cc.push(fs[i]);
+    }
+    function cont() {
+      push(arguments);
+      consume = true;
+    }
+    function pass() {
+      push(arguments);
+      consume = false;
+    }
+
+    function mark(style) {
+      marked = style;
+    }
+    function expect(text) {
+      return function(style, content) {
+        if (content == text) cont();
+        else mark("xml-error") || cont(arguments.callee);
+      };
+    }
+
+    function pushContext(tagname, startOfLine) {
+      var noIndent = UseKludges.doNotIndent.hasOwnProperty(tagname) || (context && context.noIndent);
+      context = {prev: context, name: tagname, indent: indented, startOfLine: startOfLine, noIndent: noIndent};
+    }
+    function popContext() {
+      context = context.prev;
+    }
+    function computeIndentation(baseContext) {
+      return function(nextChars) {
+        var context = baseContext;
+        if (context && context.noIndent)
+          return 0;
+        if (context && /^<\//.test(nextChars))
+          context = context.prev;
+        while (context && !context.startOfLine)
+          context = context.prev;
+        if (context)
+          return context.indent + 2;
+        else
+          return 0;
+      };
+    }
+
+    function base() {
+      return pass(element, base);
+    }
+    var harmlessTokens = {"xml-text": true, "xml-entity": true, "xml-comment": true,
+                          "xml-cdata": true, "xml-processing": true};
+    function element(style, content) {
+      if (content == "<") cont(tagname, attributes, endtag(tokenNr == 1));
+      else if (content == "</") cont(closetagname, expect(">"));
+      else if (content == "<?") cont(tagname, attributes, expect("?>"));
+      else if (harmlessTokens.hasOwnProperty(style)) cont();
+      else mark("xml-error") || cont();
+    }
+    function tagname(style, content) {
+      if (style == "xml-name") {
+        currentTag = content.toLowerCase();
+        mark("xml-tagname");
+        cont();
+      }
+      else {
+        currentTag = null;
+        pass();
+      }
+    }
+    function closetagname(style, content) {
+      if (style == "xml-name" && context && content.toLowerCase() == context.name) {
+        popContext();
+        mark("xml-tagname");
+      }
+      else {
+        mark("xml-error");
+      }
+      cont();
+    }
+    function endtag(startOfLine) {
+      return function(style, content) {
+        if (content == "/>" || (content == ">" && UseKludges.autoSelfClosers.hasOwnProperty(currentTag))) cont();
+        else if (content == ">") pushContext(currentTag, startOfLine) || cont();
+        else mark("xml-error") || cont(arguments.callee);
+      };
+    }
+    function attributes(style) {
+      if (style == "xml-name") mark("xml-attname") || cont(attribute, attributes);
+      else pass();
+    }
+    function attribute(style, content) {
+      if (content == "=") cont(value);
+      else if (content == ">" || content == "/>") pass(endtag);
+      else pass();
+    }
+    function value(style) {
+      if (style == "xml-attribute") cont(value);
+      else pass();
+    }
+
+    return {
+      indentation: function() {return indented;},
+
+      next: function(){
+        var token = tokens.next();
+        if (token.style == "whitespace" && tokenNr == 0)
+          indented = token.value.length;
+        else
+          tokenNr++;
+        if (token.content == "\n") {
+          indented = tokenNr = 0;
+          token.indentation = computeIndentation(context);
+        }
+
+        if (token.style == "whitespace" || token.type == "xml-comment")
+          return token;
+
+        while(true){
+          consume = marked = false;
+          cc.pop()(token.style, token.content);
+          if (consume){
+            if (marked)
+              token.style = marked;
+            return token;
+          }
+        }
+      },
+
+      copy: function(){
+        var _cc = cc.concat([]), _tokenState = tokens.state, _context = context;
+        var parser = this;
+        
+        return function(input){
+          cc = _cc.concat([]);
+          tokenNr = indented = 0;
+          context = _context;
+          tokens = tokenizeXML(input, _tokenState);
+          return parser;
+        };
+      }
+    };
+  }
+
+  return {
+    make: parseXML,
+    electricChars: "/",
+    configure: function(config) {
+      if (config.useHTMLKludges)
+        UseKludges = Kludges;
+      else
+        UseKludges = NoKludges;
+    }
+  };
+})();

Added: lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/select.js
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/select.js?rev=738808&view=auto
==============================================================================
--- lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/select.js (added)
+++ lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/select.js Thu Jan 29 09:49:40 2009
@@ -0,0 +1,584 @@
+/* Functionality for finding, storing, and restoring selections
+ *
+ * This does not provide a generic API, just the minimal functionality
+ * required by the CodeMirror system.
+ */
+
+// Namespace object.
+var select = {};
+
+(function() {
+  select.ie_selection = document.selection && document.selection.createRangeCollection;
+
+  // Find the 'top-level' (defined as 'a direct child of the node
+  // passed as the top argument') node that the given node is
+  // contained in. Return null if the given node is not inside the top
+  // node.
+  function topLevelNodeAt(node, top) {
+    while (node && node.parentNode != top)
+      node = node.parentNode;
+    return node;
+  }
+
+  // Find the top-level node that contains the node before this one.
+  function topLevelNodeBefore(node, top) {
+    while (!node.previousSibling && node.parentNode != top)
+      node = node.parentNode;
+    return topLevelNodeAt(node.previousSibling, top);
+  }
+
+  // Used to prevent restoring a selection when we do not need to.
+  var currentSelection = null;
+
+  var fourSpaces = "\u00a0\u00a0\u00a0\u00a0";
+
+  select.snapshotChanged = function() {
+    if (currentSelection) currentSelection.changed = true;
+  };
+
+  // This is called by the code in editor.js whenever it is replacing
+  // a text node. The function sees whether the given oldNode is part
+  // of the current selection, and updates this selection if it is.
+  // Because nodes are often only partially replaced, the length of
+  // the part that gets replaced has to be taken into account -- the
+  // selection might stay in the oldNode if the newNode is smaller
+  // than the selection's offset. The offset argument is needed in
+  // case the selection does move to the new object, and the given
+  // length is not the whole length of the new node (part of it might
+  // have been used to replace another node).
+  select.snapshotReplaceNode = function(from, to, length, offset) {
+    if (!currentSelection) return;
+    currentSelection.changed = true;
+
+    function replace(point) {
+      if (from == point.node) {
+        if (length && point.offset > length) {
+          point.offset -= length;
+        }
+        else {
+          point.node = to;
+          point.offset += (offset || 0);
+        }
+      }
+    }
+    replace(currentSelection.start);
+    replace(currentSelection.end);
+  };
+
+  select.snapshotMove = function(from, to, distance, relative, ifAtStart) {
+    if (!currentSelection) return;
+    currentSelection.changed = true;
+
+    function move(point) {
+      if (from == point.node && (!ifAtStart || point.offset == 0)) {
+        point.node = to;
+        if (relative) point.offset = Math.max(0, point.offset + distance);
+        else point.offset = distance;
+      }
+    }
+    move(currentSelection.start);
+    move(currentSelection.end);
+  };
+
+  // Most functions are defined in two ways, one for the IE selection
+  // model, one for the W3C one.
+  if (select.ie_selection) {
+    function selectionNode(win, start) {
+      var range = win.document.selection.createRange();
+      range.collapse(start);
+
+      function nodeAfter(node) {
+        var found = null;
+        while (!found && node) {
+          found = node.nextSibling;
+          node = node.parentNode;
+        }
+        return nodeAtStartOf(found);
+      }
+
+      function nodeAtStartOf(node) {
+        while (node && node.firstChild) node = node.firstChild;
+        return {node: node, offset: 0};
+      }
+
+      var containing = range.parentElement();
+      if (!isAncestor(win.document.body, containing)) return null;
+      if (!containing.firstChild) return nodeAtStartOf(containing);
+
+      var working = range.duplicate();
+      working.moveToElementText(containing);
+      working.collapse(true);
+      for (var cur = containing.firstChild; cur; cur = cur.nextSibling) {
+        if (cur.nodeType == 3) {
+          var size = cur.nodeValue.length;
+          working.move("character", size);
+        }
+        else {
+          working.moveToElementText(cur);
+          working.collapse(false);
+        }
+
+        var dir = range.compareEndPoints("StartToStart", working);
+        if (dir == 0) return nodeAfter(cur);
+        if (dir == 1) continue;
+        if (cur.nodeType != 3) return nodeAtStartOf(cur);
+
+        working.setEndPoint("StartToEnd", range);
+        return {node: cur, offset: size - working.text.length};
+      }
+      return nodeAfter(containing);
+    }
+
+    select.markSelection = function(win) {
+      currentSelection = null;
+      var sel = win.document.selection;
+      if (!sel) return;
+      var start = selectionNode(win, true),
+          end = sel.createRange().text == "" ? start : selectionNode(win, false);
+      if (!start || !end) return;
+      currentSelection = {start: start, end: end, window: win, changed: false};
+    };
+
+    select.selectMarked = function() {
+      if (!currentSelection || !currentSelection.changed) return;
+
+      function makeRange(point) {
+        var range = currentSelection.window.document.body.createTextRange();
+        var node = point.node;
+        if (!node) {
+          range.moveToElementText(win.document.body);
+          range.collapse(false);
+        }
+        else if (node.nodeType == 3) {
+          range.moveToElementText(node.parentNode);
+          var offset = point.offset;
+          while (node.previousSibling) {
+            node = node.previousSibling;
+            offset += (node.innerText || "").length;
+          }
+          range.move("character", offset);
+        }
+        else {
+          range.moveToElementText(node);
+          range.collapse(true);
+        }
+        return range;
+      }
+
+      var start = makeRange(currentSelection.start), end = makeRange(currentSelection.end);
+      start.setEndPoint("StartToEnd", end);
+      start.select();
+    };
+
+    // Get the top-level node that one end of the cursor is inside or
+    // after. Note that this returns false for 'no cursor', and null
+    // for 'start of document'.
+    select.selectionTopNode = function(container, start) {
+      var selection = container.ownerDocument.selection;
+      if (!selection) return false;
+
+      var range = selection.createRange();
+      range.collapse(start);
+      var around = range.parentElement();
+      if (around && isAncestor(container, around)) {
+        // Only use this node if the selection is not at its start.
+        var range2 = range.duplicate();
+        range2.moveToElementText(around);
+        if (range.compareEndPoints("StartToStart", range2) == -1)
+          return topLevelNodeAt(around, container);
+      }
+      // Fall-back hack
+      try {range.pasteHTML("<span id='xxx-temp-xxx'></span>");}
+      catch (e) {return false;}
+
+      var temp = container.ownerDocument.getElementById("xxx-temp-xxx");
+      if (temp) {
+        var result = topLevelNodeBefore(temp, container);
+        removeElement(temp);
+        return result;
+      }
+      return false;
+    };
+
+    // Place the cursor after this.start. This is only useful when
+    // manually moving the cursor instead of restoring it to its old
+    // position.
+    select.focusAfterNode = function(node, container) {
+      var range = container.ownerDocument.body.createTextRange();
+      range.moveToElementText(node || container);
+      range.collapse(!node);
+      range.select();
+    };
+
+    select.somethingSelected = function(win) {
+      var sel = win.document.selection;
+      return sel && (sel.createRange().text != "");
+    };
+
+    function insertAtCursor(window, html) {
+      var selection = window.document.selection;
+      if (selection) {
+        var range = selection.createRange();
+        range.pasteHTML(html);
+        range.collapse(false);
+        range.select();
+      }
+    }
+
+    // Used to normalize the effect of the enter key, since browsers
+    // do widely different things when pressing enter in designMode.
+    select.insertNewlineAtCursor = function(window) {
+      insertAtCursor(window, "<br/>");
+    };
+
+    select.insertTabAtCursor = function(window) {
+      insertAtCursor(window, fourSpaces);
+    };
+
+    // Get the BR node at the start of the line on which the cursor
+    // currently is, and the offset into the line. Returns null as
+    // node if cursor is on first line.
+    select.cursorPos = function(container, start) {
+      var selection = container.ownerDocument.selection;
+      if (!selection) return null;
+
+      var topNode = select.selectionTopNode(container, start);
+      while (topNode && topNode.nodeName != "BR")
+        topNode = topNode.previousSibling;
+
+      var range = selection.createRange(), range2 = range.duplicate();
+      range.collapse(start);
+      if (topNode) {
+        range2.moveToElementText(topNode);
+        range2.collapse(false);
+      }
+      else {
+        // When nothing is selected, we can get all kinds of funky errors here.
+        try { range2.moveToElementText(container); }
+        catch (e) { return null; }
+        range2.collapse(true);
+      }
+      range.setEndPoint("StartToStart", range2);
+
+      return {node: topNode, offset: range.text.length};
+    };
+
+    select.setCursorPos = function(container, from, to) {
+      function rangeAt(pos) {
+        var range = container.ownerDocument.body.createTextRange();
+        if (!pos.node) {
+          range.moveToElementText(container);
+          range.collapse(true);
+        }
+        else {
+          range.moveToElementText(pos.node);
+          range.collapse(false);
+        }
+        range.move("character", pos.offset);
+        return range;
+      }
+
+      var range = rangeAt(from);
+      if (to && to != from)
+        range.setEndPoint("EndToEnd", rangeAt(to));
+      range.select();
+    }
+
+    // Make sure the cursor is visible.
+    select.scrollToCursor = function(container) {
+      var selection = container.ownerDocument.selection;
+      if (!selection) return null;
+      selection.createRange().scrollIntoView();
+    };
+
+    // Some hacks for storing and re-storing the selection when the editor loses and regains focus.
+    select.selectionCoords = function (win) {
+      var selection = win.document.selection;
+      if (!selection) return null;
+      var start = selection.createRange(), end = start.duplicate();
+      start.collapse(true);
+      end.collapse(false);
+
+      var body = win.document.body;
+      return {start: {x: start.boundingLeft + body.scrollLeft - 1,
+                      y: start.boundingTop + body.scrollTop},
+              end: {x: end.boundingLeft + body.scrollLeft - 1,
+                    y: end.boundingTop + body.scrollTop}};
+    };
+
+    // Restore a stored selection.
+    select.selectCoords = function(win, coords) {
+      if (!coords) return;
+
+      var range1 = win.document.body.createTextRange(), range2 = range1.duplicate();
+      // This can fail for various hard-to-handle reasons.
+      try {
+        range1.moveToPoint(coords.start.x, coords.start.y);
+        range2.moveToPoint(coords.end.x, coords.end.y);
+        range1.setEndPoint("EndToStart", range2);
+        range1.select();
+      } catch(e) {alert(e.message);}
+    };
+  }
+  // W3C model
+  else {
+    // This is used to fix an issue with getting the scroll position
+    // in Opera.
+    var opera_scroll = window.scrollX == null;
+
+    // Store start and end nodes, and offsets within these, and refer
+    // back to the selection object from those nodes, so that this
+    // object can be updated when the nodes are replaced before the
+    // selection is restored.
+    select.markSelection = function (win) {
+      var selection = win.getSelection();
+      if (!selection || selection.rangeCount == 0)
+        return (currentSelection = null);
+      var range = selection.getRangeAt(0);
+
+      currentSelection = {
+        start: {node: range.startContainer, offset: range.startOffset},
+        end: {node: range.endContainer, offset: range.endOffset},
+        window: win,
+        scrollX: opera_scroll && win.document.body.scrollLeft,
+        scrollY: opera_scroll && win.document.body.scrollTop,
+        changed: false
+      };
+
+      // We want the nodes right at the cursor, not one of their
+      // ancestors with a suitable offset. This goes down the DOM tree
+      // until a 'leaf' is reached (or is it *up* the DOM tree?).
+      function normalize(point){
+        while (point.node.nodeType != 3 && point.node.nodeName != "BR") {
+          var newNode = point.node.childNodes[point.offset] || point.node.nextSibling;
+          point.offset = 0;
+          while (!newNode && point.node.parentNode) {
+            point.node = point.node.parentNode;
+            newNode = point.node.nextSibling;
+          }
+          point.node = newNode;
+          if (!newNode)
+            break;
+        }
+      }
+
+      normalize(currentSelection.start);
+      normalize(currentSelection.end);
+    };
+
+    select.selectMarked = function () {
+      if (!currentSelection || !currentSelection.changed) return;
+      var win = currentSelection.window, range = win.document.createRange();
+
+      function setPoint(point, which) {
+        if (point.node) {
+          // Some magic to generalize the setting of the start and end
+          // of a range.
+          if (point.offset == 0)
+            range["set" + which + "Before"](point.node);
+          else
+            range["set" + which](point.node, point.offset);
+        }
+        else {
+          range.setStartAfter(win.document.body.lastChild || win.document.body);
+        }
+      }
+
+      // Have to restore the scroll position of the frame in Opera.
+      if (opera_scroll) {
+        win.document.body.scrollLeft = currentSelection.scrollX;
+        win.document.body.scrollTop = currentSelection.scrollY;
+      }
+      setPoint(currentSelection.end, "End");
+      setPoint(currentSelection.start, "Start");
+      selectRange(range, win);
+    };
+
+    // Helper for selecting a range object.
+    function selectRange(range, window) {
+      var selection = window.getSelection();
+      selection.removeAllRanges();
+      selection.addRange(range);
+    };
+    function selectionRange(window) {
+      var selection = window.getSelection();
+      if (!selection || selection.rangeCount == 0)
+        return false;
+      else
+        return selection.getRangeAt(0);
+    }
+
+    // Finding the top-level node at the cursor in the W3C is, as you
+    // can see, quite an involved process.
+    select.selectionTopNode = function(container, start) {
+      var range = selectionRange(container.ownerDocument.defaultView);
+      if (!range) return false;
+
+      var node = start ? range.startContainer : range.endContainer;
+      var offset = start ? range.startOffset : range.endOffset;
+      // Work around (yet another) bug in Opera's selection model.
+      if (window.opera && !start && range.endContainer == container && range.endOffset == range.startOffset + 1 &&
+          container.childNodes[range.startOffset] && container.childNodes[range.startOffset].nodeName == "BR")
+        offset--;
+
+      // For text nodes, we look at the node itself if the cursor is
+      // inside, or at the node before it if the cursor is at the
+      // start.
+      if (node.nodeType == 3){
+        if (offset > 0)
+          return topLevelNodeAt(node, container);
+        else
+          return topLevelNodeBefore(node, container);
+      }
+      // Occasionally, browsers will return the HTML node as
+      // selection. If the offset is 0, we take the start of the frame
+      // ('after null'), otherwise, we take the last node.
+      else if (node.nodeName == "HTML") {
+        return (offset == 1 ? null : container.lastChild);
+      }
+      // If the given node is our 'container', we just look up the
+      // correct node by using the offset.
+      else if (node == container) {
+        return (offset == 0) ? null : node.childNodes[offset - 1];
+      }
+      // In any other case, we have a regular node. If the cursor is
+      // at the end of the node, we use the node itself, if it is at
+      // the start, we use the node before it, and in any other
+      // case, we look up the child before the cursor and use that.
+      else {
+        if (offset == node.childNodes.length)
+          return topLevelNodeAt(node, container);
+        else if (offset == 0)
+          return topLevelNodeBefore(node, container);
+        else
+          return topLevelNodeAt(node.childNodes[offset - 1], container);
+      }
+    };
+
+    select.focusAfterNode = function(node, container) {
+      var win = container.ownerDocument.defaultView,
+          range = win.document.createRange();
+      range.setStartBefore(container.firstChild || container);
+      // In Opera, setting the end of a range at the end of a line
+      // (before a BR) will cause the cursor to appear on the next
+      // line, so we set the end inside of the start node when
+      // possible.
+      if (node && !node.firstChild)
+        range.setEndAfter(node);
+      else if (node)
+        range.setEnd(node, node.childNodes.length);
+      else
+        range.setEndBefore(container.firstChild || container);
+      range.collapse(false);
+      selectRange(range, win);
+    };
+
+    select.somethingSelected = function(win) {
+      var range = selectionRange(win);
+      return range && !range.collapsed;
+    };
+
+    function insertNodeAtCursor(window, node) {
+      var range = selectionRange(window);
+      if (!range) return;
+
+      range.deleteContents();
+      range.insertNode(node);
+      range.setEndAfter(node);
+      range.collapse(false);
+      selectRange(range, window);
+      return node;
+    }
+
+    select.insertNewlineAtCursor = function(window) {
+      insertNodeAtCursor(window, window.document.createElement("BR"));
+    };
+
+    select.insertTabAtCursor = function(window) {
+      insertNodeAtCursor(window, window.document.createTextNode(fourSpaces));
+    };
+
+    select.cursorPos = function(container, start) {
+      var range = selectionRange(window);
+      if (!range) return;
+
+      var topNode = select.selectionTopNode(container, start);
+      while (topNode && topNode.nodeName != "BR")
+        topNode = topNode.previousSibling;
+
+      range = range.cloneRange();
+      range.collapse(start);
+      if (topNode)
+        range.setStartAfter(topNode);
+      else
+        range.setStartBefore(container);
+      return {node: topNode, offset: range.toString().length};
+    };
+
+    select.setCursorPos = function(container, from, to) {
+      var win = container.ownerDocument.defaultView,
+          range = win.document.createRange();
+
+      function setPoint(node, offset, side) {
+        if (!node)
+          node = container.firstChild;
+        else
+          node = node.nextSibling;
+
+        if (!node)
+          return;
+
+        if (offset == 0) {
+          range["set" + side + "Before"](node);
+          return true;
+        }
+
+        var backlog = []
+        function decompose(node) {
+          if (node.nodeType == 3)
+            backlog.push(node);
+          else
+            forEach(node.childNodes, decompose);
+        }
+        while (true) {
+          while (node && !backlog.length) {
+            decompose(node);
+            node = node.nextSibling;
+          }
+          var cur = backlog.shift();
+          if (!cur) return false;
+
+          var length = cur.nodeValue.length;
+          if (length >= offset) {
+            range["set" + side](cur, offset);
+            return true;
+          }
+          offset -= length;
+        }
+      }
+
+      to = to || from;
+      if (setPoint(to.node, to.offset, "End") && setPoint(from.node, from.offset, "Start"))
+        selectRange(range, win);
+    };
+
+    select.scrollToCursor = function(container) {
+      var body = container.ownerDocument.body, win = container.ownerDocument.defaultView;
+      var element = select.selectionTopNode(container, true) || container.firstChild;
+      
+      // In Opera, BR elements *always* have a scrollTop property of zero. Go Opera.
+      while (element && !element.offsetTop)
+        element = element.previousSibling;
+
+      var y = 0, pos = element;
+      while (pos && pos.offsetParent) {
+        y += pos.offsetTop;
+        pos = pos.offsetParent;
+      }
+
+      var screen_y = y - body.scrollTop;
+      if (screen_y < 0 || screen_y > win.innerHeight - 10)
+        win.scrollTo(0, y);
+    };
+  }
+})();

Added: lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/stringstream.js
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/stringstream.js?rev=738808&view=auto
==============================================================================
--- lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/stringstream.js (added)
+++ lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/stringstream.js Thu Jan 29 09:49:40 2009
@@ -0,0 +1,131 @@
+/* String streams are the things fed to parsers (which can feed them
+ * to a tokenizer if they want). They provide peek and next methods
+ * for looking at the current character (next 'consumes' this
+ * character, peek does not), and a get method for retrieving all the
+ * text that was consumed since the last time get was called.
+ *
+ * An easy mistake to make is to let a StopIteration exception finish
+ * the token stream while there are still characters pending in the
+ * string stream (hitting the end of the buffer while parsing a
+ * token). To make it easier to detect such errors, the strings throw
+ * an exception when this happens.
+ */
+
+// Make a string stream out of an iterator that returns strings. This
+// is applied to the result of traverseDOM (see codemirror.js), and
+// the resulting stream is fed to the parser.
+window.stringStream = function(source){
+  source = iter(source);
+  // String that's currently being iterated over.
+  var current = "";
+  // Position in that string.
+  var pos = 0;
+  // Accumulator for strings that have been iterated over but not
+  // get()-ed yet.
+  var accum = "";
+  // Make sure there are more characters ready, or throw
+  // StopIteration.
+  function ensureChars() {
+    while (pos == current.length) {
+      accum += current;
+      current = ""; // In case source.next() throws
+      pos = 0;
+      try {current = source.next();}
+      catch (e) {
+        if (e != StopIteration) throw e;
+        else return false;
+      }
+    }
+    return true;
+  }
+
+  return {
+    // Return the next character in the stream.
+    peek: function() {
+      if (!ensureChars()) return null;
+      return current.charAt(pos);
+    },
+    // Get the next character, throw StopIteration if at end, check
+    // for unused content.
+    next: function() {
+      if (!ensureChars()) {
+        if (accum.length > 0)
+          throw "End of stringstream reached without emptying buffer ('" + accum + "').";
+        else
+          throw StopIteration;
+      }
+      return current.charAt(pos++);
+    },
+    // Return the characters iterated over since the last call to
+    // .get().
+    get: function() {
+      var temp = accum;
+      accum = "";
+      if (pos > 0){
+        temp += current.slice(0, pos);
+        current = current.slice(pos);
+        pos = 0;
+      }
+      return temp;
+    },
+    // Push a string back into the stream.
+    push: function(str) {
+      current = current.slice(0, pos) + str + current.slice(pos);
+    },
+    lookAhead: function(str, consume, skipSpaces, caseInsensitive) {
+      function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
+      str = cased(str);
+      var found = false;
+
+      var _accum = accum, _pos = pos;
+      if (skipSpaces) this.nextWhile(matcher(/[\s\u00a0]/));
+
+      while (true) {
+        var end = pos + str.length, left = current.length - pos;
+        if (end <= current.length) {
+          found = str == cased(current.slice(pos, end));
+          pos = end;
+          break;
+        }
+        else if (str.slice(0, left) == cased(current.slice(pos))) {
+          accum += current; current = "";
+          try {current = source.next();}
+          catch (e) {break;}
+          pos = 0;
+          str = str.slice(left);
+        }
+        else {
+          break;
+        }
+      }
+
+      if (!(found && consume)) {
+        current = accum.slice(_accum.length) + current;
+        pos = _pos;
+        accum = _accum;
+      }
+
+      return found;
+    },
+
+    // Utils built on top of the above
+    more: function() {
+      return this.peek() !== null;
+    },
+    applies: function(test) {
+      var next = this.peek();
+      return (next !== null && test(next));
+    },
+    nextWhile: function(test) {
+      while (this.applies(test))
+        this.next();
+    },
+    equals: function(ch) {
+      return ch === this.peek();
+    },
+    endOfLine: function() {
+      var next = this.peek();
+      return next == null || next == "\n";
+    }
+  };
+};

Added: lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/tokenize.js
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/tokenize.js?rev=738808&view=auto
==============================================================================
--- lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/tokenize.js (added)
+++ lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/tokenize.js Thu Jan 29 09:49:40 2009
@@ -0,0 +1,57 @@
+// A framework for simple tokenizers. Takes care of newlines and
+// white-space, and of getting the text from the source stream into
+// the token object. A state is a function of two arguments -- a
+// string stream and a setState function. The second can be used to
+// change the tokenizer's state, and can be ignored for stateless
+// tokenizers. This function should advance the stream over a token
+// and return a string or object containing information about the next
+// token, or null to pass and have the (new) state be called to finish
+// the token. When a string is given, it is wrapped in a {style, type}
+// object. In the resulting object, the characters consumed are stored
+// under the content property. Any whitespace following them is also
+// automatically consumed, and added to the value property. (Thus,
+// content is the actual meaningful part of the token, while value
+// contains all the text it spans.)
+
+function tokenizer(source, state) {
+  // Newlines are always a separate token.
+  function isWhiteSpace(ch) {
+    // The messy regexp is because IE's regexp matcher is of the
+    // opinion that non-breaking spaces are no whitespace.
+    return ch != "\n" && /^[\s\u00a0]*$/.test(ch);
+  }
+
+  var tokenizer = {
+    state: state,
+
+    take: function(type) {
+      if (typeof(type) == "string")
+        type = {style: type, type: type};
+
+      type.content = (type.content || "") + source.get();
+      if (!/\n$/.test(type.content))
+        source.nextWhile(isWhiteSpace);
+      type.value = type.content + source.get();
+      return type;
+    },
+
+    next: function () {
+      if (!source.more()) throw StopIteration;
+
+      var type;
+      if (source.equals("\n")) {
+        source.next();
+        return this.take("whitespace");
+      }
+      
+      if (source.applies(isWhiteSpace))
+        type = "whitespace";
+      else
+        while (!type)
+          type = this.state(source, function(s) {tokenizer.state = s;});
+
+      return this.take(type);
+    }
+  };
+  return tokenizer;
+}

Added: lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/tokenizejavascript.js
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/tokenizejavascript.js?rev=738808&view=auto
==============================================================================
--- lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/tokenizejavascript.js (added)
+++ lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/tokenizejavascript.js Thu Jan 29 09:49:40 2009
@@ -0,0 +1,176 @@
+/* Tokenizer for JavaScript code */
+
+var tokenizeJavaScript = (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 JavaScript'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: style};
+    }
+    // keywords that take a parenthised expression, and then a
+    // statement (if)
+    var keywordA = result("keyword a", "js-keyword");
+    // keywords that take just a statement (else)
+    var keywordB = result("keyword b", "js-keyword");
+    // keywords that optionally take an expression, and form a
+    // statement (return)
+    var keywordC = result("keyword c", "js-keyword");
+    var operator = result("operator", "js-keyword");
+    var atom = result("atom", "js-atom");
+    return {
+      "if": keywordA, "switch": keywordA, "while": keywordA, "with": keywordA,
+      "else": keywordB, "do": keywordB, "try": keywordB, "finally": keywordB,
+      "return": keywordC, "break": keywordC, "continue": keywordC, "new": keywordC, "delete": keywordC, "throw": keywordC,
+      "in": operator, "typeof": operator, "instanceof": operator,
+      "var": result("var", "js-keyword"), "function": result("function", "js-keyword"), "catch": result("catch", "js-keyword"),
+      "for": result("for", "js-keyword"), 
+      "case": result("case", "js-keyword"), "default": result("default", "js-keyword"),
+      "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom
+    };
+  }();
+
+  // Some helper regexp matchers.
+  var isOperatorChar = matcher(/[+\-*&%\/=<>!?|]/);
+  var isDigit = matcher(/[0-9]/);
+  var isHexDigit = matcher(/[0-9A-Fa-f]/);
+  var isWordChar = matcher(/[\w\$_]/);
+
+  // Wrapper around jsToken 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 jsTokenState(inside, regexp) {
+    return function(source, setState) {
+      var newInside = inside;
+      var type = jsToken(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(jsTokenState(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 jsToken(inside, regexp, source, setInside) {
+    function readHexNumber(){
+      source.next(); // skip the 'x'
+      source.nextWhile(isHexDigit);
+      return {type: "number", style: "js-atom"};
+    }
+
+    function readNumber() {
+      source.nextWhile(isDigit);
+      if (source.equals(".")){
+        source.next();
+        source.nextWhile(isDigit);
+      }
+      if (source.equals("e") || source.equals("E")){
+        source.next();
+        if (source.equals("-"))
+          source.next();
+        source.nextWhile(isDigit);
+      }
+      return {type: "number", style: "js-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.nextWhile(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: "js-variable", content: word};
+    }
+    function readRegexp() {
+      nextUntilUnescaped(source, "/");
+      source.nextWhile(matcher(/[gi]/));
+      return {type: "regexp", style: "js-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: "js-comment"};
+    }
+    function readOperator() {
+      source.nextWhile(isOperatorChar);
+      return {type: "operator", style: "js-operator"};
+    }
+    function readString(quote) {
+      var endBackSlash = nextUntilUnescaped(source, quote);
+      setInside(endBackSlash ? quote : null);
+      return {type: "string", style: "js-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 (ch == "\"" || ch == "'")
+      return readString(ch);
+    // with punctuation, the type of the token is the symbol itself
+    else if (/[\[\]{}\(\),;\:\.]/.test(ch))
+      return {type: ch, style: "js-punctuation"};
+    else if (ch == "0" && (source.equals("x") || source.equals("X")))
+      return readHexNumber();
+    else if (isDigit(ch))
+      return readNumber();
+    else if (ch == "/"){
+      if (source.equals("*"))
+      { source.next(); return readMultilineComment(ch); }
+      else if (source.equals("/"))
+      { nextUntilUnescaped(source, null); return {type: "comment", style: "js-comment"};}
+      else if (regexp)
+        return readRegexp();
+      else
+        return readOperator();
+    }
+    else if (isOperatorChar(ch))
+      return readOperator();
+    else
+      return readWord();
+  }
+
+  // The external interface to the tokenizer.
+  return function(source, startState) {
+    return tokenizer(source, startState || jsTokenState(false, true));
+  };
+})();

Added: lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/undo.js
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/undo.js?rev=738808&view=auto
==============================================================================
--- lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/undo.js (added)
+++ lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/undo.js Thu Jan 29 09:49:40 2009
@@ -0,0 +1,388 @@
+/**
+ * Storage and control for undo information within a CodeMirror
+ * editor. 'Why on earth is such a complicated mess required for
+ * that?', I hear you ask. The goal, in implementing this, was to make
+ * the complexity of storing and reverting undo information depend
+ * only on the size of the edited or restored content, not on the size
+ * of the whole document. This makes it necessary to use a kind of
+ * 'diff' system, which, when applied to a DOM tree, causes some
+ * complexity and hackery.
+ *
+ * In short, the editor 'touches' BR elements as it parses them, and
+ * the History stores these. When nothing is touched in commitDelay
+ * milliseconds, the changes are committed: It goes over all touched
+ * nodes, throws out the ones that did not change since last commit or
+ * are no longer in the document, and assembles the rest into zero or
+ * more 'chains' -- arrays of adjacent lines. Links back to these
+ * chains are added to the BR nodes, while the chain that previously
+ * spanned these nodes is added to the undo history. Undoing a change
+ * means taking such a chain off the undo history, restoring its
+ * content (text is saved per line) and linking it back into the
+ * document.
+ */
+
+// A history object needs to know about the DOM container holding the
+// document, the maximum amount of undo levels it should store, the
+// delay (of no input) after which it commits a set of changes, and,
+// unfortunately, the 'parent' window -- a window that is not in
+// designMode, and on which setTimeout works in every browser.
+function History(container, maxDepth, commitDelay, editor, onChange) {
+  this.container = container;
+  this.maxDepth = maxDepth; this.commitDelay = commitDelay;
+  this.editor = editor; this.parent = editor.parent;
+  this.onChange = onChange;
+  // This line object represents the initial, empty editor.
+  var initial = {text: "", from: null, to: null};
+  // As the borders between lines are represented by BR elements, the
+  // start of the first line and the end of the last one are
+  // represented by null. Since you can not store any properties
+  // (links to line objects) in null, these properties are used in
+  // those cases.
+  this.first = initial; this.last = initial;
+  // Similarly, a 'historyTouched' property is added to the BR in
+  // front of lines that have already been touched, and 'firstTouched'
+  // is used for the first line.
+  this.firstTouched = false;
+  // History is the set of committed changes, touched is the set of
+  // nodes touched since the last commit.
+  this.history = []; this.redoHistory = []; this.touched = [];
+}
+
+History.prototype = {
+  // Schedule a commit (if no other touches come in for commitDelay
+  // milliseconds).
+  scheduleCommit: function() {
+    this.parent.clearTimeout(this.commitTimeout);
+    this.commitTimeout = this.parent.setTimeout(method(this, "tryCommit"), this.commitDelay);
+  },
+
+  // Mark a node as touched. Null is a valid argument.
+  touch: function(node) {
+    this.setTouched(node);
+    this.scheduleCommit();
+  },
+
+  // Undo the last change.
+  undo: function() {
+    // Make sure pending changes have been committed.
+    this.commit();
+
+    if (this.history.length) {
+      // Take the top diff from the history, apply it, and store its
+      // shadow in the redo history.
+      this.redoHistory.push(this.updateTo(this.history.pop(), "applyChain"));
+      if (this.onChange) this.onChange();
+    }
+  },
+
+  // Redo the last undone change.
+  redo: function() {
+    this.commit();
+    if (this.redoHistory.length) {
+      // The inverse of undo, basically.
+      this.addUndoLevel(this.updateTo(this.redoHistory.pop(), "applyChain"));
+      if (this.onChange) this.onChange();
+    }
+  },
+
+  // Push a changeset into the document.
+  push: function(from, to, lines) {
+    var chain = [];
+    for (var i = 0; i < lines.length; i++) {
+      var end = (i == lines.length - 1) ? to : this.container.ownerDocument.createElement("BR");
+      chain.push({from: from, to: end, text: lines[i]});
+      from = end;
+    }
+    this.pushChains([chain], from == null && to == null);
+  },
+
+  pushChains: function(chains, doNotHighlight) {
+    this.commit(doNotHighlight);
+    this.addUndoLevel(this.updateTo(chains, "applyChain"));
+    this.redoHistory = [];
+  },
+
+  // Clear the undo history, make the current document the start
+  // position.
+  reset: function() {
+    this.history = []; this.redoHistory = [];
+  },
+
+  textAfter: function(br) {
+    return this.after(br).text;
+  },
+
+  nodeAfter: function(br) {
+    return this.after(br).to;
+  },
+
+  nodeBefore: function(br) {
+    return this.before(br).from;
+  },
+
+  // Commit unless there are pending dirty nodes.
+  tryCommit: function() {
+    if (this.editor.highlightDirty()) this.commit();
+    else this.scheduleCommit();
+  },
+
+  // Check whether the touched nodes hold any changes, if so, commit
+  // them.
+  commit: function(doNotHighlight) {
+    this.parent.clearTimeout(this.commitTimeout);
+    // Make sure there are no pending dirty nodes.
+    if (!doNotHighlight) this.editor.highlightDirty(true);
+    // Build set of chains.
+    var chains = this.touchedChains(), self = this;
+
+    if (chains.length) {
+      this.addUndoLevel(this.updateTo(chains, "linkChain"));
+      this.redoHistory = [];
+      if (this.onChange) this.onChange();
+    }
+  },
+
+  // [ end of public interface ]
+
+  // Update the document with a given set of chains, return its
+  // shadow. updateFunc should be "applyChain" or "linkChain". In the
+  // second case, the chains are taken to correspond the the current
+  // document, and only the state of the line data is updated. In the
+  // first case, the content of the chains is also pushed iinto the
+  // document.
+  updateTo: function(chains, updateFunc) {
+    var shadows = [], dirty = [];
+    for (var i = 0; i < chains.length; i++) {
+      shadows.push(this.shadowChain(chains[i]));
+      dirty.push(this[updateFunc](chains[i]));
+    }
+    if (updateFunc == "applyChain")
+      this.notifyDirty(dirty);
+    return shadows;
+  },
+
+  // Notify the editor that some nodes have changed.
+  notifyDirty: function(nodes) {
+    forEach(nodes, method(this.editor, "addDirtyNode"))
+    this.editor.scheduleHighlight();
+  },
+
+  // Link a chain into the DOM nodes (or the first/last links for null
+  // nodes).
+  linkChain: function(chain) {
+    for (var i = 0; i < chain.length; i++) {
+      var line = chain[i];
+      if (line.from) line.from.historyAfter = line;
+      else this.first = line;
+      if (line.to) line.to.historyBefore = line;
+      else this.last = line;
+    }
+  },
+
+  // Get the line object after/before a given node.
+  after: function(node) {
+    return node ? node.historyAfter : this.first;
+  },
+  before: function(node) {
+    return node ? node.historyBefore : this.last;
+  },
+
+  // Mark a node as touched if it has not already been marked.
+  setTouched: function(node) {
+    if (node) {
+      if (!node.historyTouched) {
+        this.touched.push(node);
+        node.historyTouched = true;
+      }
+    }
+    else {
+      this.firstTouched = true;
+    }
+  },
+
+  // Store a new set of undo info, throw away info if there is more of
+  // it than allowed.
+  addUndoLevel: function(diffs) {
+    this.history.push(diffs);
+    if (this.history.length > this.maxDepth)
+      this.history.shift();
+  },
+
+  // Build chains from a set of touched nodes.
+  touchedChains: function() {
+    var self = this;
+    // Compare two strings, treating nbsps as spaces.
+    function compareText(a, b) {
+      return a.replace(/\u00a0/g, " ") == b.replace(/\u00a0/g, " ");
+    }
+
+    // The temp system is a crummy hack to speed up determining
+    // whether a (currently touched) node has a line object associated
+    // with it. nullTemp is used to store the object for the first
+    // line, other nodes get it stored in their historyTemp property.
+    var nullTemp = null;
+    function temp(node) {return node ? node.historyTemp : nullTemp;}
+    function setTemp(node, line) {
+      if (node) node.historyTemp = line;
+      else nullTemp = line;
+    }
+
+    function buildLine(node) {
+      var text = [];
+      for (var cur = node ? node.nextSibling : self.container.firstChild;
+           cur && cur.nodeName != "BR"; cur = cur.nextSibling)
+        if (cur.currentText) text.push(cur.currentText);
+      return {from: node, to: cur, text: text.join("")};
+    }
+
+    // Filter out unchanged lines and nodes that are no longer in the
+    // document. Build up line objects for remaining nodes.
+    var lines = [];
+    if (self.firstTouched) self.touched.push(null);
+    forEach(self.touched, function(node) {
+      if (node && node.parentNode != self.container) return;
+
+      if (node) node.historyTouched = false;
+      else self.firstTouched = false;
+
+      var line = buildLine(node), shadow = self.after(node);
+      if (!shadow || !compareText(shadow.text, line.text) || shadow.to != line.to) {
+        lines.push(line);
+        setTemp(node, line);
+      }
+    });
+
+    // Get the BR element after/before the given node.
+    function nextBR(node, dir) {
+      var link = dir + "Sibling", search = node[link];
+      while (search && search.nodeName != "BR")
+        search = search[link];
+      return search;
+    }
+
+    // Assemble line objects into chains by scanning the DOM tree
+    // around them.
+    var chains = []; self.touched = [];
+    forEach(lines, function(line) {
+      // Note that this makes the loop skip line objects that have
+      // been pulled into chains by lines before them.
+      if (!temp(line.from)) return;
+
+      var chain = [], curNode = line.from, safe = true;
+      // Put any line objects (referred to by temp info) before this
+      // one on the front of the array.
+      while (true) {
+        var curLine = temp(curNode);
+        if (!curLine) {
+          if (safe) break;
+          else curLine = buildLine(curNode);
+        }
+        chain.unshift(curLine);
+        setTemp(curNode, null);
+        if (!curNode) break;
+        safe = self.after(curNode);
+        curNode = nextBR(curNode, "previous");
+      }
+      curNode = line.to; safe = self.before(line.from);
+      // Add lines after this one at end of array.
+      while (true) {
+        if (!curNode) break;
+        var curLine = temp(curNode);
+        if (!curLine) {
+          if (safe) break;
+          else curLine = buildLine(curNode);
+        }
+        chain.push(curLine);
+        setTemp(curNode, null);
+        safe = self.before(curNode);
+        curNode = nextBR(curNode, "next");
+      }
+      chains.push(chain);
+    });
+
+    return chains;
+  },
+
+  // Find the 'shadow' of a given chain by following the links in the
+  // DOM nodes at its start and end.
+  shadowChain: function(chain) {
+    var shadows = [], next = this.after(chain[0].from), end = chain[chain.length - 1].to;
+    while (true) {
+      shadows.push(next);
+      var nextNode = next.to;
+      if (!nextNode || nextNode == end)
+        break;
+      else
+        next = nextNode.historyAfter || this.before(end);
+      // (The this.before(end) is a hack -- FF sometimes removes
+      // properties from BR nodes, in which case the best we can hope
+      // for is to not break.)
+    }
+    return shadows;
+  },
+
+  // Update the DOM tree to contain the lines specified in a given
+  // chain, link this chain into the DOM nodes.
+  applyChain: function(chain) {
+    // Some attempt is made to prevent the cursor from jumping
+    // randomly when an undo or redo happens. It still behaves a bit
+    // strange sometimes.
+    var cursor = select.cursorPos(this.container, false), self = this;
+
+    // Remove all nodes in the DOM tree between from and to (null for
+    // start/end of container).
+    function removeRange(from, to) {
+      var pos = from ? from.nextSibling : self.container.firstChild;
+      while (pos != to) {
+        var temp = pos.nextSibling;
+        removeElement(pos);
+        pos = temp;
+      }
+    }
+
+    var start = chain[0].from, end = chain[chain.length - 1].to;
+    // Clear the space where this change has to be made.
+    removeRange(start, end);
+
+    // Build a function that will insert nodes before the end node of
+    // this chain.
+    var insert = end ?
+      function(node) {self.container.insertBefore(node, end);}
+    : function(node) {self.container.appendChild(node);};
+
+    // Insert the content specified by the chain into the DOM tree.
+    for (var i = 0; i < chain.length; i++) {
+      var line = chain[i];
+      // The start and end of the space are already correct, but BR
+      // tags inside it have to be put back.
+      if (i > 0)
+        insert(line.from);
+      // Add the text.
+      var node = makePartSpan(splitSpaces(line.text), this.container.ownerDocument);
+      insert(node);
+      // See if the cursor was on this line. Put it back, adjusting
+      // for changed line length, if it was.
+      if (cursor && cursor.node == line.from) {
+        var cursordiff = 0;
+        var prev = this.after(line.from);
+        if (prev && i == chain.length - 1) {
+          // Only adjust if the cursor is after the unchanged part of
+          // the line.
+          for (var match = 0; match < cursor.offset &&
+               line.text.charAt(match) == prev.text.charAt(match); match++);
+          if (cursor.offset > match)
+            cursordiff = line.text.length - prev.text.length;
+        }
+        select.setCursorPos(this.container, {node: line.from, offset: Math.max(0, cursor.offset + cursordiff)});
+      }
+      // Cursor was in removed line, this is last new line.
+      else if (cursor && (i == chain.length - 1) && cursor.node && cursor.node.parentNode != this.container) {
+        select.setCursorPos(this.container, {node: line.from, offset: line.text.length});
+      }
+    }
+
+    // Anchor the chain in the DOM tree.
+    this.linkChain(chain);
+    return start;
+  }
+};

Added: lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/util.js
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/util.js?rev=738808&view=auto
==============================================================================
--- lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/util.js (added)
+++ lenya/trunk/src/modules/editors/resources/codemirror/0.60/js/util.js Thu Jan 29 09:49:40 2009
@@ -0,0 +1,123 @@
+/* A few useful utility functions. */
+
+// Capture a method on an object.
+function method(obj, name) {
+  return function() {obj[name].apply(obj, arguments);};
+}
+
+// The value used to signal the end of a sequence in iterators.
+var StopIteration = {toString: function() {return "StopIteration"}};
+
+// Checks whether the argument is an iterator or a regular sequence,
+// turns it into an iterator.
+function iter(seq) {
+  var i = 0;
+  if (seq.next) return seq;
+  else return {
+    next: function() {
+      if (i >= seq.length) throw StopIteration;
+      else return seq[i++];
+    }
+  };
+}
+
+// Apply a function to each element in a sequence.
+function forEach(iter, f) {
+  if (iter.next) {
+    try {while (true) f(iter.next());}
+    catch (e) {if (e != StopIteration) throw e;}
+  }
+  else {
+    for (var i = 0; i < iter.length; i++)
+      f(iter[i]);
+  }
+}
+
+// Map a function over a sequence, producing an array of results.
+function map(iter, f) {
+  var accum = [];
+  forEach(iter, function(val) {accum.push(f(val));});
+  return accum;
+}
+
+// Create a predicate function that tests a string againsts a given
+// regular expression.
+function matcher(regexp){
+  return function(value){return regexp.test(value);};
+}
+
+// Test whether a DOM node has a certain CSS class. Much faster than
+// the MochiKit equivalent, for some reason.
+function hasClass(element, className){
+  var classes = element.className;
+  return classes && new RegExp("(^| )" + className + "($| )").test(classes);
+}
+
+// Insert a DOM node after another node.
+function insertAfter(newNode, oldNode) {
+  var parent = oldNode.parentNode;
+  parent.insertBefore(newNode, oldNode.nextSibling);
+  return newNode;
+}
+
+function removeElement(node) {
+  if (node.parentNode)
+    node.parentNode.removeChild(node);
+}
+
+function clearElement(node) {
+  while (node.firstChild)
+    node.removeChild(node.firstChild);
+}
+
+// Check whether a node is contained in another one.
+function isAncestor(node, child) {
+  while (child = child.parentNode) {
+    if (node == child)
+      return true;
+  }
+  return false;
+}
+
+// The non-breaking space character.
+var nbsp = "\u00a0";
+var matching = {"{": "}", "[": "]", "(": ")",
+                "}": "{", "]": "[", ")": "("};
+
+// Standardize a few unportable event properties.
+function normalizeEvent(event) {
+  if (!event.stopPropagation) {
+    event.stopPropagation = function() {this.cancelBubble = true;};
+    event.preventDefault = function() {this.returnValue = false;};
+  }
+  if (!event.stop) {
+    event.stop = function() {
+      this.stopPropagation();
+      this.preventDefault();
+    };
+  }
+
+  if (event.type == "keypress") {
+    if (event.charCode === 0 || event.charCode == undefined)
+      event.code = event.keyCode;
+    else
+      event.code = event.charCode;
+    event.character = String.fromCharCode(event.code);
+  }
+  return event;
+}
+
+// Portably register event handlers.
+function addEventHandler(node, type, handler, removeFunc) {
+  function wrapHandler(event) {
+    handler(normalizeEvent(event || window.event));
+  }
+  if (typeof node.addEventListener == "function") {
+    node.addEventListener(type, wrapHandler, false);
+    if (removeFunc) return function() {node.removeEventListener(type, wrapHandler, false);};
+  }
+  else {
+    node.attachEvent("on" + type, wrapHandler);
+    if (removeFunc) return function() {node.detachEvent("on" + type, wrapHandler);};
+  }
+}

Added: lenya/trunk/src/modules/editors/resources/codemirror/0.60/jstest.html
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/editors/resources/codemirror/0.60/jstest.html?rev=738808&view=auto
==============================================================================
--- lenya/trunk/src/modules/editors/resources/codemirror/0.60/jstest.html (added)
+++ lenya/trunk/src/modules/editors/resources/codemirror/0.60/jstest.html Thu Jan 29 09:49:40 2009
@@ -0,0 +1,55 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <script src="js/codemirror.js" type="text/javascript"></script>
+    <script src="js/mirrorframe.js" type="text/javascript"></script>
+    <title>CodeMirror: JavaScript demonstration</title>
+    <link rel="stylesheet" type="text/css" href="css/docs.css"/>
+  </head>
+  <body style="padding: 20px;">
+
+<p>This page demonstrates <a href="index.html">CodeMirror</a>'s
+JavaScript parser. Note that the ugly buttons at the top are not are
+not part of CodeMirror proper -- they demonstrate the way it can be
+embedded in a web-application.</p>
+
+<div class="border">
+<textarea id="code" cols="120" rows="30">
+// Here you see some JavaScript code. Mess around with it to get
+// acquainted with CodeMirror's features.
+
+// Press enter inside the object and your new line will be suitably
+// indented.
+var keyBindings = {
+  enter: "newline-and-indent",
+  tab: "reindent-selection",
+  ctrl_enter: "reparse-buffer",
+  ctrl_z: "undo",
+  ctrl_y: "redo",
+  ctrl_backspace: "undo-for-safari-which-stupidly-enough-blocks-ctrl-z"
+};
+
+// Press tab on the next line and the wrong indentation will be fixed.
+      var regex = /foo|bar/i;
+
+function example(x) {
+  // Local variables get a different colour than global ones.
+  var y = 44.4;
+  return x + y - z;
+}
+</textarea>
+</div>
+
+<script type="text/javascript">
+  var textarea = document.getElementById('code');
+  var editor = new MirrorFrame(CodeMirror.replace(textarea), {
+    height: "350px",
+    content: textarea.value,
+    parserfile: ["tokenizejavascript.js", "parsejavascript.js"],
+    stylesheet: "css/jscolors.css",
+    path: "js/",
+    autoMatchParens: true
+  });
+</script>
+
+  </body>
+</html>



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@lenya.apache.org
For additional commands, e-mail: commits-help@lenya.apache.org