1 goog.provide('xrx.richxml.mode');
  2 
  3 
  4 
  5 goog.require('xrx.label');
  6 goog.require('xrx.richxml');
  7 goog.require('xrx.token');
  8 
  9 
 10 
 11 /**
 12  * CodeMirror mode for xrx.richxml.
 13  * @return {!Object}
 14  */
 15 xrx.richxml.mode = CodeMirror.defineMode('richxml', function() {
 16 
 17 
 18 
 19   function nextToken(state, className) {
 20     var previousToken = state.context.token;
 21     var previousLabel = previousToken.label();
 22     var newToken;
 23     var newLabel = previousLabel.clone();
 24     
 25     switch(className) {
 26     case xrx.richxml.className.notTag:
 27       if (previousToken.type() === xrx.token.START_TAG) {
 28         newLabel.push0();
 29       }
 30       newToken = new xrx.token.NotTag(newLabel);
 31       break;
 32     case xrx.richxml.className.startTag:
 33       if (previousToken.type() === xrx.token.START_TAG) {
 34         newLabel.child();
 35       } else {
 36         newLabel.nextSibling();
 37       }
 38       newToken = new xrx.token.StartTag(newLabel);
 39       break;
 40     case xrx.richxml.className.emptyTag:
 41       if (previousToken.type() === xrx.token.START_TAG) {
 42         newLabel.child();
 43       } else {
 44         newLabel.nextSibling();
 45       }
 46       newToken = new xrx.token.EmptyTag(newLabel);
 47       break;
 48     case xrx.richxml.className.endTag:
 49       if (previousToken.type() === xrx.token.START_TAG) {
 50         // do nothing
 51       } else {
 52         newLabel.parent()
 53       }
 54       newToken = new xrx.token.EndTag(newLabel);
 55       break;
 56     default:
 57       throw Error('Unknown token.');
 58       break;
 59     }
 60     return newToken;
 61   }
 62 
 63 
 64 
 65   function changeContext(state, className) {
 66     var token = (!state.context) ? new xrx.token.StartTag(new xrx.label([1])) : 
 67         nextToken(state, className);
 68     var newContext = {
 69       token: token,
 70       prev: state.context,
 71       next: null 
 72     };
 73 
 74     state.context = newContext;
 75   }
 76 
 77 
 78   /**
 79    * Parses the place-holder string.
 80    * @return {!xrx.richxml.className} Class name of the token type.
 81    */
 82   function parse(stream, state) {
 83     var ch = stream.next();
 84 
 85     if (ch === xrx.richxml.placeholder.startTag) {
 86       changeContext(state, xrx.richxml.className.startTag);
 87       return xrx.richxml.className.startTag;
 88     } else if (ch === xrx.richxml.placeholder.endTag) {
 89       changeContext(state, xrx.richxml.className.endTag);
 90       return xrx.richxml.className.endTag;
 91     } else if (ch === xrx.richxml.placeholder.emptyTag) {
 92       changeContext(state, xrx.richxml.className.emptyTag);
 93       return xrx.richxml.className.emptyTag;
 94     } else {
 95       while(true) {
 96         ch = stream.next();
 97         if(!ch) break; 
 98         if(ch === xrx.richxml.placeholder.startTag || ch === xrx.richxml.placeholder.endTag
 99             || ch === xrx.richxml.placeholder.emptyTag) {
100           stream.backUp(1);
101           break;
102         }
103       };
104       changeContext(state, xrx.richxml.className.notTag);
105       return xrx.richxml.className.notTag;
106     }
107   }
108 
109 
110 
111   return {
112     startState: function() {
113       return {
114         tokenize: parse,
115         context: null
116       };
117     },
118     token: function(stream, state) {
119       var style = state.tokenize(stream, state);
120       return style;
121     }
122   };
123 });
124 
125 
126 /**
127  * 
128  */
129 CodeMirror.defineMIME('text/richxml', 'richxml');