added t3editor as system extension
authorIngo Renner <ingo.renner@typo3.org>
Thu, 15 Nov 2007 20:21:41 +0000 (20:21 +0000)
committerIngo Renner <ingo.renner@typo3.org>
Thu, 15 Nov 2007 20:21:41 +0000 (20:21 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@2723 709f56b5-9817-0410-a4d7-c38de5d9e867

12 files changed:
typo3/sysext/t3editor/css/t3editor.css [new file with mode: 0755]
typo3/sysext/t3editor/icons/loader_eeeeee.gif [new file with mode: 0644]
typo3/sysext/t3editor/jslib/LICENSE [new file with mode: 0755]
typo3/sysext/t3editor/jslib/Mochi.js [new file with mode: 0644]
typo3/sysext/t3editor/jslib/parsejavascript.js [new file with mode: 0644]
typo3/sysext/t3editor/jslib/parsetyposcript.js [new file with mode: 0755]
typo3/sysext/t3editor/jslib/select.js [new file with mode: 0755]
typo3/sysext/t3editor/jslib/stringstream.js [new file with mode: 0644]
typo3/sysext/t3editor/jslib/t3editor.js [new file with mode: 0755]
typo3/sysext/t3editor/jslib/tokenizejavascript.js [new file with mode: 0644]
typo3/sysext/t3editor/jslib/tokenizetyposcript.js [new file with mode: 0755]
typo3/sysext/t3editor/jslib/util.js [new file with mode: 0644]

diff --git a/typo3/sysext/t3editor/css/t3editor.css b/typo3/sysext/t3editor/css/t3editor.css
new file mode 100755 (executable)
index 0000000..4c83930
--- /dev/null
@@ -0,0 +1,241 @@
+
+.editbox {
+  border-width: 0;
+  margin: .0em;
+  padding: 0;
+  font-family: monospace;
+  font-size: 12px;
+  color: black;
+  background-color: #fff;
+}
+
+.editbox p {
+  margin: 0;
+}
+
+
+/* Syntax highlighting */
+
+span.part {
+       color: #666;
+}
+
+span.other {
+       color: black;
+}
+
+span.reserved, .t3e_autoCompleteBox ul li span.word_reserved {
+  color: #770088;
+}
+
+span.keyword, .t3e_autoCompleteBox ul li span.word_keyword {
+       color: #0000cc;
+       font-weight: bold;
+       font-size: 0.95em;
+}
+
+span.keyword2, .t3e_autoCompleteBox ul li span.word_keyword2 {
+       color: #0000cc;
+}
+
+span.keyword3, .t3e_autoCompleteBox ul li span.word_keyword3 {
+       color: #0000ff;
+}
+
+
+span.prop {
+       color: #00f;
+}
+
+span.operator {
+       color: #f00;
+}
+span.punctuation {
+       color: #c00;
+}
+
+span.atom {
+  color: #448888;
+}
+
+span.variable {
+  color: black;
+}
+
+/*
+span.variabledef {
+  color: #0000FF;
+}
+
+span.localvariable {
+  color: #004499;
+}
+
+span.property {
+  color: black;
+}
+*/
+
+span.comment {
+  color: #AA7700;
+}
+
+span.string {
+  color: #AA2222;
+}
+
+/* unparsed code */
+pre.code, .editbox {
+  color: #666;
+}
+
+
+/* around the editor */
+.t3e_outerdiv {
+       border: 1px solid gray;
+       position: relative;
+    background-color: #EFEFF4;
+       background-image: url('../icons/loader_eeeeee.gif');
+       background-position: 49% 50%;
+       background-repeat: no-repeat;
+}
+.t3e_modalOverlay {
+       position: absolute;
+       top: 0; left: 0;
+    background-color: #EFEFF4;
+       background-image: url('../icons/loader_eeeeee.gif');
+       background-position: 49% 50%;
+       background-repeat: no-repeat;
+       z-index:200;
+       width: 100%;
+       height: 100%;
+}
+.t3e_autoCompleteBox {
+       position: absolute;
+       top: 0; left: 0;
+    background-color: #EFEFF4;
+       z-index:190;    
+       border:2px solid silver;
+       padding:0px;
+}
+.t3e_autoCompleteBox ul{
+       list-style-type: none;
+       padding:0px;
+       margin:0px;
+       
+}
+.t3e_autoCompleteBox ul li{
+       padding-left:2px;
+       padding-right:2px;
+       font-weight:bold;
+       cursor: pointer; cursor: hand;
+}
+.t3e_autoCompleteBox ul li.active{
+       padding-left:2px;
+       padding-right:2px;
+       font-weight:bold;
+       background-color: #cfcfcf;
+}
+.t3e_fullscreen {
+       position: absolute;
+       top: 0;
+       left: 0;
+}
+.t3e_linenum_wrap {
+       width: 4em; 
+       position: absolute; top: 0pt; left: 0pt;
+       overflow: hidden;
+}
+.t3e_linenum {
+       font-size: 12px; 
+    font-family: monospace;
+       padding: 0 3px 0 0;
+       margin: 0;
+    background-color: #EFEFF4;
+       color: #000;
+       width: 3em;
+       float: left;
+       text-align: right;
+       list-style-type: none;
+}
+
+.t3e_linenum li {
+       padding: 0 3px 0 0;
+       margin: 0;
+}
+
+.t3e_iframe_wrap {
+       margin: 0 0 0 4em;
+}
+
+.t3e_iframe {
+       display: block; 
+       /* width: 100%; */
+       padding: 0;
+}
+
+.t3e_footer_wrap {
+       clear: both;
+       width: 100%;
+       font-size: 0.9em;
+       padding-right: 20px;
+}
+
+.t3e_footer_item {
+       float: right;
+       height: 16px;
+       border-left: 1px solid gray;
+       padding: 4px 14px 0 14px;
+}
+
+
+.t3e_clickable {
+  cursor:pointer;cursor:hand;
+}
+
+
+.t3e_footer_overlay {
+       position: absolute; bottom: 20px; right: 17px; 
+       opacity: 0.85;
+       background-color: #EFEFF4;
+       width: 180px; 
+       height: 70%;
+       padding: 5px 0px 10px 0px;
+       border-left: 1px solid gray;
+       border-right: 1px solid gray;
+       border-top: 1px solid gray;
+       z-index: 100;
+}
+.t3e_footer_overlay#t3e_footer_overlay_options {
+       height: 8em;
+}
+.t3e_footer_overlay ul {
+       list-style-type: none;
+       padding: 0;
+       margin: 0;
+}
+.t3e_footer_overlay ul li {
+       color: #212121;
+       padding: 2px 6px 2px 6px;
+       cursor:pointer;cursor:hand;
+}
+.t3e_footer_overlay ul li label {
+       cursor:pointer;cursor:hand;
+       }
+.t3e_footer_overlay ul li:hover {
+       background-color: #cfcfcf;
+}
+
+#t3e_modalOverlay_help {
+       background-image: none;
+       width: 90%;
+       height: 80%;
+       top: 10%;
+       left: 5%;
+       padding: 10px;
+       border: 1px solid gray;
+}
+
+.t3e_footeritem_active {
+       background-color: #cfcfcf;
+}
\ No newline at end of file
diff --git a/typo3/sysext/t3editor/icons/loader_eeeeee.gif b/typo3/sysext/t3editor/icons/loader_eeeeee.gif
new file mode 100644 (file)
index 0000000..d6c3a70
Binary files /dev/null and b/typo3/sysext/t3editor/icons/loader_eeeeee.gif differ
diff --git a/typo3/sysext/t3editor/jslib/LICENSE b/typo3/sysext/t3editor/jslib/LICENSE
new file mode 100755 (executable)
index 0000000..829ac27
--- /dev/null
@@ -0,0 +1,68 @@
+
+Licence of t3editor
+===================
+
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2007 Tobias Liebig <mail_typo3@etobi.de>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+t3editor is written by Tobias Liebig.
+
+Many thanks for help on the conceptual work, testing, feedback and providing several patches 
+to Vitaly Dutchak, Thomas Hempel and all the other people.
+
+t3editor is based on Codemirror by Marijn Haverbeke http://marijn.haverbeke.de/codemirror/
+Thanks Marjin! 
+Codemirror uses MochiKit. See http://mochikit.com/ for licence.
+
+
+This is the original licence: 
+/***************************************************************
+ Copyright (c) 2007 Marijn Haverbeke
+
+ 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.
+
+ Marijn Haverbeke
+ marijnh at gmail
+***************************************************************/
+
diff --git a/typo3/sysext/t3editor/jslib/Mochi.js b/typo3/sysext/t3editor/jslib/Mochi.js
new file mode 100644 (file)
index 0000000..33e7c2a
--- /dev/null
@@ -0,0 +1,3808 @@
+/***
+
+    MochiKit.MochiKit 1.4 : PACKED VERSION
+
+    THIS FILE IS AUTOMATICALLY GENERATED.  If creating patches, please
+    diff against the source tree, not this file.
+
+    See <http://mochikit.com/> for documentation, downloads, license, etc.
+
+    (c) 2005 Bob Ippolito.  All rights Reserved.
+
+***/
+
+if(typeof (dojo)!="undefined"){
+dojo.provide("MochiKit.Base");
+}
+if(typeof (MochiKit)=="undefined"){
+MochiKit={};
+}
+if(typeof (MochiKit.Base)=="undefined"){
+MochiKit.Base={};
+}
+if(typeof (MochiKit.__export__)=="undefined"){
+MochiKit.__export__=(MochiKit.__compat__||(typeof (JSAN)=="undefined"&&typeof (dojo)=="undefined"));
+}
+MochiKit.Base.VERSION="1.4";
+MochiKit.Base.NAME="MochiKit.Base";
+MochiKit.Base.update=function(_1,_2){
+if(_1===null){
+_1={};
+}
+for(var i=1;i<arguments.length;i++){
+var o=arguments[i];
+if(typeof (o)!="undefined"&&o!==null){
+for(var k in o){
+_1[k]=o[k];
+}
+}
+}
+return _1;
+};
+MochiKit.Base.update(MochiKit.Base,{__repr__:function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+},toString:function(){
+return this.__repr__();
+},camelize:function(_6){
+var _7=_6.split("-");
+var cc=_7[0];
+for(var i=1;i<_7.length;i++){
+cc+=_7[i].charAt(0).toUpperCase()+_7[i].substring(1);
+}
+return cc;
+},counter:function(n){
+if(arguments.length===0){
+n=1;
+}
+return function(){
+return n++;
+};
+},clone:function(_b){
+var me=arguments.callee;
+if(arguments.length==1){
+me.prototype=_b;
+return new me();
+}
+},_flattenArray:function(_d,_e){
+for(var i=0;i<_e.length;i++){
+var o=_e[i];
+if(o instanceof Array){
+arguments.callee(_d,o);
+}else{
+_d.push(o);
+}
+}
+return _d;
+},flattenArray:function(lst){
+return MochiKit.Base._flattenArray([],lst);
+},flattenArguments:function(lst){
+var res=[];
+var m=MochiKit.Base;
+var _15=m.extend(null,arguments);
+while(_15.length){
+var o=_15.shift();
+if(o&&typeof (o)=="object"&&typeof (o.length)=="number"){
+for(var i=o.length-1;i>=0;i--){
+_15.unshift(o[i]);
+}
+}else{
+res.push(o);
+}
+}
+return res;
+},extend:function(_18,obj,_1a){
+if(!_1a){
+_1a=0;
+}
+if(obj){
+var l=obj.length;
+if(typeof (l)!="number"){
+if(typeof (MochiKit.Iter)!="undefined"){
+obj=MochiKit.Iter.list(obj);
+l=obj.length;
+}else{
+throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
+}
+}
+if(!_18){
+_18=[];
+}
+for(var i=_1a;i<l;i++){
+_18.push(obj[i]);
+}
+}
+return _18;
+},updatetree:function(_1d,obj){
+if(_1d===null){
+_1d={};
+}
+for(var i=1;i<arguments.length;i++){
+var o=arguments[i];
+if(typeof (o)!="undefined"&&o!==null){
+for(var k in o){
+var v=o[k];
+if(typeof (_1d[k])=="object"&&typeof (v)=="object"){
+arguments.callee(_1d[k],v);
+}else{
+_1d[k]=v;
+}
+}
+}
+}
+return _1d;
+},setdefault:function(_23,obj){
+if(_23===null){
+_23={};
+}
+for(var i=1;i<arguments.length;i++){
+var o=arguments[i];
+for(var k in o){
+if(!(k in _23)){
+_23[k]=o[k];
+}
+}
+}
+return _23;
+},keys:function(obj){
+var _29=[];
+for(var _2a in obj){
+_29.push(_2a);
+}
+return _29;
+},values:function(obj){
+var _2c=[];
+for(var _2d in obj){
+_2c.push(obj[_2d]);
+}
+return _2c;
+},items:function(obj){
+var _2f=[];
+var e;
+for(var _31 in obj){
+var v;
+try{
+v=obj[_31];
+}
+catch(e){
+continue;
+}
+_2f.push([_31,v]);
+}
+return _2f;
+},_newNamedError:function(_33,_34,_35){
+_35.prototype=new MochiKit.Base.NamedError(_33.NAME+"."+_34);
+_33[_34]=_35;
+},operator:{truth:function(a){
+return !!a;
+},lognot:function(a){
+return !a;
+},identity:function(a){
+return a;
+},not:function(a){
+return ~a;
+},neg:function(a){
+return -a;
+},add:function(a,b){
+return a+b;
+},sub:function(a,b){
+return a-b;
+},div:function(a,b){
+return a/b;
+},mod:function(a,b){
+return a%b;
+},mul:function(a,b){
+return a*b;
+},and:function(a,b){
+return a&b;
+},or:function(a,b){
+return a|b;
+},xor:function(a,b){
+return a^b;
+},lshift:function(a,b){
+return a<<b;
+},rshift:function(a,b){
+return a>>b;
+},zrshift:function(a,b){
+return a>>>b;
+},eq:function(a,b){
+return a==b;
+},ne:function(a,b){
+return a!=b;
+},gt:function(a,b){
+return a>b;
+},ge:function(a,b){
+return a>=b;
+},lt:function(a,b){
+return a<b;
+},le:function(a,b){
+return a<=b;
+},seq:function(a,b){
+return a===b;
+},sne:function(a,b){
+return a!==b;
+},ceq:function(a,b){
+return MochiKit.Base.compare(a,b)===0;
+},cne:function(a,b){
+return MochiKit.Base.compare(a,b)!==0;
+},cgt:function(a,b){
+return MochiKit.Base.compare(a,b)==1;
+},cge:function(a,b){
+return MochiKit.Base.compare(a,b)!=-1;
+},clt:function(a,b){
+return MochiKit.Base.compare(a,b)==-1;
+},cle:function(a,b){
+return MochiKit.Base.compare(a,b)!=1;
+},logand:function(a,b){
+return a&&b;
+},logor:function(a,b){
+return a||b;
+},contains:function(a,b){
+return b in a;
+}},forwardCall:function(_73){
+return function(){
+return this[_73].apply(this,arguments);
+};
+},itemgetter:function(_74){
+return function(arg){
+return arg[_74];
+};
+},typeMatcher:function(){
+var _76={};
+for(var i=0;i<arguments.length;i++){
+var typ=arguments[i];
+_76[typ]=typ;
+}
+return function(){
+for(var i=0;i<arguments.length;i++){
+if(!(typeof (arguments[i]) in _76)){
+return false;
+}
+}
+return true;
+};
+},isNull:function(){
+for(var i=0;i<arguments.length;i++){
+if(arguments[i]!==null){
+return false;
+}
+}
+return true;
+},isUndefinedOrNull:function(){
+for(var i=0;i<arguments.length;i++){
+var o=arguments[i];
+if(!(typeof (o)=="undefined"||o===null)){
+return false;
+}
+}
+return true;
+},isEmpty:function(obj){
+return !MochiKit.Base.isNotEmpty.apply(this,arguments);
+},isNotEmpty:function(obj){
+for(var i=0;i<arguments.length;i++){
+var o=arguments[i];
+if(!(o&&o.length)){
+return false;
+}
+}
+return true;
+},isArrayLike:function(){
+for(var i=0;i<arguments.length;i++){
+var o=arguments[i];
+var typ=typeof (o);
+if((typ!="object"&&!(typ=="function"&&typeof (o.item)=="function"))||o===null||typeof (o.length)!="number"||o.nodeType===3){
+return false;
+}
+}
+return true;
+},isDateLike:function(){
+for(var i=0;i<arguments.length;i++){
+var o=arguments[i];
+if(typeof (o)!="object"||o===null||typeof (o.getTime)!="function"){
+return false;
+}
+}
+return true;
+},xmap:function(fn){
+if(fn===null){
+return MochiKit.Base.extend(null,arguments,1);
+}
+var _87=[];
+for(var i=1;i<arguments.length;i++){
+_87.push(fn(arguments[i]));
+}
+return _87;
+},map:function(fn,lst){
+var m=MochiKit.Base;
+var itr=MochiKit.Iter;
+var _8d=m.isArrayLike;
+if(arguments.length<=2){
+if(!_8d(lst)){
+if(itr){
+lst=itr.list(lst);
+if(fn===null){
+return lst;
+}
+}else{
+throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
+}
+}
+if(fn===null){
+return m.extend(null,lst);
+}
+var _8e=[];
+for(var i=0;i<lst.length;i++){
+_8e.push(fn(lst[i]));
+}
+return _8e;
+}else{
+if(fn===null){
+fn=Array;
+}
+var _90=null;
+for(i=1;i<arguments.length;i++){
+if(!_8d(arguments[i])){
+if(itr){
+return itr.list(itr.imap.apply(null,arguments));
+}else{
+throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
+}
+}
+var l=arguments[i].length;
+if(_90===null||_90>l){
+_90=l;
+}
+}
+_8e=[];
+for(i=0;i<_90;i++){
+var _92=[];
+for(var j=1;j<arguments.length;j++){
+_92.push(arguments[j][i]);
+}
+_8e.push(fn.apply(this,_92));
+}
+return _8e;
+}
+},xfilter:function(fn){
+var _95=[];
+if(fn===null){
+fn=MochiKit.Base.operator.truth;
+}
+for(var i=1;i<arguments.length;i++){
+var o=arguments[i];
+if(fn(o)){
+_95.push(o);
+}
+}
+return _95;
+},filter:function(fn,lst,_9a){
+var _9b=[];
+var m=MochiKit.Base;
+if(!m.isArrayLike(lst)){
+if(MochiKit.Iter){
+lst=MochiKit.Iter.list(lst);
+}else{
+throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
+}
+}
+if(fn===null){
+fn=m.operator.truth;
+}
+if(typeof (Array.prototype.filter)=="function"){
+return Array.prototype.filter.call(lst,fn,_9a);
+}else{
+if(typeof (_9a)=="undefined"||_9a===null){
+for(var i=0;i<lst.length;i++){
+var o=lst[i];
+if(fn(o)){
+_9b.push(o);
+}
+}
+}else{
+for(i=0;i<lst.length;i++){
+o=lst[i];
+if(fn.call(_9a,o)){
+_9b.push(o);
+}
+}
+}
+}
+return _9b;
+},_wrapDumbFunction:function(_9f){
+return function(){
+switch(arguments.length){
+case 0:
+return _9f();
+case 1:
+return _9f(arguments[0]);
+case 2:
+return _9f(arguments[0],arguments[1]);
+case 3:
+return _9f(arguments[0],arguments[1],arguments[2]);
+}
+var _a0=[];
+for(var i=0;i<arguments.length;i++){
+_a0.push("arguments["+i+"]");
+}
+return eval("(func("+_a0.join(",")+"))");
+};
+},methodcaller:function(_a2){
+var _a3=MochiKit.Base.extend(null,arguments,1);
+if(typeof (_a2)=="function"){
+return function(obj){
+return _a2.apply(obj,_a3);
+};
+}else{
+return function(obj){
+return obj[_a2].apply(obj,_a3);
+};
+}
+},method:function(_a6,_a7){
+var m=MochiKit.Base;
+return m.bind.apply(this,m.extend([_a7,_a6],arguments,2));
+},compose:function(f1,f2){
+var _ab=[];
+var m=MochiKit.Base;
+if(arguments.length===0){
+throw new TypeError("compose() requires at least one argument");
+}
+for(var i=0;i<arguments.length;i++){
+var fn=arguments[i];
+if(typeof (fn)!="function"){
+throw new TypeError(m.repr(fn)+" is not a function");
+}
+_ab.push(fn);
+}
+return function(){
+var _af=arguments;
+for(var i=_ab.length-1;i>=0;i--){
+_af=[_ab[i].apply(this,_af)];
+}
+return _af[0];
+};
+},bind:function(_b1,_b2){
+if(typeof (_b1)=="string"){
+_b1=_b2[_b1];
+}
+var _b3=_b1.im_func;
+var _b4=_b1.im_preargs;
+var _b5=_b1.im_self;
+var m=MochiKit.Base;
+if(typeof (_b1)=="function"&&typeof (_b1.apply)=="undefined"){
+_b1=m._wrapDumbFunction(_b1);
+}
+if(typeof (_b3)!="function"){
+_b3=_b1;
+}
+if(typeof (_b2)!="undefined"){
+_b5=_b2;
+}
+if(typeof (_b4)=="undefined"){
+_b4=[];
+}else{
+_b4=_b4.slice();
+}
+m.extend(_b4,arguments,2);
+var _b7=function(){
+var _b8=arguments;
+var me=arguments.callee;
+if(me.im_preargs.length>0){
+_b8=m.concat(me.im_preargs,_b8);
+}
+var _ba=me.im_self;
+if(!_ba){
+_ba=this;
+}
+return me.im_func.apply(_ba,_b8);
+};
+_b7.im_self=_b5;
+_b7.im_func=_b3;
+_b7.im_preargs=_b4;
+return _b7;
+},bindMethods:function(_bb){
+var _bc=MochiKit.Base.bind;
+for(var k in _bb){
+var _be=_bb[k];
+if(typeof (_be)=="function"){
+_bb[k]=_bc(_be,_bb);
+}
+}
+},registerComparator:function(_bf,_c0,_c1,_c2){
+MochiKit.Base.comparatorRegistry.register(_bf,_c0,_c1,_c2);
+},_primitives:{"boolean":true,"string":true,"number":true},compare:function(a,b){
+if(a==b){
+return 0;
+}
+var _c5=(typeof (a)=="undefined"||a===null);
+var _c6=(typeof (b)=="undefined"||b===null);
+if(_c5&&_c6){
+return 0;
+}else{
+if(_c5){
+return -1;
+}else{
+if(_c6){
+return 1;
+}
+}
+}
+var m=MochiKit.Base;
+var _c8=m._primitives;
+if(!(typeof (a) in _c8&&typeof (b) in _c8)){
+try{
+return m.comparatorRegistry.match(a,b);
+}
+catch(e){
+if(e!=m.NotFound){
+throw e;
+}
+}
+}
+if(a<b){
+return -1;
+}else{
+if(a>b){
+return 1;
+}
+}
+var _c9=m.repr;
+throw new TypeError(_c9(a)+" and "+_c9(b)+" can not be compared");
+},compareDateLike:function(a,b){
+return MochiKit.Base.compare(a.getTime(),b.getTime());
+},compareArrayLike:function(a,b){
+var _ce=MochiKit.Base.compare;
+var _cf=a.length;
+var _d0=0;
+if(_cf>b.length){
+_d0=1;
+_cf=b.length;
+}else{
+if(_cf<b.length){
+_d0=-1;
+}
+}
+for(var i=0;i<_cf;i++){
+var cmp=_ce(a[i],b[i]);
+if(cmp){
+return cmp;
+}
+}
+return _d0;
+},registerRepr:function(_d3,_d4,_d5,_d6){
+MochiKit.Base.reprRegistry.register(_d3,_d4,_d5,_d6);
+},repr:function(o){
+if(typeof (o)=="undefined"){
+return "undefined";
+}else{
+if(o===null){
+return "null";
+}
+}
+try{
+if(typeof (o.__repr__)=="function"){
+return o.__repr__();
+}else{
+if(typeof (o.repr)=="function"&&o.repr!=arguments.callee){
+return o.repr();
+}
+}
+return MochiKit.Base.reprRegistry.match(o);
+}
+catch(e){
+if(typeof (o.NAME)=="string"&&(o.toString==Function.prototype.toString||o.toString==Object.prototype.toString)){
+return o.NAME;
+}
+}
+try{
+var _d8=(o+"");
+}
+catch(e){
+return "["+typeof (o)+"]";
+}
+if(typeof (o)=="function"){
+o=_d8.replace(/^\s+/,"");
+var idx=o.indexOf("{");
+if(idx!=-1){
+o=o.substr(0,idx)+"{...}";
+}
+}
+return _d8;
+},reprArrayLike:function(o){
+var m=MochiKit.Base;
+return "["+m.map(m.repr,o).join(", ")+"]";
+},reprString:function(o){
+return ("\""+o.replace(/(["\\])/g,"\\$1")+"\"").replace(/[\f]/g,"\\f").replace(/[\b]/g,"\\b").replace(/[\n]/g,"\\n").replace(/[\t]/g,"\\t").replace(/[\r]/g,"\\r");
+},reprNumber:function(o){
+return o+"";
+},registerJSON:function(_de,_df,_e0,_e1){
+MochiKit.Base.jsonRegistry.register(_de,_df,_e0,_e1);
+},evalJSON:function(){
+return eval("("+MochiKit.Base._filterJSON(arguments[0])+")");
+},_filterJSON:function(s){
+var m=s.match(/^\s*\/\*(.*)\*\/\s*$/);
+if(m){
+return m[1];
+}
+return s;
+},serializeJSON:function(o){
+var _e5=typeof (o);
+if(_e5=="number"||_e5=="boolean"){
+return o+"";
+}else{
+if(o===null){
+return "null";
+}
+}
+var m=MochiKit.Base;
+var _e7=m.reprString;
+if(_e5=="string"){
+return _e7(o);
+}
+var me=arguments.callee;
+var _e9;
+if(typeof (o.__json__)=="function"){
+_e9=o.__json__();
+if(o!==_e9){
+return me(_e9);
+}
+}
+if(typeof (o.json)=="function"){
+_e9=o.json();
+if(o!==_e9){
+return me(_e9);
+}
+}
+if(_e5!="function"&&typeof (o.length)=="number"){
+var res=[];
+for(var i=0;i<o.length;i++){
+var val=me(o[i]);
+if(typeof (val)!="string"){
+val="undefined";
+}
+res.push(val);
+}
+return "["+res.join(", ")+"]";
+}
+try{
+_e9=m.jsonRegistry.match(o);
+if(o!==_e9){
+return me(_e9);
+}
+}
+catch(e){
+if(e!=m.NotFound){
+throw e;
+}
+}
+if(_e5=="undefined"){
+throw new TypeError("undefined can not be serialized as JSON");
+}
+if(_e5=="function"){
+return null;
+}
+res=[];
+for(var k in o){
+var _ee;
+if(typeof (k)=="number"){
+_ee="\""+k+"\"";
+}else{
+if(typeof (k)=="string"){
+_ee=_e7(k);
+}else{
+continue;
+}
+}
+val=me(o[k]);
+if(typeof (val)!="string"){
+continue;
+}
+res.push(_ee+":"+val);
+}
+return "{"+res.join(", ")+"}";
+},objEqual:function(a,b){
+return (MochiKit.Base.compare(a,b)===0);
+},arrayEqual:function(_f1,arr){
+if(_f1.length!=arr.length){
+return false;
+}
+return (MochiKit.Base.compare(_f1,arr)===0);
+},concat:function(){
+var _f3=[];
+var _f4=MochiKit.Base.extend;
+for(var i=0;i<arguments.length;i++){
+_f4(_f3,arguments[i]);
+}
+return _f3;
+},keyComparator:function(key){
+var m=MochiKit.Base;
+var _f8=m.compare;
+if(arguments.length==1){
+return function(a,b){
+return _f8(a[key],b[key]);
+};
+}
+var _fb=m.extend(null,arguments);
+return function(a,b){
+var _fe=0;
+for(var i=0;(_fe===0)&&(i<_fb.length);i++){
+var key=_fb[i];
+_fe=_f8(a[key],b[key]);
+}
+return _fe;
+};
+},reverseKeyComparator:function(key){
+var _102=MochiKit.Base.keyComparator.apply(this,arguments);
+return function(a,b){
+return _102(b,a);
+};
+},partial:function(func){
+var m=MochiKit.Base;
+return m.bind.apply(this,m.extend([func,undefined],arguments,1));
+},listMinMax:function(_107,lst){
+if(lst.length===0){
+return null;
+}
+var cur=lst[0];
+var _10a=MochiKit.Base.compare;
+for(var i=1;i<lst.length;i++){
+var o=lst[i];
+if(_10a(o,cur)==_107){
+cur=o;
+}
+}
+return cur;
+},objMax:function(){
+return MochiKit.Base.listMinMax(1,arguments);
+},objMin:function(){
+return MochiKit.Base.listMinMax(-1,arguments);
+},findIdentical:function(lst,_10e,_10f,end){
+if(typeof (end)=="undefined"||end===null){
+end=lst.length;
+}
+if(typeof (_10f)=="undefined"||_10f===null){
+_10f=0;
+}
+for(var i=_10f;i<end;i++){
+if(lst[i]===_10e){
+return i;
+}
+}
+return -1;
+},mean:function(){
+var sum=0;
+var m=MochiKit.Base;
+var args=m.extend(null,arguments);
+var _115=args.length;
+while(args.length){
+var o=args.shift();
+if(o&&typeof (o)=="object"&&typeof (o.length)=="number"){
+_115+=o.length-1;
+for(var i=o.length-1;i>=0;i--){
+sum+=o[i];
+}
+}else{
+sum+=o;
+}
+}
+if(_115<=0){
+throw new TypeError("mean() requires at least one argument");
+}
+return sum/_115;
+},median:function(){
+var data=MochiKit.Base.flattenArguments(arguments);
+if(data.length===0){
+throw new TypeError("median() requires at least one argument");
+}
+data.sort(compare);
+if(data.length%2==0){
+var _119=data.length/2;
+return (data[_119]+data[_119-1])/2;
+}else{
+return data[(data.length-1)/2];
+}
+},findValue:function(lst,_11b,_11c,end){
+if(typeof (end)=="undefined"||end===null){
+end=lst.length;
+}
+if(typeof (_11c)=="undefined"||_11c===null){
+_11c=0;
+}
+var cmp=MochiKit.Base.compare;
+for(var i=_11c;i<end;i++){
+if(cmp(lst[i],_11b)===0){
+return i;
+}
+}
+return -1;
+},nodeWalk:function(node,_121){
+var _122=[node];
+var _123=MochiKit.Base.extend;
+while(_122.length){
+var res=_121(_122.shift());
+if(res){
+_123(_122,res);
+}
+}
+},nameFunctions:function(_125){
+var base=_125.NAME;
+if(typeof (base)=="undefined"){
+base="";
+}else{
+base=base+".";
+}
+for(var name in _125){
+var o=_125[name];
+if(typeof (o)=="function"&&typeof (o.NAME)=="undefined"){
+try{
+o.NAME=base+name;
+}
+catch(e){
+}
+}
+}
+},queryString:function(_129,_12a){
+if(typeof (MochiKit.DOM)!="undefined"&&arguments.length==1&&(typeof (_129)=="string"||(typeof (_129.nodeType)!="undefined"&&_129.nodeType>0))){
+var kv=MochiKit.DOM.formContents(_129);
+_129=kv[0];
+_12a=kv[1];
+}else{
+if(arguments.length==1){
+if(typeof (_129.length)=="number"&&_129.length==2){
+return arguments.callee(_129[0],_129[1]);
+}
+var o=_129;
+_129=[];
+_12a=[];
+for(var k in o){
+var v=o[k];
+if(typeof (v)=="function"){
+continue;
+}else{
+if(typeof (v)!="string"&&typeof (v.length)=="number"){
+for(var i=0;i<v.length;i++){
+_129.push(k);
+_12a.push(v[i]);
+}
+}else{
+_129.push(k);
+_12a.push(v);
+}
+}
+}
+}
+}
+var rval=[];
+var len=Math.min(_129.length,_12a.length);
+var _132=MochiKit.Base.urlEncode;
+for(var i=0;i<len;i++){
+v=_12a[i];
+if(typeof (v)!="undefined"&&v!==null){
+rval.push(_132(_129[i])+"="+_132(v));
+}
+}
+return rval.join("&");
+},parseQueryString:function(_133,_134){
+var qstr=(_133.charAt(0)=="?")?_133.substring(1):_133;
+var _136=qstr.replace(/\+/g,"%20").split(/(\&amp\;|\&\#38\;|\&#x26;|\&)/);
+var o={};
+var _138;
+if(typeof (decodeURIComponent)!="undefined"){
+_138=decodeURIComponent;
+}else{
+_138=unescape;
+}
+if(_134){
+for(var i=0;i<_136.length;i++){
+var pair=_136[i].split("=");
+var name=_138(pair.shift());
+if(!name){
+continue;
+}
+var arr=o[name];
+if(!(arr instanceof Array)){
+arr=[];
+o[name]=arr;
+}
+arr.push(_138(pair.join("=")));
+}
+}else{
+for(i=0;i<_136.length;i++){
+pair=_136[i].split("=");
+var name=pair.shift();
+if(!name){
+continue;
+}
+o[_138(name)]=_138(pair.join("="));
+}
+}
+return o;
+}});
+MochiKit.Base.AdapterRegistry=function(){
+this.pairs=[];
+};
+MochiKit.Base.AdapterRegistry.prototype={register:function(name,_13e,wrap,_140){
+if(_140){
+this.pairs.unshift([name,_13e,wrap]);
+}else{
+this.pairs.push([name,_13e,wrap]);
+}
+},match:function(){
+for(var i=0;i<this.pairs.length;i++){
+var pair=this.pairs[i];
+if(pair[1].apply(this,arguments)){
+return pair[2].apply(this,arguments);
+}
+}
+throw MochiKit.Base.NotFound;
+},unregister:function(name){
+for(var i=0;i<this.pairs.length;i++){
+var pair=this.pairs[i];
+if(pair[0]==name){
+this.pairs.splice(i,1);
+return true;
+}
+}
+return false;
+}};
+MochiKit.Base.EXPORT=["flattenArray","noop","camelize","counter","clone","extend","update","updatetree","setdefault","keys","values","items","NamedError","operator","forwardCall","itemgetter","typeMatcher","isCallable","isUndefined","isUndefinedOrNull","isNull","isEmpty","isNotEmpty","isArrayLike","isDateLike","xmap","map","xfilter","filter","methodcaller","compose","bind","bindMethods","NotFound","AdapterRegistry","registerComparator","compare","registerRepr","repr","objEqual","arrayEqual","concat","keyComparator","reverseKeyComparator","partial","merge","listMinMax","listMax","listMin","objMax","objMin","nodeWalk","zip","urlEncode","queryString","serializeJSON","registerJSON","evalJSON","parseQueryString","findValue","findIdentical","flattenArguments","method","average","mean","median"];
+MochiKit.Base.EXPORT_OK=["nameFunctions","comparatorRegistry","reprRegistry","jsonRegistry","compareDateLike","compareArrayLike","reprArrayLike","reprString","reprNumber"];
+MochiKit.Base._exportSymbols=function(_146,_147){
+if(!MochiKit.__export__){
+return;
+}
+var all=_147.EXPORT_TAGS[":all"];
+for(var i=0;i<all.length;i++){
+_146[all[i]]=_147[all[i]];
+}
+};
+MochiKit.Base.__new__=function(){
+var m=this;
+m.noop=m.operator.identity;
+m.forward=m.forwardCall;
+m.find=m.findValue;
+if(typeof (encodeURIComponent)!="undefined"){
+m.urlEncode=function(_14b){
+return encodeURIComponent(_14b).replace(/\'/g,"%27");
+};
+}else{
+m.urlEncode=function(_14c){
+return escape(_14c).replace(/\+/g,"%2B").replace(/\"/g,"%22").rval.replace(/\'/g,"%27");
+};
+}
+m.NamedError=function(name){
+this.message=name;
+this.name=name;
+};
+m.NamedError.prototype=new Error();
+m.update(m.NamedError.prototype,{repr:function(){
+if(this.message&&this.message!=this.name){
+return this.name+"("+m.repr(this.message)+")";
+}else{
+return this.name+"()";
+}
+},toString:m.forwardCall("repr")});
+m.NotFound=new m.NamedError("MochiKit.Base.NotFound");
+m.listMax=m.partial(m.listMinMax,1);
+m.listMin=m.partial(m.listMinMax,-1);
+m.isCallable=m.typeMatcher("function");
+m.isUndefined=m.typeMatcher("undefined");
+m.merge=m.partial(m.update,null);
+m.zip=m.partial(m.map,null);
+m.average=m.mean;
+m.comparatorRegistry=new m.AdapterRegistry();
+m.registerComparator("dateLike",m.isDateLike,m.compareDateLike);
+m.registerComparator("arrayLike",m.isArrayLike,m.compareArrayLike);
+m.reprRegistry=new m.AdapterRegistry();
+m.registerRepr("arrayLike",m.isArrayLike,m.reprArrayLike);
+m.registerRepr("string",m.typeMatcher("string"),m.reprString);
+m.registerRepr("numbers",m.typeMatcher("number","boolean"),m.reprNumber);
+m.jsonRegistry=new m.AdapterRegistry();
+var all=m.concat(m.EXPORT,m.EXPORT_OK);
+m.EXPORT_TAGS={":common":m.concat(m.EXPORT_OK),":all":all};
+m.nameFunctions(this);
+};
+MochiKit.Base.__new__();
+if(MochiKit.__export__){
+compare=MochiKit.Base.compare;
+compose=MochiKit.Base.compose;
+serializeJSON=MochiKit.Base.serializeJSON;
+}
+MochiKit.Base._exportSymbols(this,MochiKit.Base);
+if(typeof (dojo)!="undefined"){
+dojo.provide("MochiKit.DOM");
+dojo.require("MochiKit.Base");
+}
+if(typeof (JSAN)!="undefined"){
+JSAN.use("MochiKit.Base",[]);
+}
+try{
+if(typeof (MochiKit.Base)=="undefined"){
+throw "";
+}
+}
+catch(e){
+throw "MochiKit.DOM depends on MochiKit.Base!";
+}
+if(typeof (MochiKit.DOM)=="undefined"){
+MochiKit.DOM={};
+}
+MochiKit.DOM.NAME="MochiKit.DOM";
+MochiKit.DOM.VERSION="1.4";
+MochiKit.DOM.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.DOM.toString=function(){
+return this.__repr__();
+};
+MochiKit.DOM.EXPORT=["removeEmptyTextNodes","formContents","currentWindow","currentDocument","withWindow","withDocument","registerDOMConverter","coerceToDOM","createDOM","createDOMFunc","isChildNode","getNodeAttribute","removeNodeAttribute","setNodeAttribute","updateNodeAttributes","appendChildNodes","insertSiblingNodesAfter","insertSiblingNodesBefore","replaceChildNodes","removeElement","swapDOM","BUTTON","TT","PRE","H1","H2","H3","BR","CANVAS","HR","LABEL","TEXTAREA","FORM","STRONG","SELECT","OPTION","OPTGROUP","LEGEND","FIELDSET","P","UL","OL","LI","TD","TR","THEAD","TBODY","TFOOT","TABLE","TH","INPUT","SPAN","A","DIV","IMG","getElement","$","getElementsByTagAndClassName","addToCallStack","addLoadEvent","focusOnLoad","setElementClass","toggleElementClass","addElementClass","removeElementClass","swapElementClass","hasElementClass","escapeHTML","toHTML","emitHTML","scrapeText","isParent","getFirstParentByTagAndClassName","makeClipping","undoClipping","makePositioned","undoPositioned","getFirstElementByTagAndClassName"];
+MochiKit.DOM.EXPORT_OK=["domConverters"];
+MochiKit.DOM.DEPRECATED=[["computedStyle","MochiKit.Style.getStyle","1.4"],["elementDimensions","MochiKit.Style.getElementDimensions","1.4"],["elementPosition","MochiKit.Style.getElementPosition","1.4"],["hideElement","MochiKit.Style.hideElement","1.4"],["setElementDimensions","MochiKit.Style.setElementDimensions","1.4"],["setElementPosition","MochiKit.Style.setElementPosition","1.4"],["setDisplayForElement","MochiKit.Style.setDisplayForElement","1.4"],["setOpacity","MochiKit.Style.setOpacity","1.4"],["showElement","MochiKit.Style.showElement","1.4"],["Coordinates","MochiKit.Style.Coordinates","1.4"],["Dimensions","MochiKit.Style.Dimensions","1.4"]];
+MochiKit.DOM.getViewportDimensions=new Function(""+"if (!MochiKit[\"Style\"]) {"+"    throw new Error(\"This function has been deprecated and depends on MochiKit.Style.\");"+"}"+"return MochiKit.Style.getViewportDimensions.apply(this, arguments);");
+MochiKit.Base.update(MochiKit.DOM,{currentWindow:function(){
+return MochiKit.DOM._window;
+},currentDocument:function(){
+return MochiKit.DOM._document;
+},withWindow:function(win,func){
+var self=MochiKit.DOM;
+var _152=self._document;
+var _153=self._window;
+var rval;
+try{
+self._window=win;
+self._document=win.document;
+rval=func();
+}
+catch(e){
+self._window=_153;
+self._document=_152;
+throw e;
+}
+self._window=_153;
+self._document=_152;
+return rval;
+},formContents:function(elem){
+var _156=[];
+var _157=[];
+var m=MochiKit.Base;
+var self=MochiKit.DOM;
+if(typeof (elem)=="undefined"||elem===null){
+elem=self._document.body;
+}else{
+elem=self.getElement(elem);
+}
+m.nodeWalk(elem,function(elem){
+var name=elem.name;
+if(m.isNotEmpty(name)){
+var _15c=elem.tagName.toUpperCase();
+if(_15c==="INPUT"&&(elem.type=="radio"||elem.type=="checkbox")&&!elem.checked){
+return null;
+}
+if(_15c==="SELECT"){
+if(elem.type=="select-one"){
+if(elem.selectedIndex>=0){
+var opt=elem.options[elem.selectedIndex];
+var v=opt.value;
+if(!v){
+var h=opt.outerHTML;
+if(h&&!h.match(/^[^>]+\svalue\s*=/i)){
+v=opt.text;
+}
+}
+_156.push(name);
+_157.push(v);
+return null;
+}
+_156.push(name);
+_157.push("");
+return null;
+}else{
+var opts=elem.options;
+if(!opts.length){
+_156.push(name);
+_157.push("");
+return null;
+}
+for(var i=0;i<opts.length;i++){
+var opt=opts[i];
+if(!opt.selected){
+continue;
+}
+var v=opt.value;
+if(!v){
+var h=opt.outerHTML;
+if(h&&!h.match(/^[^>]+\svalue\s*=/i)){
+v=opt.text;
+}
+}
+_156.push(name);
+_157.push(v);
+}
+return null;
+}
+}
+if(_15c==="FORM"||_15c==="P"||_15c==="SPAN"||_15c==="DIV"){
+return elem.childNodes;
+}
+_156.push(name);
+_157.push(elem.value||"");
+return null;
+}
+return elem.childNodes;
+});
+return [_156,_157];
+},withDocument:function(doc,func){
+var self=MochiKit.DOM;
+var _165=self._document;
+var rval;
+try{
+self._document=doc;
+rval=func();
+}
+catch(e){
+self._document=_165;
+throw e;
+}
+self._document=_165;
+return rval;
+},registerDOMConverter:function(name,_168,wrap,_16a){
+MochiKit.DOM.domConverters.register(name,_168,wrap,_16a);
+},coerceToDOM:function(node,ctx){
+var m=MochiKit.Base;
+var im=MochiKit.Iter;
+var self=MochiKit.DOM;
+if(im){
+var iter=im.iter;
+var _171=im.repeat;
+var map=m.map;
+}
+var _173=self.domConverters;
+var _174=arguments.callee;
+var _175=m.NotFound;
+while(true){
+if(typeof (node)=="undefined"||node===null){
+return null;
+}
+if(typeof (node)=="function"&&typeof (node.length)=="number"&&!(node instanceof Function)){
+node=im.list(node);
+}
+if(typeof (node.nodeType)!="undefined"&&node.nodeType>0){
+return node;
+}
+if(typeof (node)=="number"||typeof (node)=="boolean"){
+node=node.toString();
+}
+if(typeof (node)=="string"){
+return self._document.createTextNode(node);
+}
+if(typeof (node.__dom__)=="function"){
+node=node.__dom__(ctx);
+continue;
+}
+if(typeof (node.dom)=="function"){
+node=node.dom(ctx);
+continue;
+}
+if(typeof (node)=="function"){
+node=node.apply(ctx,[ctx]);
+continue;
+}
+if(im){
+var _176=null;
+try{
+_176=iter(node);
+}
+catch(e){
+}
+if(_176){
+return map(_174,_176,_171(ctx));
+}
+}
+try{
+node=_173.match(node,ctx);
+continue;
+}
+catch(e){
+if(e!=_175){
+throw e;
+}
+}
+return self._document.createTextNode(node.toString());
+}
+return undefined;
+},isChildNode:function(node,_178){
+var self=MochiKit.DOM;
+if(typeof (node)=="string"){
+node=self.getElement(node);
+}
+if(typeof (_178)=="string"){
+_178=self.getElement(_178);
+}
+if(node===_178){
+return true;
+}
+while(node&&node.tagName.toUpperCase()!="BODY"){
+node=node.parentNode;
+if(node===_178){
+return true;
+}
+}
+return false;
+},setNodeAttribute:function(node,attr,_17c){
+var o={};
+o[attr]=_17c;
+try{
+return MochiKit.DOM.updateNodeAttributes(node,o);
+}
+catch(e){
+}
+return null;
+},getNodeAttribute:function(node,attr){
+var self=MochiKit.DOM;
+var _181=self.attributeArray.renames[attr];
+node=self.getElement(node);
+try{
+if(_181){
+return node[_181];
+}
+return node.getAttribute(attr);
+}
+catch(e){
+}
+return null;
+},removeNodeAttribute:function(node,attr){
+var self=MochiKit.DOM;
+var _185=self.attributeArray.renames[attr];
+node=self.getElement(node);
+try{
+if(_185){
+return node[_185];
+}
+return node.removeAttribute(attr);
+}
+catch(e){
+}
+return null;
+},updateNodeAttributes:function(node,_187){
+var elem=node;
+var self=MochiKit.DOM;
+if(typeof (node)=="string"){
+elem=self.getElement(node);
+}
+if(_187){
+var _18a=MochiKit.Base.updatetree;
+if(self.attributeArray.compliant){
+for(var k in _187){
+var v=_187[k];
+if(typeof (v)=="object"&&typeof (elem[k])=="object"){
+if(k=="style"&&MochiKit.Style){
+MochiKit.Style.setStyle(elem,v);
+}else{
+_18a(elem[k],v);
+}
+}else{
+if(k.substring(0,2)=="on"){
+if(typeof (v)=="string"){
+v=new Function(v);
+}
+elem[k]=v;
+}else{
+elem.setAttribute(k,v);
+}
+}
+}
+}else{
+var _18d=self.attributeArray.renames;
+for(var k in _187){
+v=_187[k];
+var _18e=_18d[k];
+if(k=="style"&&typeof (v)=="string"){
+elem.style.cssText=v;
+}else{
+if(typeof (_18e)=="string"){
+elem[_18e]=v;
+}else{
+if(typeof (elem[k])=="object"&&typeof (v)=="object"){
+if(k=="style"&&MochiKit.Style){
+MochiKit.Style.setStyle(elem,v);
+}else{
+_18a(elem[k],v);
+}
+}else{
+if(k.substring(0,2)=="on"){
+if(typeof (v)=="string"){
+v=new Function(v);
+}
+elem[k]=v;
+}else{
+elem.setAttribute(k,v);
+}
+}
+}
+}
+}
+}
+}
+return elem;
+},appendChildNodes:function(node){
+var elem=node;
+var self=MochiKit.DOM;
+if(typeof (node)=="string"){
+elem=self.getElement(node);
+}
+var _192=[self.coerceToDOM(MochiKit.Base.extend(null,arguments,1),elem)];
+var _193=MochiKit.Base.concat;
+while(_192.length){
+var n=_192.shift();
+if(typeof (n)=="undefined"||n===null){
+}else{
+if(typeof (n.nodeType)=="number"){
+elem.appendChild(n);
+}else{
+_192=_193(n,_192);
+}
+}
+}
+return elem;
+},insertSiblingNodesBefore:function(node){
+var elem=node;
+var self=MochiKit.DOM;
+if(typeof (node)=="string"){
+elem=self.getElement(node);
+}
+var _198=[self.coerceToDOM(MochiKit.Base.extend(null,arguments,1),elem)];
+var _199=elem.parentNode;
+var _19a=MochiKit.Base.concat;
+while(_198.length){
+var n=_198.shift();
+if(typeof (n)=="undefined"||n===null){
+}else{
+if(typeof (n.nodeType)=="number"){
+_199.insertBefore(n,elem);
+}else{
+_198=_19a(n,_198);
+}
+}
+}
+return _199;
+},insertSiblingNodesAfter:function(node){
+var elem=node;
+var self=MochiKit.DOM;
+if(typeof (node)=="string"){
+elem=self.getElement(node);
+}
+var _19f=[self.coerceToDOM(MochiKit.Base.extend(null,arguments,1),elem)];
+if(elem.nextSibling){
+return self.insertSiblingNodesBefore(elem.nextSibling,_19f);
+}else{
+return self.appendChildNodes(elem.parentNode,_19f);
+}
+},replaceChildNodes:function(node){
+var elem=node;
+var self=MochiKit.DOM;
+if(typeof (node)=="string"){
+elem=self.getElement(node);
+arguments[0]=elem;
+}
+var _1a3;
+while((_1a3=elem.firstChild)){
+elem.removeChild(_1a3);
+}
+if(arguments.length<2){
+return elem;
+}else{
+return self.appendChildNodes.apply(this,arguments);
+}
+},createDOM:function(name,_1a5){
+var elem;
+var self=MochiKit.DOM;
+var m=MochiKit.Base;
+if(typeof (_1a5)=="string"||typeof (_1a5)=="number"){
+var args=m.extend([name,null],arguments,1);
+return arguments.callee.apply(this,args);
+}
+if(typeof (name)=="string"){
+var _1aa=self._xhtml;
+if(_1a5&&!self.attributeArray.compliant){
+var _1ab="";
+if("name" in _1a5){
+_1ab+=" name=\""+self.escapeHTML(_1a5.name)+"\"";
+}
+if(name=="input"&&"type" in _1a5){
+_1ab+=" type=\""+self.escapeHTML(_1a5.type)+"\"";
+}
+if(_1ab){
+name="<"+name+_1ab+">";
+_1aa=false;
+}
+}
+var d=self._document;
+if(_1aa&&d===document){
+elem=d.createElementNS("http://www.w3.org/1999/xhtml",name);
+}else{
+elem=d.createElement(name);
+}
+}else{
+elem=name;
+}
+if(_1a5){
+self.updateNodeAttributes(elem,_1a5);
+}
+if(arguments.length<=2){
+return elem;
+}else{
+var args=m.extend([elem],arguments,2);
+return self.appendChildNodes.apply(this,args);
+}
+},createDOMFunc:function(){
+var m=MochiKit.Base;
+return m.partial.apply(this,m.extend([MochiKit.DOM.createDOM],arguments));
+},removeElement:function(elem){
+var e=MochiKit.DOM.getElement(elem);
+e.parentNode.removeChild(e);
+return e;
+},swapDOM:function(dest,src){
+var self=MochiKit.DOM;
+dest=self.getElement(dest);
+var _1b3=dest.parentNode;
+if(src){
+src=self.getElement(src);
+_1b3.replaceChild(src,dest);
+}else{
+_1b3.removeChild(dest);
+}
+return src;
+},getElement:function(id){
+var self=MochiKit.DOM;
+if(arguments.length==1){
+return ((typeof (id)=="string")?self._document.getElementById(id):id);
+}else{
+return MochiKit.Base.map(self.getElement,arguments);
+}
+},getElementsByTagAndClassName:function(_1b6,_1b7,_1b8){
+var self=MochiKit.DOM;
+if(typeof (_1b6)=="undefined"||_1b6===null){
+_1b6="*";
+}
+if(typeof (_1b8)=="undefined"||_1b8===null){
+_1b8=self._document;
+}
+_1b8=self.getElement(_1b8);
+var _1ba=(_1b8.getElementsByTagName(_1b6)||self._document.all);
+if(typeof (_1b7)=="undefined"||_1b7===null){
+return MochiKit.Base.extend(null,_1ba);
+}
+var _1bb=[];
+for(var i=0;i<_1ba.length;i++){
+var _1bd=_1ba[i];
+var cls=_1bd.className;
+if(!cls){
+continue;
+}
+var _1bf=cls.split(" ");
+for(var j=0;j<_1bf.length;j++){
+if(_1bf[j]==_1b7){
+_1bb.push(_1bd);
+break;
+}
+}
+}
+return _1bb;
+},_newCallStack:function(path,once){
+var rval=function(){
+var _1c4=arguments.callee.callStack;
+for(var i=0;i<_1c4.length;i++){
+if(_1c4[i].apply(this,arguments)===false){
+break;
+}
+}
+if(once){
+try{
+this[path]=null;
+}
+catch(e){
+}
+}
+};
+rval.callStack=[];
+return rval;
+},addToCallStack:function(_1c6,path,func,once){
+var self=MochiKit.DOM;
+var _1cb=_1c6[path];
+var _1cc=_1cb;
+if(!(typeof (_1cb)=="function"&&typeof (_1cb.callStack)=="object"&&_1cb.callStack!==null)){
+_1cc=self._newCallStack(path,once);
+if(typeof (_1cb)=="function"){
+_1cc.callStack.push(_1cb);
+}
+_1c6[path]=_1cc;
+}
+_1cc.callStack.push(func);
+},addLoadEvent:function(func){
+var self=MochiKit.DOM;
+self.addToCallStack(self._window,"onload",func,true);
+},focusOnLoad:function(_1cf){
+var self=MochiKit.DOM;
+self.addLoadEvent(function(){
+_1cf=self.getElement(_1cf);
+if(_1cf){
+_1cf.focus();
+}
+});
+},setElementClass:function(_1d1,_1d2){
+var self=MochiKit.DOM;
+var obj=self.getElement(_1d1);
+if(self.attributeArray.compliant){
+obj.setAttribute("class",_1d2);
+}else{
+obj.setAttribute("className",_1d2);
+}
+},toggleElementClass:function(_1d5){
+var self=MochiKit.DOM;
+for(var i=1;i<arguments.length;i++){
+var obj=self.getElement(arguments[i]);
+if(!self.addElementClass(obj,_1d5)){
+self.removeElementClass(obj,_1d5);
+}
+}
+},addElementClass:function(_1d9,_1da){
+var self=MochiKit.DOM;
+var obj=self.getElement(_1d9);
+var cls=obj.className;
+if(cls==undefined||cls.length===0){
+self.setElementClass(obj,_1da);
+return true;
+}
+if(cls==_1da){
+return false;
+}
+var _1de=cls.split(" ");
+for(var i=0;i<_1de.length;i++){
+if(_1de[i]==_1da){
+return false;
+}
+}
+self.setElementClass(obj,cls+" "+_1da);
+return true;
+},removeElementClass:function(_1e0,_1e1){
+var self=MochiKit.DOM;
+var obj=self.getElement(_1e0);
+var cls=obj.className;
+if(cls==undefined||cls.length===0){
+return false;
+}
+if(cls==_1e1){
+self.setElementClass(obj,"");
+return true;
+}
+var _1e5=cls.split(" ");
+for(var i=0;i<_1e5.length;i++){
+if(_1e5[i]==_1e1){
+_1e5.splice(i,1);
+self.setElementClass(obj,_1e5.join(" "));
+return true;
+}
+}
+return false;
+},swapElementClass:function(_1e7,_1e8,_1e9){
+var obj=MochiKit.DOM.getElement(_1e7);
+var res=MochiKit.DOM.removeElementClass(obj,_1e8);
+if(res){
+MochiKit.DOM.addElementClass(obj,_1e9);
+}
+return res;
+},hasElementClass:function(_1ec,_1ed){
+var obj=MochiKit.DOM.getElement(_1ec);
+var cls=obj.className;
+if(!cls){
+return false;
+}
+var _1f0=cls.split(" ");
+for(var i=1;i<arguments.length;i++){
+var good=false;
+for(var j=0;j<_1f0.length;j++){
+if(_1f0[j]==arguments[i]){
+good=true;
+break;
+}
+}
+if(!good){
+return false;
+}
+}
+return true;
+},escapeHTML:function(s){
+return s.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
+},toHTML:function(dom){
+return MochiKit.DOM.emitHTML(dom).join("");
+},emitHTML:function(dom,lst){
+if(typeof (lst)=="undefined"||lst===null){
+lst=[];
+}
+var _1f8=[dom];
+var self=MochiKit.DOM;
+var _1fa=self.escapeHTML;
+var _1fb=self.attributeArray;
+while(_1f8.length){
+dom=_1f8.pop();
+if(typeof (dom)=="string"){
+lst.push(dom);
+}else{
+if(dom.nodeType==1){
+lst.push("<"+dom.tagName.toLowerCase());
+var _1fc=[];
+var _1fd=_1fb(dom);
+for(var i=0;i<_1fd.length;i++){
+var a=_1fd[i];
+_1fc.push([" ",a.name,"=\"",_1fa(a.value),"\""]);
+}
+_1fc.sort();
+for(i=0;i<_1fc.length;i++){
+var _200=_1fc[i];
+for(var j=0;j<_200.length;j++){
+lst.push(_200[j]);
+}
+}
+if(dom.hasChildNodes()){
+lst.push(">");
+_1f8.push("</"+dom.tagName.toLowerCase()+">");
+var _202=dom.childNodes;
+for(i=_202.length-1;i>=0;i--){
+_1f8.push(_202[i]);
+}
+}else{
+lst.push("/>");
+}
+}else{
+if(dom.nodeType==3){
+lst.push(_1fa(dom.nodeValue));
+}
+}
+}
+}
+return lst;
+},scrapeText:function(node,_204){
+var rval=[];
+(function(node){
+var cn=node.childNodes;
+if(cn){
+for(var i=0;i<cn.length;i++){
+arguments.callee.call(this,cn[i]);
+}
+}
+var _209=node.nodeValue;
+if(typeof (_209)=="string"){
+rval.push(_209);
+}
+})(MochiKit.DOM.getElement(node));
+if(_204){
+return rval;
+}else{
+return rval.join("");
+}
+},removeEmptyTextNodes:function(_20a){
+_20a=MochiKit.DOM.getElement(_20a);
+for(var i=0;i<_20a.childNodes.length;i++){
+var node=_20a.childNodes[i];
+if(node.nodeType==3&&!/\S/.test(node.nodeValue)){
+node.parentNode.removeChild(node);
+}
+}
+},makeClipping:function(_20d){
+_20d=MochiKit.DOM.getElement(_20d);
+var _20e=_20d.style.overflow;
+if((MochiKit.Style.getStyle(_20d,"overflow")||"visible")!="hidden"){
+_20d.style.overflow="hidden";
+}
+return _20e;
+},undoClipping:function(_20f,_210){
+_20f=MochiKit.DOM.getElement(_20f);
+if(!_210){
+return;
+}
+_20f.style.overflow=_210;
+},makePositioned:function(_211){
+_211=MochiKit.DOM.getElement(_211);
+var pos=MochiKit.Style.getStyle(_211,"position");
+if(pos=="static"||!pos){
+_211.style.position="relative";
+if(/Opera/.test(navigator.userAgent)){
+_211.style.top=0;
+_211.style.left=0;
+}
+}
+},undoPositioned:function(_213){
+_213=MochiKit.DOM.getElement(_213);
+if(_213.style.position=="relative"){
+_213.style.position=_213.style.top=_213.style.left=_213.style.bottom=_213.style.right="";
+}
+},getFirstElementByTagAndClassName:function(_214,_215,_216){
+var self=MochiKit.DOM;
+if(typeof (_214)=="undefined"||_214===null){
+_214="*";
+}
+if(typeof (_216)=="undefined"||_216===null){
+_216=self._document;
+}
+_216=self.getElement(_216);
+var _218=(_216.getElementsByTagName(_214)||self._document.all);
+if(typeof (_215)=="undefined"||_215===null){
+return _218[0];
+}
+for(var i=0;i<_218.length;i++){
+var _21a=_218[i];
+var _21b=_21a.className.split(" ");
+for(var j=0;j<_21b.length;j++){
+if(_21b[j]==_215){
+return _21a;
+}
+}
+}
+},getFirstParentByTagAndClassName:function(elem,_21e,_21f){
+var self=MochiKit.DOM;
+elem=self.getElement(elem);
+if(typeof (_21e)=="undefined"||_21e===null){
+_21e="*";
+}else{
+_21e=_21e.toUpperCase();
+}
+if(typeof (_21f)=="undefined"||_21f===null){
+_21f=null;
+}
+var _221="";
+var _222="";
+while(elem&&elem.tagName){
+elem=elem.parentNode;
+if(_21e=="*"&&_21f===null){
+return elem;
+}
+_221=elem.className.split(" ");
+_222=elem.tagName.toUpperCase();
+if(_21f===null&&_21e==_222){
+return elem;
+}else{
+if(_21f!==null){
+for(var i=0;i<_221.length;i++){
+if(_21e=="*"&&_221[i]==_21f){
+return elem;
+}else{
+if(_21e==_222&&_221[i]==_21f){
+return elem;
+}
+}
+}
+}
+}
+}
+return elem;
+},isParent:function(_224,_225){
+if(!_224.parentNode||_224==_225){
+return false;
+}
+if(_224.parentNode==_225){
+return true;
+}
+return MochiKit.DOM.isParent(_224.parentNode,_225);
+},__new__:function(win){
+var m=MochiKit.Base;
+if(typeof (document)!="undefined"){
+this._document=document;
+var _228="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+this._xhtml=(document.documentElement&&document.createElementNS&&document.documentElement.namespaceURI===_228);
+}else{
+if(MochiKit.MockDOM){
+this._document=MochiKit.MockDOM.document;
+}
+}
+this._window=win;
+this.domConverters=new m.AdapterRegistry();
+var _229=this._document.createElement("span");
+var _22a;
+if(_229&&_229.attributes&&_229.attributes.length>0){
+var _22b=m.filter;
+_22a=function(node){
+return _22b(_22a.ignoreAttrFilter,node.attributes);
+};
+_22a.ignoreAttr={};
+var _22d=_229.attributes;
+var _22e=_22a.ignoreAttr;
+for(var i=0;i<_22d.length;i++){
+var a=_22d[i];
+_22e[a.name]=a.value;
+}
+_22a.ignoreAttrFilter=function(a){
+return (_22a.ignoreAttr[a.name]!=a.value);
+};
+_22a.compliant=false;
+_22a.renames={"class":"className","checked":"defaultChecked","usemap":"useMap","for":"htmlFor","readonly":"readOnly","colspan":"colSpan","bgcolor":"bgColor","cellspacing":"cellSpacing","cellpadding":"cellPadding"};
+}else{
+_22a=function(node){
+return node.attributes;
+};
+_22a.compliant=true;
+_22a.renames={};
+}
+this.attributeArray=_22a;
+var _233=function(_234,arr){
+var _236=arr[1].split(".");
+var str="";
+var obj={};
+str+="if (!MochiKit."+_236[1]+") { throw new Error(\"";
+str+="This function has been deprecated and depends on MochiKit.";
+str+=_236[1]+".\");}";
+str+="return MochiKit."+_236[1]+"."+arr[0];
+str+=".apply(this, arguments);";
+obj[_236[2]]=new Function(str);
+MochiKit.Base.update(MochiKit[_234],obj);
+};
+for(var i;i<MochiKit.DOM.DEPRECATED.length;i++){
+_233("DOM",MochiKit.DOM.DEPRECATED[i]);
+}
+var _239=this.createDOMFunc;
+this.UL=_239("ul");
+this.OL=_239("ol");
+this.LI=_239("li");
+this.TD=_239("td");
+this.TR=_239("tr");
+this.TBODY=_239("tbody");
+this.THEAD=_239("thead");
+this.TFOOT=_239("tfoot");
+this.TABLE=_239("table");
+this.TH=_239("th");
+this.INPUT=_239("input");
+this.SPAN=_239("span");
+this.A=_239("a");
+this.DIV=_239("div");
+this.IMG=_239("img");
+this.BUTTON=_239("button");
+this.TT=_239("tt");
+this.PRE=_239("pre");
+this.H1=_239("h1");
+this.H2=_239("h2");
+this.H3=_239("h3");
+this.BR=_239("br");
+this.HR=_239("hr");
+this.LABEL=_239("label");
+this.TEXTAREA=_239("textarea");
+this.FORM=_239("form");
+this.P=_239("p");
+this.SELECT=_239("select");
+this.OPTION=_239("option");
+this.OPTGROUP=_239("optgroup");
+this.LEGEND=_239("legend");
+this.FIELDSET=_239("fieldset");
+this.STRONG=_239("strong");
+this.CANVAS=_239("canvas");
+this.$=this.getElement;
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+m.nameFunctions(this);
+}});
+MochiKit.DOM.__new__(((typeof (window)=="undefined")?this:window));
+if(MochiKit.__export__){
+withWindow=MochiKit.DOM.withWindow;
+withDocument=MochiKit.DOM.withDocument;
+}
+MochiKit.Base._exportSymbols(this,MochiKit.DOM);
+if(typeof (dojo)!="undefined"){
+dojo.provide("MochiKit.Style");
+dojo.require("MochiKit.Base");
+dojo.require("MochiKit.DOM");
+}
+if(typeof (JSAN)!="undefined"){
+JSAN.use("MochiKit.Base",[]);
+JSAN.use("MochiKit.DOM",[]);
+}
+try{
+if(typeof (MochiKit.Base)=="undefined"){
+throw "";
+}
+}
+catch(e){
+throw "MochiKit.Style depends on MochiKit.Base!";
+}
+try{
+if(typeof (MochiKit.DOM)=="undefined"){
+throw "";
+}
+}
+catch(e){
+throw "MochiKit.Style depends on MochiKit.DOM!";
+}
+if(typeof (MochiKit.Style)=="undefined"){
+MochiKit.Style={};
+}
+MochiKit.Style.NAME="MochiKit.Style";
+MochiKit.Style.VERSION="1.4";
+MochiKit.Style.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.Style.toString=function(){
+return this.__repr__();
+};
+MochiKit.Style.EXPORT_OK=[];
+MochiKit.Style.EXPORT=["setStyle","setOpacity","getStyle","getElementDimensions","elementDimensions","setElementDimensions","getElementPosition","elementPosition","setElementPosition","setDisplayForElement","hideElement","showElement","getViewportDimensions","getViewportPosition","Dimensions","Coordinates"];
+MochiKit.Style.Dimensions=function(w,h){
+this.w=w;
+this.h=h;
+};
+MochiKit.Style.Dimensions.prototype.__repr__=function(){
+var repr=MochiKit.Base.repr;
+return "{w: "+repr(this.w)+", h: "+repr(this.h)+"}";
+};
+MochiKit.Style.Dimensions.prototype.toString=function(){
+return this.__repr__();
+};
+MochiKit.Style.Coordinates=function(x,y){
+this.x=x;
+this.y=y;
+};
+MochiKit.Style.Coordinates.prototype.__repr__=function(){
+var repr=MochiKit.Base.repr;
+return "{x: "+repr(this.x)+", y: "+repr(this.y)+"}";
+};
+MochiKit.Style.Coordinates.prototype.toString=function(){
+return this.__repr__();
+};
+MochiKit.Base.update(MochiKit.Style,{getStyle:function(elem,_241){
+var dom=MochiKit.DOM;
+var d=dom._document;
+elem=dom.getElement(elem);
+_241=MochiKit.Base.camelize(_241);
+if(!elem||elem==d){
+return undefined;
+}
+if(_241=="opacity"&&elem.filters){
+var _244=(MochiKit.Style.getStyle(elem,"filter")||"").match(/alpha\(opacity=(.*)\)/);
+if(_244&&_244[1]){
+return parseFloat(_244[1])/100;
+}
+return 1;
+}
+var _245=elem.style?elem.style[_241]:null;
+if(!_245){
+if(d.defaultView&&d.defaultView.getComputedStyle){
+var css=d.defaultView.getComputedStyle(elem,null);
+_241=_241.replace(/([A-Z])/g,"-$1").toLowerCase();
+_245=css?css.getPropertyValue(_241):null;
+}else{
+if(elem.currentStyle){
+_245=elem.currentStyle[_241];
+}
+}
+}
+if(_241=="opacity"){
+_245=parseFloat(_245);
+}
+if(/Opera/.test(navigator.userAgent)&&(MochiKit.Base.find(["left","top","right","bottom"],_241)!=-1)){
+if(MochiKit.Style.getStyle(elem,"position")=="static"){
+_245="auto";
+}
+}
+return _245=="auto"?null:_245;
+},setStyle:function(elem,_248){
+elem=MochiKit.DOM.getElement(elem);
+for(var name in _248){
+if(name=="opacity"){
+MochiKit.Style.setOpacity(elem,_248[name]);
+}else{
+elem.style[MochiKit.Base.camelize(name)]=_248[name];
+}
+}
+},setOpacity:function(elem,o){
+elem=MochiKit.DOM.getElement(elem);
+var self=MochiKit.Style;
+if(o==1){
+var _24d=/Gecko/.test(navigator.userAgent)&&!(/Konqueror|AppleWebKit|KHTML/.test(navigator.userAgent));
+elem.style["opacity"]=_24d?0.999999:1;
+if(/MSIE/.test(navigator.userAgent)){
+elem.style["filter"]=self.getStyle(elem,"filter").replace(/alpha\([^\)]*\)/gi,"");
+}
+}else{
+if(o<0.00001){
+o=0;
+}
+elem.style["opacity"]=o;
+if(/MSIE/.test(navigator.userAgent)){
+elem.style["filter"]=self.getStyle(elem,"filter").replace(/alpha\([^\)]*\)/gi,"")+"alpha(opacity="+o*100+")";
+}
+}
+},getElementPosition:function(elem,_24f){
+var self=MochiKit.Style;
+var dom=MochiKit.DOM;
+elem=dom.getElement(elem);
+if(!elem||(!(elem.x&&elem.y)&&(!elem.parentNode===null||self.getStyle(elem,"display")=="none"))){
+return undefined;
+}
+var c=new self.Coordinates(0,0);
+var box=null;
+var _254=null;
+var d=MochiKit.DOM._document;
+var de=d.documentElement;
+var b=d.body;
+if(!elem.parentNode&&elem.x&&elem.y){
+c.x+=elem.x||0;
+c.y+=elem.y||0;
+}else{
+if(elem.getBoundingClientRect){
+box=elem.getBoundingClientRect();
+c.x+=box.left+(de.scrollLeft||b.scrollLeft)-(de.clientLeft||0);
+c.y+=box.top+(de.scrollTop||b.scrollTop)-(de.clientTop||0);
+}else{
+if(elem.offsetParent){
+c.x+=elem.offsetLeft;
+c.y+=elem.offsetTop;
+_254=elem.offsetParent;
+if(_254!=elem){
+while(_254){
+c.x+=_254.offsetLeft;
+c.y+=_254.offsetTop;
+_254=_254.offsetParent;
+}
+}
+var ua=navigator.userAgent.toLowerCase();
+if((typeof (opera)!="undefined"&&parseFloat(opera.version())<9)||(ua.indexOf("AppleWebKit")!=-1&&self.getStyle(elem,"position")=="absolute")){
+c.x-=b.offsetLeft;
+c.y-=b.offsetTop;
+}
+}
+}
+}
+if(typeof (_24f)!="undefined"){
+_24f=arguments.callee(_24f);
+if(_24f){
+c.x-=(_24f.x||0);
+c.y-=(_24f.y||0);
+}
+}
+if(elem.parentNode){
+_254=elem.parentNode;
+}else{
+_254=null;
+}
+while(_254){
+var _259=_254.tagName.toUpperCase();
+if(_259==="BODY"||_259==="HTML"){
+break;
+}
+var disp=self.getStyle(_254,"display");
+if(disp!="inline"&&disp!="table-row"){
+c.x-=_254.scrollLeft;
+c.y-=_254.scrollTop;
+}
+if(_254.parentNode){
+_254=_254.parentNode;
+}else{
+_254=null;
+}
+}
+return c;
+},setElementPosition:function(elem,_25c,_25d){
+elem=MochiKit.DOM.getElement(elem);
+if(typeof (_25d)=="undefined"){
+_25d="px";
+}
+var _25e={};
+var _25f=MochiKit.Base.isUndefinedOrNull;
+if(!_25f(_25c.x)){
+_25e["left"]=_25c.x+_25d;
+}
+if(!_25f(_25c.y)){
+_25e["top"]=_25c.y+_25d;
+}
+MochiKit.DOM.updateNodeAttributes(elem,{"style":_25e});
+},getElementDimensions:function(elem){
+var self=MochiKit.Style;
+var dom=MochiKit.DOM;
+if(typeof (elem.w)=="number"||typeof (elem.h)=="number"){
+return new self.Dimensions(elem.w||0,elem.h||0);
+}
+elem=dom.getElement(elem);
+if(!elem){
+return undefined;
+}
+var disp=self.getStyle(elem,"display");
+if(disp!="none"&&disp!==""&&typeof (disp)!="undefined"){
+return new self.Dimensions(elem.offsetWidth||0,elem.offsetHeight||0);
+}
+var s=elem.style;
+var _265=s.visibility;
+var _266=s.position;
+s.visibility="hidden";
+s.position="absolute";
+s.display="";
+var _267=elem.offsetWidth;
+var _268=elem.offsetHeight;
+s.display="none";
+s.position=_266;
+s.visibility=_265;
+return new self.Dimensions(_267,_268);
+},setElementDimensions:function(elem,_26a,_26b){
+elem=MochiKit.DOM.getElement(elem);
+if(typeof (_26b)=="undefined"){
+_26b="px";
+}
+var _26c={};
+var _26d=MochiKit.Base.isUndefinedOrNull;
+if(!_26d(_26a.w)){
+_26c["width"]=_26a.w+_26b;
+}
+if(!_26d(_26a.h)){
+_26c["height"]=_26a.h+_26b;
+}
+MochiKit.DOM.updateNodeAttributes(elem,{"style":_26c});
+},setDisplayForElement:function(_26e,_26f){
+var _270=MochiKit.Base.extend(null,arguments,1);
+var _271=MochiKit.DOM.getElement;
+for(var i=0;i<_270.length;i++){
+_26f=_271(_270[i]);
+if(_26f){
+_26f.style.display=_26e;
+}
+}
+},getViewportDimensions:function(){
+var d=new MochiKit.Style.Dimensions();
+var w=MochiKit.DOM._window;
+var b=MochiKit.DOM._document.body;
+if(w.innerWidth){
+d.w=w.innerWidth;
+d.h=w.innerHeight;
+}else{
+if(b.parentElement.clientWidth){
+d.w=b.parentElement.clientWidth;
+d.h=b.parentElement.clientHeight;
+}else{
+if(b&&b.clientWidth){
+d.w=b.clientWidth;
+d.h=b.clientHeight;
+}
+}
+}
+return d;
+},getViewportPosition:function(){
+var c=new MochiKit.Style.Coordinates(0,0);
+var d=MochiKit.DOM._document;
+var de=d.documentElement;
+var db=d.body;
+if(de&&(de.scrollTop||de.scrollLeft)){
+c.x=de.scrollLeft;
+c.y=de.scrollTop;
+}else{
+if(db){
+c.x=db.scrollLeft;
+c.y=db.scrollTop;
+}
+}
+return c;
+},__new__:function(){
+var m=MochiKit.Base;
+this.elementPosition=this.getElementPosition;
+this.elementDimensions=this.getElementDimensions;
+this.hideElement=m.partial(this.setDisplayForElement,"none");
+this.showElement=m.partial(this.setDisplayForElement,"block");
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+m.nameFunctions(this);
+}});
+MochiKit.Style.__new__();
+MochiKit.Base._exportSymbols(this,MochiKit.Style);
+if(typeof (dojo)!="undefined"){
+dojo.provide("MochiKit.Signal");
+dojo.require("MochiKit.Base");
+dojo.require("MochiKit.DOM");
+dojo.require("MochiKit.Style");
+}
+if(typeof (JSAN)!="undefined"){
+JSAN.use("MochiKit.Base",[]);
+JSAN.use("MochiKit.DOM",[]);
+JSAN.use("MochiKit.Style",[]);
+}
+try{
+if(typeof (MochiKit.Base)=="undefined"){
+throw "";
+}
+}
+catch(e){
+throw "MochiKit.Signal depends on MochiKit.Base!";
+}
+try{
+if(typeof (MochiKit.DOM)=="undefined"){
+throw "";
+}
+}
+catch(e){
+throw "MochiKit.Signal depends on MochiKit.DOM!";
+}
+try{
+if(typeof (MochiKit.Style)=="undefined"){
+throw "";
+}
+}
+catch(e){
+throw "MochiKit.Signal depends on MochiKit.Style!";
+}
+if(typeof (MochiKit.Signal)=="undefined"){
+MochiKit.Signal={};
+}
+MochiKit.Signal.NAME="MochiKit.Signal";
+MochiKit.Signal.VERSION="1.4";
+MochiKit.Signal._observers=[];
+MochiKit.Signal.Event=function(src,e){
+this._event=e||window.event;
+this._src=src;
+};
+MochiKit.Base.update(MochiKit.Signal.Event.prototype,{__repr__:function(){
+var repr=MochiKit.Base.repr;
+var str="{event(): "+repr(this.event())+", src(): "+repr(this.src())+", type(): "+repr(this.type())+", target(): "+repr(this.target());
+if(this.type()&&this.type().indexOf("key")===0||this.type().indexOf("mouse")===0||this.type().indexOf("click")!=-1||this.type()=="contextmenu"){
+str+=", modifier(): "+"{alt: "+repr(this.modifier().alt)+", ctrl: "+repr(this.modifier().ctrl)+", meta: "+repr(this.modifier().meta)+", shift: "+repr(this.modifier().shift)+", any: "+repr(this.modifier().any)+"}";
+}
+if(this.type()&&this.type().indexOf("key")===0){
+str+=", key(): {code: "+repr(this.key().code)+", string: "+repr(this.key().string)+"}";
+}
+if(this.type()&&(this.type().indexOf("mouse")===0||this.type().indexOf("click")!=-1||this.type()=="contextmenu")){
+str+=", mouse(): {page: "+repr(this.mouse().page)+", client: "+repr(this.mouse().client);
+if(this.type()!="mousemove"){
+str+=", button: {left: "+repr(this.mouse().button.left)+", middle: "+repr(this.mouse().button.middle)+", right: "+repr(this.mouse().button.right)+"}}";
+}else{
+str+="}";
+}
+}
+if(this.type()=="mouseover"||this.type()=="mouseout"){
+str+=", relatedTarget(): "+repr(this.relatedTarget());
+}
+str+="}";
+return str;
+},toString:function(){
+return this.__repr__();
+},src:function(){
+return this._src;
+},event:function(){
+return this._event;
+},type:function(){
+return this._event.type||undefined;
+},target:function(){
+return this._event.target||this._event.srcElement;
+},_relatedTarget:null,relatedTarget:function(){
+if(this._relatedTarget!==null){
+return this._relatedTarget;
+}
+var elem=null;
+if(this.type()=="mouseover"){
+elem=(this._event.relatedTarget||this._event.fromElement);
+}else{
+if(this.type()=="mouseout"){
+elem=(this._event.relatedTarget||this._event.toElement);
+}
+}
+if(elem!==null){
+this._relatedTarget=elem;
+return elem;
+}
+return undefined;
+},_modifier:null,modifier:function(){
+if(this._modifier!==null){
+return this._modifier;
+}
+var m={};
+m.alt=this._event.altKey;
+m.ctrl=this._event.ctrlKey;
+m.meta=this._event.metaKey||false;
+m.shift=this._event.shiftKey;
+m.any=m.alt||m.ctrl||m.shift||m.meta;
+this._modifier=m;
+return m;
+},_key:null,key:function(){
+if(this._key!==null){
+return this._key;
+}
+var k={};
+if(this.type()&&this.type().indexOf("key")===0){
+if(this.type()=="keydown"||this.type()=="keyup"){
+k.code=this._event.keyCode;
+k.string=(MochiKit.Signal._specialKeys[k.code]||"KEY_UNKNOWN");
+this._key=k;
+return k;
+}else{
+if(this.type()=="keypress"){
+k.code=0;
+k.string="";
+if(typeof (this._event.charCode)!="undefined"&&this._event.charCode!==0&&!MochiKit.Signal._specialMacKeys[this._event.charCode]){
+k.code=this._event.charCode;
+k.string=String.fromCharCode(k.code);
+}else{
+if(this._event.keyCode&&typeof (this._event.charCode)=="undefined"){
+k.code=this._event.keyCode;
+k.string=String.fromCharCode(k.code);
+}
+}
+this._key=k;
+return k;
+}
+}
+}
+return undefined;
+},_mouse:null,mouse:function(){
+if(this._mouse!==null){
+return this._mouse;
+}
+var m={};
+var e=this._event;
+if(this.type()&&(this.type().indexOf("mouse")===0||this.type().indexOf("click")!=-1||this.type()=="contextmenu")){
+m.client=new MochiKit.Style.Coordinates(0,0);
+if(e.clientX||e.clientY){
+m.client.x=(!e.clientX||e.clientX<0)?0:e.clientX;
+m.client.y=(!e.clientY||e.clientY<0)?0:e.clientY;
+}
+m.page=new MochiKit.Style.Coordinates(0,0);
+if(e.pageX||e.pageY){
+m.page.x=(!e.pageX||e.pageX<0)?0:e.pageX;
+m.page.y=(!e.pageY||e.pageY<0)?0:e.pageY;
+}else{
+var de=MochiKit.DOM._document.documentElement;
+var b=MochiKit.DOM._document.body;
+m.page.x=e.clientX+(de.scrollLeft||b.scrollLeft)-(de.clientLeft||0);
+m.page.y=e.clientY+(de.scrollTop||b.scrollTop)-(de.clientTop||0);
+}
+if(this.type()!="mousemove"){
+m.button={};
+m.button.left=false;
+m.button.right=false;
+m.button.middle=false;
+if(e.which){
+m.button.left=(e.which==1);
+m.button.middle=(e.which==2);
+m.button.right=(e.which==3);
+}else{
+m.button.left=!!(e.button&1);
+m.button.right=!!(e.button&2);
+m.button.middle=!!(e.button&4);
+}
+}
+this._mouse=m;
+return m;
+}
+return undefined;
+},stop:function(){
+this.stopPropagation();
+this.preventDefault();
+},stopPropagation:function(){
+if(this._event.stopPropagation){
+this._event.stopPropagation();
+}else{
+this._event.cancelBubble=true;
+}
+},preventDefault:function(){
+if(this._event.preventDefault){
+this._event.preventDefault();
+}else{
+if(this._confirmUnload===null){
+this._event.returnValue=false;
+}
+}
+},_confirmUnload:null,confirmUnload:function(msg){
+if(this.type()=="beforeunload"){
+this._confirmUnload=msg;
+this._event.returnValue=msg;
+}
+}});
+MochiKit.Signal._specialMacKeys={3:"KEY_ENTER",63289:"KEY_NUM_PAD_CLEAR",63276:"KEY_PAGE_UP",63277:"KEY_PAGE_DOWN",63275:"KEY_END",63273:"KEY_HOME",63234:"KEY_ARROW_LEFT",63232:"KEY_ARROW_UP",63235:"KEY_ARROW_RIGHT",63233:"KEY_ARROW_DOWN",63302:"KEY_INSERT",63272:"KEY_DELETE"};
+(function(){
+var _287=MochiKit.Signal._specialMacKeys;
+for(i=63236;i<=63242;i++){
+_287[i]="KEY_F"+(i-63236+1);
+}
+})();
+MochiKit.Signal._specialKeys={8:"KEY_BACKSPACE",9:"KEY_TAB",12:"KEY_NUM_PAD_CLEAR",13:"KEY_ENTER",16:"KEY_SHIFT",17:"KEY_CTRL",18:"KEY_ALT",19:"KEY_PAUSE",20:"KEY_CAPS_LOCK",27:"KEY_ESCAPE",32:"KEY_SPACEBAR",33:"KEY_PAGE_UP",34:"KEY_PAGE_DOWN",35:"KEY_END",36:"KEY_HOME",37:"KEY_ARROW_LEFT",38:"KEY_ARROW_UP",39:"KEY_ARROW_RIGHT",40:"KEY_ARROW_DOWN",44:"KEY_PRINT_SCREEN",45:"KEY_INSERT",46:"KEY_DELETE",59:"KEY_SEMICOLON",91:"KEY_WINDOWS_LEFT",92:"KEY_WINDOWS_RIGHT",93:"KEY_SELECT",106:"KEY_NUM_PAD_ASTERISK",107:"KEY_NUM_PAD_PLUS_SIGN",109:"KEY_NUM_PAD_HYPHEN-MINUS",110:"KEY_NUM_PAD_FULL_STOP",111:"KEY_NUM_PAD_SOLIDUS",144:"KEY_NUM_LOCK",145:"KEY_SCROLL_LOCK",186:"KEY_SEMICOLON",187:"KEY_EQUALS_SIGN",188:"KEY_COMMA",189:"KEY_HYPHEN-MINUS",190:"KEY_FULL_STOP",191:"KEY_SOLIDUS",192:"KEY_GRAVE_ACCENT",219:"KEY_LEFT_SQUARE_BRACKET",220:"KEY_REVERSE_SOLIDUS",221:"KEY_RIGHT_SQUARE_BRACKET",222:"KEY_APOSTROPHE"};
+(function(){
+var _288=MochiKit.Signal._specialKeys;
+for(var i=48;i<=57;i++){
+_288[i]="KEY_"+(i-48);
+}
+for(i=65;i<=90;i++){
+_288[i]="KEY_"+String.fromCharCode(i);
+}
+for(i=96;i<=105;i++){
+_288[i]="KEY_NUM_PAD_"+(i-96);
+}
+for(i=112;i<=123;i++){
+_288[i]="KEY_F"+(i-112+1);
+}
+})();
+MochiKit.Signal.Ident=function(_28a){
+this.source=_28a.source;
+this.signal=_28a.signal;
+this.listener=_28a.listener;
+this.isDOM=_28a.isDOM;
+this.objOrFunc=_28a.objOrFunc;
+this.funcOrStr=_28a.funcOrStr;
+this.connected=_28a.connected;
+};
+MochiKit.Signal.Ident.prototype={};
+MochiKit.Base.update(MochiKit.Signal,{__repr__:function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+},toString:function(){
+return this.__repr__();
+},_unloadCache:function(){
+var self=MochiKit.Signal;
+var _28c=self._observers;
+for(var i=0;i<_28c.length;i++){
+if(_28c[i].signal!=="onload"&&_28c[i].signal!=="onunload"){
+self._disconnect(_28c[i]);
+}
+}
+},_listener:function(src,sig,func,obj,_292){
+var self=MochiKit.Signal;
+var E=self.Event;
+if(!_292){
+return MochiKit.Base.bind(func,obj);
+}
+obj=obj||src;
+if(typeof (func)=="string"){
+if(sig==="onload"||sig==="onunload"){
+return function(_295){
+obj[func].apply(obj,[new E(src,_295)]);
+var _296=new MochiKit.Signal.Ident({source:src,signal:sig,objOrFunc:obj,funcOrStr:func});
+MochiKit.Signal._disconnect(_296);
+};
+}else{
+return function(_297){
+obj[func].apply(obj,[new E(src,_297)]);
+};
+}
+}else{
+if(sig==="onload"||sig==="onunload"){
+return function(_298){
+func.apply(obj,[new E(src,_298)]);
+MochiKit.Signal.disconnect(src,sig,func);
+var _299=new MochiKit.Signal.Ident({source:src,signal:sig,objOrFunc:func});
+MochiKit.Signal._disconnect(_299);
+};
+}else{
+return function(_29a){
+func.apply(obj,[new E(src,_29a)]);
+};
+}
+}
+},_browserAlreadyHasMouseEnterAndLeave:function(){
+return /MSIE/.test(navigator.userAgent);
+},_mouseEnterListener:function(src,sig,func,obj){
+var E=MochiKit.Signal.Event;
+return function(_2a0){
+var e=new E(src,_2a0);
+try{
+e.relatedTarget().nodeName;
+}
+catch(err){
+return;
+}
+e.stop();
+if(MochiKit.DOM.isChildNode(e.relatedTarget(),src)){
+return;
+}
+e.type=function(){
+return sig;
+};
+if(typeof (func)=="string"){
+return obj[func].apply(obj,[e]);
+}else{
+return func.apply(obj,[e]);
+}
+};
+},_getDestPair:function(_2a2,_2a3){
+var obj=null;
+var func=null;
+if(typeof (_2a3)!="undefined"){
+obj=_2a2;
+func=_2a3;
+if(typeof (_2a3)=="string"){
+if(typeof (_2a2[_2a3])!="function"){
+throw new Error("'funcOrStr' must be a function on 'objOrFunc'");
+}
+}else{
+if(typeof (_2a3)!="function"){
+throw new Error("'funcOrStr' must be a function or string");
+}
+}
+}else{
+if(typeof (_2a2)!="function"){
+throw new Error("'objOrFunc' must be a function if 'funcOrStr' is not given");
+}else{
+func=_2a2;
+}
+}
+return [obj,func];
+},connect:function(src,sig,_2a8,_2a9){
+src=MochiKit.DOM.getElement(src);
+var self=MochiKit.Signal;
+if(typeof (sig)!="string"){
+throw new Error("'sig' must be a string");
+}
+var _2ab=self._getDestPair(_2a8,_2a9);
+var obj=_2ab[0];
+var func=_2ab[1];
+if(typeof (obj)=="undefined"||obj===null){
+obj=src;
+}
+var _2ae=!!(src.addEventListener||src.attachEvent);
+if(_2ae&&(sig==="onmouseenter"||sig==="onmouseleave")&&!self._browserAlreadyHasMouseEnterAndLeave()){
+var _2af=self._mouseEnterListener(src,sig.substr(2),func,obj);
+if(sig==="onmouseenter"){
+sig="onmouseover";
+}else{
+sig="onmouseout";
+}
+}else{
+var _2af=self._listener(src,sig,func,obj,_2ae);
+}
+if(src.addEventListener){
+src.addEventListener(sig.substr(2),_2af,false);
+}else{
+if(src.attachEvent){
+src.attachEvent(sig,_2af);
+}
+}
+var _2b0=new MochiKit.Signal.Ident({source:src,signal:sig,listener:_2af,isDOM:_2ae,objOrFunc:_2a8,funcOrStr:_2a9,connected:true});
+self._observers.push(_2b0);
+if(!_2ae&&typeof (src.__connect__)=="function"){
+var args=MochiKit.Base.extend([_2b0],arguments,1);
+src.__connect__.apply(src,args);
+}
+return _2b0;
+},_disconnect:function(_2b2){
+if(!_2b2.connected){
+return;
+}
+_2b2.connected=false;
+if(!_2b2.isDOM){
+return;
+}
+var src=_2b2.source;
+var sig=_2b2.signal;
+var _2b5=_2b2.listener;
+if(src.removeEventListener){
+src.removeEventListener(sig.substr(2),_2b5,false);
+}else{
+if(src.detachEvent){
+src.detachEvent(sig,_2b5);
+}else{
+throw new Error("'src' must be a DOM element");
+}
+}
+},disconnect:function(_2b6){
+var self=MochiKit.Signal;
+var _2b8=self._observers;
+var m=MochiKit.Base;
+if(arguments.length>1){
+var src=MochiKit.DOM.getElement(arguments[0]);
+var sig=arguments[1];
+var obj=arguments[2];
+var func=arguments[3];
+for(var i=_2b8.length-1;i>=0;i--){
+var o=_2b8[i];
+if(o.source===src&&o.signal===sig&&o.objOrFunc===obj&&o.funcOrStr===func){
+self._disconnect(o);
+if(!self._lock){
+_2b8.splice(i,1);
+}else{
+self._dirty=true;
+}
+return true;
+}
+}
+}else{
+var idx=m.findIdentical(_2b8,_2b6);
+if(idx>=0){
+self._disconnect(_2b6);
+if(!self._lock){
+_2b8.splice(idx,1);
+}else{
+self._dirty=true;
+}
+return true;
+}
+}
+return false;
+},disconnectAllTo:function(_2c1,_2c2){
+var self=MochiKit.Signal;
+var _2c4=self._observers;
+var _2c5=self._disconnect;
+var _2c6=self._lock;
+var _2c7=self._dirty;
+if(typeof (_2c2)==="undefined"){
+_2c2=null;
+}
+for(var i=_2c4.length-1;i>=0;i--){
+var _2c9=_2c4[i];
+if(_2c9.objOrFunc===_2c1&&(_2c2===null||_2c9.funcOrStr===_2c2)){
+_2c5(_2c9);
+if(_2c6){
+_2c7=true;
+}else{
+_2c4.splice(i,1);
+}
+}
+}
+self._dirty=_2c7;
+},disconnectAll:function(src,sig){
+src=MochiKit.DOM.getElement(src);
+var m=MochiKit.Base;
+var _2cd=m.flattenArguments(m.extend(null,arguments,1));
+var self=MochiKit.Signal;
+var _2cf=self._disconnect;
+var _2d0=self._observers;
+var i,_2d2;
+var _2d3=self._lock;
+var _2d4=self._dirty;
+if(_2cd.length===0){
+for(i=_2d0.length-1;i>=0;i--){
+_2d2=_2d0[i];
+if(_2d2.source===src){
+_2cf(_2d2);
+if(!_2d3){
+_2d0.splice(i,1);
+}else{
+_2d4=true;
+}
+}
+}
+}else{
+var sigs={};
+for(i=0;i<_2cd.length;i++){
+sigs[_2cd[i]]=true;
+}
+for(i=_2d0.length-1;i>=0;i--){
+_2d2=_2d0[i];
+if(_2d2.source===src&&_2d2.signal in sigs){
+_2cf(_2d2);
+if(!_2d3){
+_2d0.splice(i,1);
+}else{
+_2d4=true;
+}
+}
+}
+}
+self._dirty=_2d4;
+},signal:function(src,sig){
+var self=MochiKit.Signal;
+var _2d9=self._observers;
+src=MochiKit.DOM.getElement(src);
+var args=MochiKit.Base.extend(null,arguments,2);
+var _2db=[];
+self._lock=true;
+for(var i=0;i<_2d9.length;i++){
+var _2dd=_2d9[i];
+if(_2dd.source===src&&_2dd.signal===sig&&_2dd.connected){
+try{
+_2dd.listener.apply(src,args);
+}
+catch(e){
+_2db.push(e);
+}
+}
+}
+self._lock=false;
+if(self._dirty){
+self._dirty=false;
+for(var i=_2d9.length-1;i>=0;i--){
+if(!_2d9[i].connected){
+_2d9.splice(i,1);
+}
+}
+}
+if(_2db.length==1){
+throw _2db[0];
+}else{
+if(_2db.length>1){
+var e=new Error("Multiple errors thrown in handling 'sig', see errors property");
+e.errors=_2db;
+throw e;
+}
+}
+}});
+MochiKit.Signal.EXPORT_OK=[];
+MochiKit.Signal.EXPORT=["connect","disconnect","signal","disconnectAll","disconnectAllTo"];
+MochiKit.Signal.__new__=function(win){
+var m=MochiKit.Base;
+this._document=document;
+this._window=win;
+this._lock=false;
+this._dirty=false;
+try{
+this.connect(window,"onunload",this._unloadCache);
+}
+catch(e){
+}
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+m.nameFunctions(this);
+};
+MochiKit.Signal.__new__(this);
+if(MochiKit.__export__){
+connect=MochiKit.Signal.connect;
+disconnect=MochiKit.Signal.disconnect;
+disconnectAll=MochiKit.Signal.disconnectAll;
+signal=MochiKit.Signal.signal;
+}
+MochiKit.Base._exportSymbols(this,MochiKit.Signal);
+if(typeof (dojo)!="undefined"){
+dojo.provide("MochiKit.Iter");
+dojo.require("MochiKit.Base");
+}
+if(typeof (JSAN)!="undefined"){
+JSAN.use("MochiKit.Base",[]);
+}
+try{
+if(typeof (MochiKit.Base)=="undefined"){
+throw "";
+}
+}
+catch(e){
+throw "MochiKit.Iter depends on MochiKit.Base!";
+}
+if(typeof (MochiKit.Iter)=="undefined"){
+MochiKit.Iter={};
+}
+MochiKit.Iter.NAME="MochiKit.Iter";
+MochiKit.Iter.VERSION="1.4";
+MochiKit.Base.update(MochiKit.Iter,{__repr__:function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+},toString:function(){
+return this.__repr__();
+},registerIteratorFactory:function(name,_2e2,_2e3,_2e4){
+MochiKit.Iter.iteratorRegistry.register(name,_2e2,_2e3,_2e4);
+},iter:function(_2e5,_2e6){
+var self=MochiKit.Iter;
+if(arguments.length==2){
+return self.takewhile(function(a){
+return a!=_2e6;
+},_2e5);
+}
+if(typeof (_2e5.next)=="function"){
+return _2e5;
+}else{
+if(typeof (_2e5.iter)=="function"){
+return _2e5.iter();
+}
+}
+try{
+return self.iteratorRegistry.match(_2e5);
+}
+catch(e){
+var m=MochiKit.Base;
+if(e==m.NotFound){
+e=new TypeError(typeof (_2e5)+": "+m.repr(_2e5)+" is not iterable");
+}
+throw e;
+}
+},count:function(n){
+if(!n){
+n=0;
+}
+var m=MochiKit.Base;
+return {repr:function(){
+return "count("+n+")";
+},toString:m.forwardCall("repr"),next:m.counter(n)};
+},cycle:function(p){
+var self=MochiKit.Iter;
+var m=MochiKit.Base;
+var lst=[];
+var _2f0=self.iter(p);
+return {repr:function(){
+return "cycle(...)";
+},toString:m.forwardCall("repr"),next:function(){
+try{
+var rval=_2f0.next();
+lst.push(rval);
+return rval;
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+if(lst.length===0){
+this.next=function(){
+throw self.StopIteration;
+};
+}else{
+var i=-1;
+this.next=function(){
+i=(i+1)%lst.length;
+return lst[i];
+};
+}
+return this.next();
+}
+}};
+},repeat:function(elem,n){
+var m=MochiKit.Base;
+if(typeof (n)=="undefined"){
+return {repr:function(){
+return "repeat("+m.repr(elem)+")";
+},toString:m.forwardCall("repr"),next:function(){
+return elem;
+}};
+}
+return {repr:function(){
+return "repeat("+m.repr(elem)+", "+n+")";
+},toString:m.forwardCall("repr"),next:function(){
+if(n<=0){
+throw MochiKit.Iter.StopIteration;
+}
+n-=1;
+return elem;
+}};
+},next:function(_2f6){
+return _2f6.next();
+},izip:function(p,q){
+var m=MochiKit.Base;
+var self=MochiKit.Iter;
+var next=self.next;
+var _2fc=m.map(self.iter,arguments);
+return {repr:function(){
+return "izip(...)";
+},toString:m.forwardCall("repr"),next:function(){
+return m.map(next,_2fc);
+}};
+},ifilter:function(pred,seq){
+var m=MochiKit.Base;
+seq=MochiKit.Iter.iter(seq);
+if(pred===null){
+pred=m.operator.truth;
+}
+return {repr:function(){
+return "ifilter(...)";
+},toString:m.forwardCall("repr"),next:function(){
+while(true){
+var rval=seq.next();
+if(pred(rval)){
+return rval;
+}
+}
+return undefined;
+}};
+},ifilterfalse:function(pred,seq){
+var m=MochiKit.Base;
+seq=MochiKit.Iter.iter(seq);
+if(pred===null){
+pred=m.operator.truth;
+}
+return {repr:function(){
+return "ifilterfalse(...)";
+},toString:m.forwardCall("repr"),next:function(){
+while(true){
+var rval=seq.next();
+if(!pred(rval)){
+return rval;
+}
+}
+return undefined;
+}};
+},islice:function(seq){
+var self=MochiKit.Iter;
+var m=MochiKit.Base;
+seq=self.iter(seq);
+var _308=0;
+var stop=0;
+var step=1;
+var i=-1;
+if(arguments.length==2){
+stop=arguments[1];
+}else{
+if(arguments.length==3){
+_308=arguments[1];
+stop=arguments[2];
+}else{
+_308=arguments[1];
+stop=arguments[2];
+step=arguments[3];
+}
+}
+return {repr:function(){
+return "islice("+["...",_308,stop,step].join(", ")+")";
+},toString:m.forwardCall("repr"),next:function(){
+var rval;
+while(i<_308){
+rval=seq.next();
+i++;
+}
+if(_308>=stop){
+throw self.StopIteration;
+}
+_308+=step;
+return rval;
+}};
+},imap:function(fun,p,q){
+var m=MochiKit.Base;
+var self=MochiKit.Iter;
+var _312=m.map(self.iter,m.extend(null,arguments,1));
+var map=m.map;
+var next=self.next;
+return {repr:function(){
+return "imap(...)";
+},toString:m.forwardCall("repr"),next:function(){
+return fun.apply(this,map(next,_312));
+}};
+},applymap:function(fun,seq,self){
+seq=MochiKit.Iter.iter(seq);
+var m=MochiKit.Base;
+return {repr:function(){
+return "applymap(...)";
+},toString:m.forwardCall("repr"),next:function(){
+return fun.apply(self,seq.next());
+}};
+},chain:function(p,q){
+var self=MochiKit.Iter;
+var m=MochiKit.Base;
+if(arguments.length==1){
+return self.iter(arguments[0]);
+}
+var _31d=m.map(self.iter,arguments);
+return {repr:function(){
+return "chain(...)";
+},toString:m.forwardCall("repr"),next:function(){
+while(_31d.length>1){
+try{
+return _31d[0].next();
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+_31d.shift();
+}
+}
+if(_31d.length==1){
+var arg=_31d.shift();
+this.next=m.bind("next",arg);
+return this.next();
+}
+throw self.StopIteration;
+}};
+},takewhile:function(pred,seq){
+var self=MochiKit.Iter;
+seq=self.iter(seq);
+return {repr:function(){
+return "takewhile(...)";
+},toString:MochiKit.Base.forwardCall("repr"),next:function(){
+var rval=seq.next();
+if(!pred(rval)){
+this.next=function(){
+throw self.StopIteration;
+};
+this.next();
+}
+return rval;
+}};
+},dropwhile:function(pred,seq){
+seq=MochiKit.Iter.iter(seq);
+var m=MochiKit.Base;
+var bind=m.bind;
+return {"repr":function(){
+return "dropwhile(...)";
+},"toString":m.forwardCall("repr"),"next":function(){
+while(true){
+var rval=seq.next();
+if(!pred(rval)){
+break;
+}
+}
+this.next=bind("next",seq);
+return rval;
+}};
+},_tee:function(_328,sync,_32a){
+sync.pos[_328]=-1;
+var m=MochiKit.Base;
+var _32c=m.listMin;
+return {repr:function(){
+return "tee("+_328+", ...)";
+},toString:m.forwardCall("repr"),next:function(){
+var rval;
+var i=sync.pos[_328];
+if(i==sync.max){
+rval=_32a.next();
+sync.deque.push(rval);
+sync.max+=1;
+sync.pos[_328]+=1;
+}else{
+rval=sync.deque[i-sync.min];
+sync.pos[_328]+=1;
+if(i==sync.min&&_32c(sync.pos)!=sync.min){
+sync.min+=1;
+sync.deque.shift();
+}
+}
+return rval;
+}};
+},tee:function(_32f,n){
+var rval=[];
+var sync={"pos":[],"deque":[],"max":-1,"min":-1};
+if(arguments.length==1||typeof (n)=="undefined"||n===null){
+n=2;
+}
+var self=MochiKit.Iter;
+_32f=self.iter(_32f);
+var _tee=self._tee;
+for(var i=0;i<n;i++){
+rval.push(_tee(i,sync,_32f));
+}
+return rval;
+},list:function(_336){
+var rval;
+if(_336 instanceof Array){
+return _336.slice();
+}
+if(typeof (_336)=="function"&&!(_336 instanceof Function)&&typeof (_336.length)=="number"){
+rval=[];
+for(var i=0;i<_336.length;i++){
+rval.push(_336[i]);
+}
+return rval;
+}
+var self=MochiKit.Iter;
+_336=self.iter(_336);
+var rval=[];
+try{
+while(true){
+rval.push(_336.next());
+}
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+return rval;
+}
+return undefined;
+},reduce:function(fn,_33b,_33c){
+var i=0;
+var x=_33c;
+var self=MochiKit.Iter;
+_33b=self.iter(_33b);
+if(arguments.length<3){
+try{
+x=_33b.next();
+}
+catch(e){
+if(e==self.StopIteration){
+e=new TypeError("reduce() of empty sequence with no initial value");
+}
+throw e;
+}
+i++;
+}
+try{
+while(true){
+x=fn(x,_33b.next());
+}
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+}
+return x;
+},range:function(){
+var _340=0;
+var stop=0;
+var step=1;
+if(arguments.length==1){
+stop=arguments[0];
+}else{
+if(arguments.length==2){
+_340=arguments[0];
+stop=arguments[1];
+}else{
+if(arguments.length==3){
+_340=arguments[0];
+stop=arguments[1];
+step=arguments[2];
+}else{
+throw new TypeError("range() takes 1, 2, or 3 arguments!");
+}
+}
+}
+if(step===0){
+throw new TypeError("range() step must not be 0");
+}
+return {next:function(){
+if((step>0&&_340>=stop)||(step<0&&_340<=stop)){
+throw MochiKit.Iter.StopIteration;
+}
+var rval=_340;
+_340+=step;
+return rval;
+},repr:function(){
+return "range("+[_340,stop,step].join(", ")+")";
+},toString:MochiKit.Base.forwardCall("repr")};
+},sum:function(_344,_345){
+if(typeof (_345)=="undefined"||_345===null){
+_345=0;
+}
+var x=_345;
+var self=MochiKit.Iter;
+_344=self.iter(_344);
+try{
+while(true){
+x+=_344.next();
+}
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+}
+return x;
+},exhaust:function(_348){
+var self=MochiKit.Iter;
+_348=self.iter(_348);
+try{
+while(true){
+_348.next();
+}
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+}
+},forEach:function(_34a,func,self){
+var m=MochiKit.Base;
+if(arguments.length>2){
+func=m.bind(func,self);
+}
+if(m.isArrayLike(_34a)){
+try{
+for(var i=0;i<_34a.length;i++){
+func(_34a[i]);
+}
+}
+catch(e){
+if(e!=MochiKit.Iter.StopIteration){
+throw e;
+}
+}
+}else{
+self=MochiKit.Iter;
+self.exhaust(self.imap(func,_34a));
+}
+},every:function(_34f,func){
+var self=MochiKit.Iter;
+try{
+self.ifilterfalse(func,_34f).next();
+return false;
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+return true;
+}
+},sorted:function(_352,cmp){
+var rval=MochiKit.Iter.list(_352);
+if(arguments.length==1){
+cmp=MochiKit.Base.compare;
+}
+rval.sort(cmp);
+return rval;
+},reversed:function(_355){
+var rval=MochiKit.Iter.list(_355);
+rval.reverse();
+return rval;
+},some:function(_357,func){
+var self=MochiKit.Iter;
+try{
+self.ifilter(func,_357).next();
+return true;
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+return false;
+}
+},iextend:function(lst,_35b){
+if(MochiKit.Base.isArrayLike(_35b)){
+for(var i=0;i<_35b.length;i++){
+lst.push(_35b[i]);
+}
+}else{
+var self=MochiKit.Iter;
+_35b=self.iter(_35b);
+try{
+while(true){
+lst.push(_35b.next());
+}
+}
+catch(e){
+if(e!=self.StopIteration){
+throw e;
+}
+}
+}
+return lst;
+},groupby:function(_35e,_35f){
+var m=MochiKit.Base;
+var self=MochiKit.Iter;
+if(arguments.length<2){
+_35f=m.operator.identity;
+}
+_35e=self.iter(_35e);
+var pk=undefined;
+var k=undefined;
+var v;
+function fetch(){
+v=_35e.next();
+k=_35f(v);
+}
+function eat(){
+var ret=v;
+v=undefined;
+return ret;
+}
+var _366=true;
+var _367=m.compare;
+return {repr:function(){
+return "groupby(...)";
+},next:function(){
+while(_367(k,pk)===0){
+fetch();
+if(_366){
+_366=false;
+break;
+}
+}
+pk=k;
+return [k,{next:function(){
+if(v==undefined){
+fetch();
+}
+if(_367(k,pk)!==0){
+throw self.StopIteration;
+}
+return eat();
+}}];
+}};
+},groupby_as_array:function(_368,_369){
+var m=MochiKit.Base;
+var self=MochiKit.Iter;
+if(arguments.length<2){
+_369=m.operator.identity;
+}
+_368=self.iter(_368);
+var _36c=[];
+var _36d=true;
+var _36e;
+var _36f=m.compare;
+while(true){
+try{
+var _370=_368.next();
+var key=_369(_370);
+}
+catch(e){
+if(e==self.StopIteration){
+break;
+}
+throw e;
+}
+if(_36d||_36f(key,_36e)!==0){
+var _372=[];
+_36c.push([key,_372]);
+}
+_372.push(_370);
+_36d=false;
+_36e=key;
+}
+return _36c;
+},arrayLikeIter:function(_373){
+var i=0;
+return {repr:function(){
+return "arrayLikeIter(...)";
+},toString:MochiKit.Base.forwardCall("repr"),next:function(){
+if(i>=_373.length){
+throw MochiKit.Iter.StopIteration;
+}
+return _373[i++];
+}};
+},hasIterateNext:function(_375){
+return (_375&&typeof (_375.iterateNext)=="function");
+},iterateNextIter:function(_376){
+return {repr:function(){
+return "iterateNextIter(...)";
+},toString:MochiKit.Base.forwardCall("repr"),next:function(){
+var rval=_376.iterateNext();
+if(rval===null||rval===undefined){
+throw MochiKit.Iter.StopIteration;
+}
+return rval;
+}};
+}});
+MochiKit.Iter.EXPORT_OK=["iteratorRegistry","arrayLikeIter","hasIterateNext","iterateNextIter",];
+MochiKit.Iter.EXPORT=["StopIteration","registerIteratorFactory","iter","count","cycle","repeat","next","izip","ifilter","ifilterfalse","islice","imap","applymap","chain","takewhile","dropwhile","tee","list","reduce","range","sum","exhaust","forEach","every","sorted","reversed","some","iextend","groupby","groupby_as_array"];
+MochiKit.Iter.__new__=function(){
+var m=MochiKit.Base;
+if(typeof (StopIteration)!="undefined"){
+this.StopIteration=StopIteration;
+}else{
+this.StopIteration=new m.NamedError("StopIteration");
+}
+this.iteratorRegistry=new m.AdapterRegistry();
+this.registerIteratorFactory("arrayLike",m.isArrayLike,this.arrayLikeIter);
+this.registerIteratorFactory("iterateNext",this.hasIterateNext,this.iterateNextIter);
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+m.nameFunctions(this);
+};
+MochiKit.Iter.__new__();
+if(MochiKit.__export__){
+reduce=MochiKit.Iter.reduce;
+}
+MochiKit.Base._exportSymbols(this,MochiKit.Iter);
+if(typeof (dojo)!="undefined"){
+dojo.provide("MochiKit.Async");
+dojo.require("MochiKit.Base");
+}
+if(typeof (JSAN)!="undefined"){
+JSAN.use("MochiKit.Base",[]);
+}
+try{
+if(typeof (MochiKit.Base)=="undefined"){
+throw "";
+}
+}
+catch(e){
+throw "MochiKit.Async depends on MochiKit.Base!";
+}
+if(typeof (MochiKit.Async)=="undefined"){
+MochiKit.Async={};
+}
+MochiKit.Async.NAME="MochiKit.Async";
+MochiKit.Async.VERSION="1.4";
+MochiKit.Async.__repr__=function(){
+return "["+this.NAME+" "+this.VERSION+"]";
+};
+MochiKit.Async.toString=function(){
+return this.__repr__();
+};
+MochiKit.Async.Deferred=function(_379){
+this.chain=[];
+this.id=this._nextId();
+this.fired=-1;
+this.paused=0;
+this.results=[null,null];
+this.canceller=_379;
+this.silentlyCancelled=false;
+this.chained=false;
+};
+MochiKit.Async.Deferred.prototype={repr:function(){
+var _37a;
+if(this.fired==-1){
+_37a="unfired";
+}else{
+if(this.fired===0){
+_37a="success";
+}else{
+_37a="error";
+}
+}
+return "Deferred("+this.id+", "+_37a+")";
+},toString:MochiKit.Base.forwardCall("repr"),_nextId:MochiKit.Base.counter(),cancel:function(){
+var self=MochiKit.Async;
+if(this.fired==-1){
+if(this.canceller){
+this.canceller(this);
+}else{
+this.silentlyCancelled=true;
+}
+if(this.fired==-1){
+this.errback(new self.CancelledError(this));
+}
+}else{
+if((this.fired===0)&&(this.results[0] instanceof self.Deferred)){
+this.results[0].cancel();
+}
+}
+},_resback:function(res){
+this.fired=((res instanceof Error)?1:0);
+this.results[this.fired]=res;
+this._fire();
+},_check:function(){
+if(this.fired!=-1){
+if(!this.silentlyCancelled){
+throw new MochiKit.Async.AlreadyCalledError(this);
+}
+this.silentlyCancelled=false;
+return;
+}
+},callback:function(res){
+this._check();
+if(res instanceof MochiKit.Async.Deferred){
+throw new Error("Deferred instances can only be chained if they are the result of a callback");
+}
+this._resback(res);
+},errback:function(res){
+this._check();
+var self=MochiKit.Async;
+if(res instanceof self.Deferred){
+throw new Error("Deferred instances can only be chained if they are the result of a callback");
+}
+if(!(res instanceof Error)){
+res=new self.GenericError(res);
+}
+this._resback(res);
+},addBoth:function(fn){
+if(arguments.length>1){
+fn=MochiKit.Base.partial.apply(null,arguments);
+}
+return this.addCallbacks(fn,fn);
+},addCallback:function(fn){
+if(arguments.length>1){
+fn=MochiKit.Base.partial.apply(null,arguments);
+}
+return this.addCallbacks(fn,null);
+},addErrback:function(fn){
+if(arguments.length>1){
+fn=MochiKit.Base.partial.apply(null,arguments);
+}
+return this.addCallbacks(null,fn);
+},addCallbacks:function(cb,eb){
+if(this.chained){
+throw new Error("Chained Deferreds can not be re-used");
+}
+this.chain.push([cb,eb]);
+if(this.fired>=0){
+this._fire();
+}
+return this;
+},_fire:function(){
+var _385=this.chain;
+var _386=this.fired;
+var res=this.results[_386];
+var self=this;
+var cb=null;
+while(_385.length>0&&this.paused===0){
+var pair=_385.shift();
+var f=pair[_386];
+if(f===null){
+continue;
+}
+try{
+res=f(res);
+_386=((res instanceof Error)?1:0);
+if(res instanceof MochiKit.Async.Deferred){
+cb=function(res){
+self._resback(res);
+self.paused--;
+if((self.paused===0)&&(self.fired>=0)){
+self._fire();
+}
+};
+this.paused++;
+}
+}
+catch(err){
+_386=1;
+if(!(err instanceof Error)){
+err=new MochiKit.Async.GenericError(err);
+}
+res=err;
+}
+}
+this.fired=_386;
+this.results[_386]=res;
+if(cb&&this.paused){
+res.addBoth(cb);
+res.chained=true;
+}
+}};
+MochiKit.Base.update(MochiKit.Async,{evalJSONRequest:function(req){
+return MochiKit.Base.evalJSON(req.responseText);
+},succeed:function(_38e){
+var d=new MochiKit.Async.Deferred();
+d.callback.apply(d,arguments);
+return d;
+},fail:function(_390){
+var d=new MochiKit.Async.Deferred();
+d.errback.apply(d,arguments);
+return d;
+},getXMLHttpRequest:function(){
+var self=arguments.callee;
+if(!self.XMLHttpRequest){
+var _393=[function(){
+return new XMLHttpRequest();
+},function(){
+return new ActiveXObject("Msxml2.XMLHTTP");
+},function(){
+return new ActiveXObject("Microsoft.XMLHTTP");
+},function(){
+return new ActiveXObject("Msxml2.XMLHTTP.4.0");
+},function(){
+throw new MochiKit.Async.BrowserComplianceError("Browser does not support XMLHttpRequest");
+}];
+for(var i=0;i<_393.length;i++){
+var func=_393[i];
+try{
+self.XMLHttpRequest=func;
+return func();
+}
+catch(e){
+}
+}
+}
+return self.XMLHttpRequest();
+},_xhr_onreadystatechange:function(d){
+var m=MochiKit.Base;
+if(this.readyState==4){
+try{
+this.onreadystatechange=null;
+}
+catch(e){
+try{
+this.onreadystatechange=m.noop;
+}
+catch(e){
+}
+}
+var _398=null;
+try{
+_398=this.status;
+if(!_398&&m.isNotEmpty(this.responseText)){
+_398=304;
+}
+}
+catch(e){
+}
+if(_398==200||_398==201||_398==204||_398==304||_398==1223){
+d.callback(this);
+}else{
+var err=new MochiKit.Async.XMLHttpRequestError(this,"Request failed");
+if(err.number){
+d.errback(err);
+}else{
+d.errback(err);
+}
+}
+}
+},_xhr_canceller:function(req){
+try{
+req.onreadystatechange=null;
+}
+catch(e){
+try{
+req.onreadystatechange=MochiKit.Base.noop;
+}
+catch(e){
+}
+}
+req.abort();
+},sendXMLHttpRequest:function(req,_39c){
+if(typeof (_39c)=="undefined"||_39c===null){
+_39c="";
+}
+var m=MochiKit.Base;
+var self=MochiKit.Async;
+var d=new self.Deferred(m.partial(self._xhr_canceller,req));
+try{
+req.onreadystatechange=m.bind(self._xhr_onreadystatechange,req,d);
+req.send(_39c);
+}
+catch(e){
+try{
+req.onreadystatechange=null;
+}
+catch(ignore){
+}
+d.errback(e);
+}
+return d;
+},doXHR:function(url,opts){
+var self=MochiKit.Async;
+return self.callLater(0,self._doXHR,url,opts);
+},_doXHR:function(url,opts){
+var m=MochiKit.Base;
+opts=m.update({method:"GET",sendContent:""},opts);
+var self=MochiKit.Async;
+var req=self.getXMLHttpRequest();
+if(opts.queryString){
+var qs=m.queryString(opts.queryString);
+if(qs){
+url+="?"+qs;
+}
+}
+if("username" in opts){
+req.open(opts.method,url,true,opts.username,opts.password);
+}else{
+req.open(opts.method,url,true);
+}
+if(req.overrideMimeType&&opts.mimeType){
+req.overrideMimeType(opts.mimeType);
+}
+if(opts.headers){
+var _3a9=opts.headers;
+if(!m.isArrayLike(_3a9)){
+_3a9=m.items(_3a9);
+}
+for(var i=0;i<_3a9.length;i++){
+var _3ab=_3a9[i];
+var name=_3ab[0];
+var _3ad=_3ab[1];
+req.setRequestHeader(name,_3ad);
+}
+}
+return self.sendXMLHttpRequest(req,opts.sendContent);
+},_buildURL:function(url){
+if(arguments.length>1){
+var m=MochiKit.Base;
+var qs=m.queryString.apply(null,m.extend(null,arguments,1));
+if(qs){
+return url+"?"+qs;
+}
+}
+return url;
+},doSimpleXMLHttpRequest:function(url){
+var self=MochiKit.Async;
+url=self._buildURL.apply(self,arguments);
+return self.doXHR(url);
+},loadJSONDoc:function(url){
+var self=MochiKit.Async;
+url=self._buildURL.apply(self,arguments);
+var d=self.doXHR(url,{"mimeType":"text/plain","headers":[["Accept","application/json"]]});
+d=d.addCallback(self.evalJSONRequest);
+return d;
+},wait:function(_3b6,_3b7){
+var d=new MochiKit.Async.Deferred();
+var m=MochiKit.Base;
+if(typeof (_3b7)!="undefined"){
+d.addCallback(function(){
+return _3b7;
+});
+}
+var _3ba=setTimeout(m.bind("callback",d),Math.floor(_3b6*1000));
+d.canceller=function(){
+try{
+clearTimeout(_3ba);
+}
+catch(e){
+}
+};
+return d;
+},callLater:function(_3bb,func){
+var m=MochiKit.Base;
+var _3be=m.partial.apply(m,m.extend(null,arguments,1));
+return MochiKit.Async.wait(_3bb).addCallback(function(res){
+return _3be();
+});
+}});
+MochiKit.Async.DeferredLock=function(){
+this.waiting=[];
+this.locked=false;
+this.id=this._nextId();
+};
+MochiKit.Async.DeferredLock.prototype={__class__:MochiKit.Async.DeferredLock,acquire:function(){
+var d=new MochiKit.Async.Deferred();
+if(this.locked){
+this.waiting.push(d);
+}else{
+this.locked=true;
+d.callback(this);
+}
+return d;
+},release:function(){
+if(!this.locked){
+throw TypeError("Tried to release an unlocked DeferredLock");
+}
+this.locked=false;
+if(this.waiting.length>0){
+this.locked=true;
+this.waiting.shift().callback(this);
+}
+},_nextId:MochiKit.Base.counter(),repr:function(){
+var _3c1;
+if(this.locked){
+_3c1="locked, "+this.waiting.length+" waiting";
+}else{
+_3c1="unlocked";
+}
+return "DeferredLock("+this.id+", "+_3c1+")";
+},toString:MochiKit.Base.forwardCall("repr")};
+MochiKit.Async.DeferredList=function(list,_3c3,_3c4,_3c5,_3c6){
+MochiKit.Async.Deferred.apply(this,[_3c6]);
+this.list=list;
+var _3c7=[];
+this.resultList=_3c7;
+this.finishedCount=0;
+this.fireOnOneCallback=_3c3;
+this.fireOnOneErrback=_3c4;
+this.consumeErrors=_3c5;
+var cb=MochiKit.Base.bind(this._cbDeferred,this);
+for(var i=0;i<list.length;i++){
+var d=list[i];
+_3c7.push(undefined);
+d.addCallback(cb,i,true);
+d.addErrback(cb,i,false);
+}
+if(list.length===0&&!_3c3){
+this.callback(this.resultList);
+}
+};
+MochiKit.Async.DeferredList.prototype=new MochiKit.Async.Deferred();
+MochiKit.Async.DeferredList.prototype._cbDeferred=function(_3cb,_3cc,_3cd){
+this.resultList[_3cb]=[_3cc,_3cd];
+this.finishedCount+=1;
+if(this.fired==-1){
+if(_3cc&&this.fireOnOneCallback){
+this.callback([_3cb,_3cd]);
+}else{
+if(!_3cc&&this.fireOnOneErrback){
+this.errback(_3cd);
+}else{
+if(this.finishedCount==this.list.length){
+this.callback(this.resultList);
+}
+}
+}
+}
+if(!_3cc&&this.consumeErrors){
+_3cd=null;
+}
+return _3cd;
+};
+MochiKit.Async.gatherResults=function(_3ce){
+var d=new MochiKit.Async.DeferredList(_3ce,false,true,false);
+d.addCallback(function(_3d0){
+var ret=[];
+for(var i=0;i<_3d0.length;i++){
+ret.push(_3d0[i][1]);
+}
+return ret;
+});
+return d;
+};
+MochiKit.Async.maybeDeferred=function(func){
+var self=MochiKit.Async;
+var _3d5;
+try{
+var r=func.apply(null,MochiKit.Base.extend([],arguments,1));
+if(r instanceof self.Deferred){
+_3d5=r;
+}else{
+if(r instanceof Error){
+_3d5=self.fail(r);
+}else{
+_3d5=self.succeed(r);
+}
+}
+}
+catch(e){
+_3d5=self.fail(e);
+}
+return _3d5;
+};
+MochiKit.Async.EXPORT=["AlreadyCalledError","CancelledError","BrowserComplianceError","GenericError","XMLHttpRequestError","Deferred","succeed","fail","getXMLHttpRequest","doSimpleXMLHttpRequest","loadJSONDoc","wait","callLater","sendXMLHttpRequest","DeferredLock","DeferredList","gatherResults","maybeDeferred","doXHR"];
+MochiKit.Async.EXPORT_OK=["evalJSONRequest"];
+MochiKit.Async.__new__=function(){
+var m=MochiKit.Base;
+var ne=m.partial(m._newNamedError,this);
+ne("AlreadyCalledError",function(_3d9){
+this.deferred=_3d9;
+});
+ne("CancelledError",function(_3da){
+this.deferred=_3da;
+});
+ne("BrowserComplianceError",function(msg){
+this.message=msg;
+});
+ne("GenericError",function(msg){
+this.message=msg;
+});
+ne("XMLHttpRequestError",function(req,msg){
+this.req=req;
+this.message=msg;
+try{
+this.number=req.status;
+}
+catch(e){
+}
+});
+this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
+m.nameFunctions(this);
+};
+MochiKit.Async.__new__();
+MochiKit.Base._exportSymbols(this,MochiKit.Async);
+
+
diff --git a/typo3/sysext/t3editor/jslib/parsejavascript.js b/typo3/sysext/t3editor/jslib/parsejavascript.js
new file mode 100644 (file)
index 0000000..fde545a
--- /dev/null
@@ -0,0 +1,340 @@
+/* JavaScript parser
+ *
+ * A parser that can be plugged into the CodeMirror system has to
+ * implement the following interface: It is a function that, when
+ * called with a string stream (stringstream.js) as an argument,
+ * returns a MochiKit-style iterator (object with a 'next' method).
+ * This iterator, when called, consumes some input from the string
+ * stream, and returns a token object. Token objects must have a
+ * 'value' property (the text they represent), a 'style' property (the
+ * CSS style that should be used to colour them). Tokens for newline
+ * characters must also have a 'lexicalContext' property, which has an
+ * 'indentation' method that can be used to determine the proper
+ * indentation level for the next line. This method optionally takes
+ * the first character of the next line as an argument, which it can
+ * use to adjust the indentation level.
+ *
+ * So far this should be easy. The hard part is that the iterator
+ * produced by the parse function must also have a 'copy' method. This
+ * method, called without arguments, returns a function representing
+ * the current state of the parser. When this function is later called
+ * with a string stream as its argument, it returns a parser iterator
+ * object that resumes parsing using the old state and the new input
+ * stream. It may assume that only one parser is active at a time, and
+ * clobber the state of the old parser (the implementation below
+ * certianly does).
+ */
+
+// 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.
+var parseJavaScript = function() {
+  // Token types that can be considered to be atoms.
+  var atomicTypes = setObject("atom", "number", "variable", "string", "regexp");  
+
+  // 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), '[', '{', 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.
+  JSLexical.prototype.indentation = function(firstChar) {
+    var closing = firstChar == this.type;
+    if (this.type == "vardef")
+      return this.indented + 4;
+    if (this.type == "stat")
+      return this.indented + 2;
+    else if (this.align)
+      return this.column - (closing ? 1 : 0);
+    else
+      return this.indented + (closing ? 0 : 2);
+  }
+
+  // The parser-iterator-producing function itself.
+  return function(input){
+    // 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(-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.type == "newline"){
+        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 a lexical context associated with them,
+       // which is used for indentation.
+        token.lexicalContext = lexical;
+      }
+      // No more processing for meaningless tokens.
+      if (token.type == "whitespace" || token.type == "newline" || 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. Marked is used to 
+      while(true){
+        consume = marked = false;
+       // Take and execute the topmost action.
+        cc.pop()(token.type, token.name);
+        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.name))
+            token.style = "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([]), _regexp = tokens.regexp, _comment = tokens.inComment;
+  
+      return function(input){
+        context = _context;
+        lexical = _lexical;
+        cc = _cc.concat([]); // copies the array
+        column = indented = 0;
+        tokens = tokenizeJavaScript(input);
+        tokens.regexp = _regexp;
+        tokens.inComment = _comment;
+        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 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("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(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("stat"), expression, statement, poplex);
+      else if (type == "keyword b") cont(pushlex("stat"), statement, poplex);
+      else if (type == "{") cont(pushlex("}"), block, poplex);
+      else if (type == "function") cont(functiondef);
+      else if (type == "for") cont(pushlex("stat"), expect("("), pushlex(")"), forspec1, expect(")"), poplex, statement, poplex);
+      else if (type == "case") cont(expression, expect(":"));
+      else if (type == "variable") cont(pushlex("stat"), maybelabel);
+      else if (type == "catch") cont(pushlex("stat"), 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);
+      else if (type == ".") cont(property, maybeoperator);
+      else if (type == "[") cont(pushlex("]"), expression, expect("]"), poplex);
+    }
+    // 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 think they are variables.
+    function property(type){
+      if (type == "variable") {mark("property"); cont();}
+    }
+    // This parses a property and its value in an object literal.
+    function objprop(type){
+      if (type == "variable") mark("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() {
+        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;
+  }
+}();
diff --git a/typo3/sysext/t3editor/jslib/parsetyposcript.js b/typo3/sysext/t3editor/jslib/parsetyposcript.js
new file mode 100755 (executable)
index 0000000..035f5e5
--- /dev/null
@@ -0,0 +1,333 @@
+/* TypoScript parser
+ * 
+ * based on parsejavascript.js by Marijn Haverbeke
+ *
+ * A parser that can be plugged into the CodeMirror system has to
+ * implement the following interface: It is a function that, when
+ * called with a string stream (stringstream.js) as an argument,
+ * returns a MochiKit-style iterator (object with a 'next' method).
+ * This iterator, when called, consumes some input from the string
+ * stream, and returns a token object. Token objects must have a
+ * 'value' property (the text they represent), a 'style' property (the
+ * CSS style that should be used to colour them). Tokens for newline
+ * characters must also have a 'lexicalContext' property, which has an
+ * 'indentation' method that can be used to determine the proper
+ * indentation level for the next line. This method optionally takes
+ * the first character of the next line as an argument, which it can
+ * use to adjust the indentation level.
+ *
+ * So far this should be easy. The hard part is that the iterator
+ * produced by the parse function must also have a 'copy' method. This
+ * method, called without arguments, returns a function representing
+ * the current state of the parser. When this function is later called
+ * with a string stream as its argument, it returns a parser iterator
+ * object that resumes parsing using the old state and the new input
+ * stream. It may assume that only one parser is active at a time, and
+ * clobber the state of the old parser (the implementation below
+ * certianly does).
+ */
+
+// Parse function for TypoScript. Makes use of the tokenizer from
+// tokenizetyposcript.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.
+var parseTypoScript = function() {
+  // Token types that can be considered to be atoms.
+  var atomicTypes = setObject("atom", "number", "variable", "string", "regexp");  
+
+  // Constructor for the lexical context objects.
+  function TSLexical(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), '[', '{', 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 indentation rules.
+  TSLexical.prototype.indentation = function(firstChar) {
+    var closing = firstChar == this.type;
+       if (this.type == "}")
+      return this.indented + 2;
+
+    else if (this.align)
+      return this.column - (closing ? 1 : 0);
+    else
+      return this.indented + (closing ? 0 : 2);
+  }
+
+  // The parser-iterator-producing function itself.
+  return function(input){
+    // Wrap the input in a token stream
+    var tokens = tokenizeTypoScript(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 TSLexical(-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.type == "newline"){
+        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 a lexical context associated with them,
+       // which is used for indentation.
+        token.lexicalContext = lexical;
+      }
+      // No more processing for meaningless tokens.
+      if (token.type == "whitespace" || token.type == "newline" || 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. Marked is used to 
+      while(true){
+        consume = marked = false;
+       // Take and execute the topmost action.
+        cc.pop()(token.type, token.name);
+        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 _context = context, _lexical = lexical, _cc = cc.concat([]), _regexp = tokens.regexp, _comment = tokens.inComment;
+  
+      return function(input){
+        context = _context;
+        lexical = _lexical;
+        cc = _cc.concat([]); // copies the array
+        column = indented = 0;
+        tokens = tokenizeTypoScript(input);
+        tokens.regexp = _regexp;
+        tokens.inComment = _comment;
+        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 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("variabledef");
+        context.vars[varname] = true;
+      }
+    }
+
+  
+    // Push a new lexical context of the given type.
+    function pushlex(type){
+      var result = function(){
+        lexical = new TSLexical(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(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 == "{")              cont(pushlex("{"), block, poplex);
+         // else if (type == "[")              cont(pushlex("]"), condition, poplex);
+      else cont();
+    }
+       
+    // 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);
+      else if (type == ".") cont(property, maybeoperator);
+      else if (type == "[") cont(pushlex("]"), expression, expect("]"), poplex);
+    }
+    // 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 think they are variables.
+    function property(type){
+      if (type == "variable") {mark("property"); cont();}
+    }
+    // This parses a property and its value in an object literal.
+    function objprop(type){
+      if (type == "variable") mark("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() {
+        pass(what, proceed);
+      };
+    }
+       
+    // Look for statements until a closing brace is found.
+    function block(type){
+         if (type == "}") cont();
+      else pass(statement, block);
+    }
+       
+    // Look for statements until a closing brace is found.
+    function condition(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;
+  }
+}();
diff --git a/typo3/sysext/t3editor/jslib/select.js b/typo3/sysext/t3editor/jslib/select.js
new file mode 100755 (executable)
index 0000000..68369c2
--- /dev/null
@@ -0,0 +1,358 @@
+/* Functionality for finding, storing, and re-storing selections
+ *
+ * This does not provide a generic API, just the minimal functionality
+ * required by the CodeMirror system.
+ */
+
+// Namespace object.
+var select = {};
+
+(function() {
+  var 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) {
+    if (!node){
+        return null;
+    }
+    while (!node.previousSibling && node.parentNode != top){
+        node = node.parentNode;
+    }
+      
+    return topLevelNodeAt(node.previousSibling, top);
+  }
+
+  // Most functions are defined in two ways, one for the IE selection
+  // model, one for the W3C one.
+  if (ie_selection) {
+    // Store the current selection in such a way that it can be
+    // restored after we manipulated the DOM tree. For IE, we store
+    // pixel coordinates.
+    select.markSelection = function (win) {
+      var selection = win.document.selection;
+      var start = selection.createRange(), end = start.duplicate();
+      start.collapse(true);
+      end.collapse(false);
+
+      var body = win.document.body;
+      // And we better hope no fool gave this window a padding or a
+      // margin, or all these computations will be in vain.
+      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},
+              window: win};
+    };
+
+    // Restore a stored selection.
+    select.selectMarked = function(sel) {
+      if (!sel)
+       return;
+      var range1 = sel.window.document.body.createTextRange(), range2 = range1.duplicate();
+      range1.moveToPoint(sel.start.x, sel.start.y);
+      range2.moveToPoint(sel.end.x, sel.end.y);
+      range1.setEndPoint("EndToStart", range2);
+      range1.select();
+    };
+
+    // Not needed in IE model -- see W3C model.
+    select.replaceSelection = function(){};
+
+    // A Cursor object represents a top-level node that the cursor is
+    // currently in or after. It is not possible to reliably get more
+    // detailed information, but just this node is enough for most
+    // purposes.
+    select.Cursor = function(container) {
+        this.container = container;
+        this.doc = container.ownerDocument;
+        var selection = this.doc.selection;
+        this.valid = !!selection;
+        if (this.valid) {
+            var range = selection.createRange();
+            range.collapse(false);
+            var around = range.parentElement();
+            if (around && isAncestor(container, around)) {
+                  this.start = topLevelNodeAt(around, container);
+            }
+            else {
+                range.pasteHTML("<span id='// temp //'></span>");
+                var temp = this.doc.getElementById("// temp //");
+                this.start = topLevelNodeBefore(temp, container);
+                if (temp)
+                    removeElement(temp);
+            }
+        }
+    };
+
+    // Place the cursor after this.start. This is only useful when
+    // manually moving the cursor instead of restoring it to its old
+    // position.
+    select.Cursor.prototype.focus = function () {
+      var range = this.doc.body.createTextRange();
+      range.moveToElementText(this.start || this.container);
+      range.collapse(!this.start);
+      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) {
+      var selection = window.document.selection;
+      if (selection) {
+       var range = selection.createRange();
+       range.pasteHTML("<br/>");
+       range.collapse(false);
+       range.select();
+      }
+    };
+       
+       // Insert a custom string at current cursor position (added for t3editor)
+    select.insertTextAtCursor = function(window,text) {
+      var selection = window.document.selection;
+      if (selection) {
+        var range = selection.createRange();
+        range.pasteHTML(text);
+        range.collapse(false);
+       range.select();
+      }
+       };
+         
+  }
+  // W3C model
+  else {
+    // Well, Opera isn't even supported at the moment, but it almost
+    // is, and this is used to fix an issue with getting the scroll
+    // position.
+    var opera_scroll = !window.scrollX && !window.scrollY;
+
+    // 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 null;
+      var range = selection.getRangeAt(0);
+
+      var result = {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};
+
+      // 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(result.start);
+      normalize(result.end);
+      // Make the links back to the selection object (see
+      // replaceSelection).
+      if (result.start.node)
+       result.start.node.selectStart = result.start;
+      if (result.end.node)
+       result.end.node.selectEnd = result.end;
+
+      return result;
+    };
+
+    // Helper for selecting a range object.
+    function selectRange(range, window) {
+      var selection = window.getSelection();
+      selection.removeAllRanges();
+      selection.addRange(range);
+    };
+
+    select.selectMarked = function (sel) {
+      if (!sel)
+       return;
+      var win = sel.window;
+      var range = win.document.createRange();
+
+      function setPoint(point, which) {
+       if (point.node) {
+         // Remove the link back to the selection.
+          delete point.node["select" + which];
+         // 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){
+       sel.window.document.body.scrollLeft = sel.scrollX;
+       sel.window.document.body.scrollTop = sel.scrollY;
+      }
+         try {
+        setPoint(sel.start, "Start");
+        setPoint(sel.end, "End");
+        selectRange(range, win);
+         } catch(e) {}
+    };
+
+    // This is called by the code in codemirror.js whenever it is
+    // replacing a part of the DOM tree. 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.replaceSelection = function(oldNode, newNode, length, offset) {
+      function replace(which) {
+       var selObj = oldNode["select" + which];
+       if (selObj) {
+          if (selObj.offset > length) {
+            selObj.offset -= length;
+          }
+          else {
+            newNode["select" + which] = selObj;
+            delete oldNode["select" + which];
+            selObj.node = newNode;
+            selObj.offset += (offset || 0);
+          }
+       }
+      }
+      replace("Start");
+      replace("End");
+    };
+
+    // Finding the top-level node at the cursor in the W3C is, as you
+    // can see, quite an involved process. [Some of this can probably
+    // be simplified, but I'm afraid to touch it now that it finally
+    // works.]
+    select.Cursor = function(container) {
+      this.container = container;
+      this.win = container.ownerDocument.defaultView;
+      var selection = this.win.getSelection();
+      this.valid = selection && selection.rangeCount > 0;
+      if (this.valid) {
+       var range = selection.getRangeAt(0);
+       var end = range.endContainer;
+       // 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 (end.nodeType == 3){
+          if (range.endOffset > 0)
+            this.start = topLevelNodeAt(end, this.container);
+          else
+            this.start = topLevelNodeBefore(end, this.container);
+       }
+       // Occasionally, browsers will return the HTML node as
+       // selection (Opera does this all the time, which is the
+       // reason this editor does not work on that browser). If the
+       // offset is 0, we take the start of the frame ('after null'),
+       // otherwise, we take the last node.
+       else if (end.nodeName == "HTML") {
+          this.start = (range.endOffset == 1 ? null : container.lastChild);
+       }
+       // If the given node is our 'container', we just look up the
+       // correct node by using the offset.
+       else if (end == container) {
+          if (range.endOffset == 0)
+            this.start = null;
+          else
+            this.start = end.childNodes[range.endOffset - 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 (range.endOffset == end.childNodes.length)
+            this.start = topLevelNodeAt(end, this.container);
+          else if (range.endOffset == 0)
+            this.start = topLevelNodeBefore(end, this.container);
+          else
+            this.start = topLevelNodeAt(end.childNodes[range.endOffset - 1], this.container);
+       }
+      }
+    };
+
+    select.Cursor.prototype.focus = function() {
+        var sel = this.win.getSelection();
+        var range = this.win.document.createRange();
+        range.setStartBefore(this.container.firstChild || this.container);
+        if (this.start)
+            range.setEndAfter(this.start);
+        else
+            range.setEndBefore(this.container.firstChild || this.container);
+                 
+        range.collapse(false);
+        selectRange(range, this.win);
+    };
+       
+       
+
+    select.insertNewlineAtCursor = function(window) {
+      var selection = window.getSelection();
+      if (selection && selection.rangeCount > 0) {
+       var range = selection.getRangeAt(0);
+       var br = withDocument(window.document, BR);
+       range.insertNode(br);
+       range.setEndAfter(br);
+       range.collapse(false);
+       selectRange(range, window);
+      }
+    };
+       
+       // added for t3editor
+    select.insertTextAtCursor = function(window,text) {
+      var selection = window.getSelection();
+      if (selection && selection.rangeCount > 0) {
+        var range = selection.getRangeAt(0);
+        // var br = withDocument(window.document, BR);
+        textnode = window.document.createTextNode(text);
+        range.insertNode(textnode);
+        range.setEndAfter(textnode);
+        range.collapse(false);
+        selectRange(range, window);
+      }
+    }; 
+  }
+
+  // Search backwards through the top-level nodes until the next BR or
+  // the start of the frame.
+  select.Cursor.prototype.startOfLine = function() {
+    var start = this.start || this.container.firstChild;
+    while (start && start.nodeName != "BR")
+      start = start.previousSibling;
+    return start;
+  };
+}());
diff --git a/typo3/sysext/t3editor/jslib/stringstream.js b/typo3/sysext/t3editor/jslib/stringstream.js
new file mode 100644 (file)
index 0000000..35c3956
--- /dev/null
@@ -0,0 +1,76 @@
+/* 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.
+ */
+
+// Make a stream out of a single string. Not used by the editor, but
+// very useful for testing your parser.
+function singleStringStream(string) {
+  var pos = 0, start = 0;
+  
+  function peek() {
+    if (pos < string.length)
+      return string.charAt(pos);
+    else
+      return null;
+  }
+
+  function next() {
+    if (pos >= string.length)
+      throw StopIteration;
+    return string.charAt(pos++);
+  }
+
+  function get() {
+    var result = string.slice(start, pos);
+    start = pos;
+    return result;
+  }
+
+  return {peek: peek, next: next, get: get};
+}
+
+// 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.
+function multiStringStream(source){
+  source = iter(source);
+  var current = "", pos = 0;
+  var peeked = null, accum = "";
+  var result = {peek: peek, next: next, get: get};
+
+  function peek(){
+    if (!peeked)
+      peeked = nextOr(result, null);
+    return peeked;
+  }
+  function next(){
+    if (peeked){
+      var temp = peeked;
+      peeked = null;
+      return temp;
+    }
+    while (pos == current.length){
+      accum += current;
+      current = ""; // In case source.next() throws
+      pos = 0;
+      current = source.next();
+    }
+    return current.charAt(pos++);
+  }
+  function get(){
+    var temp = accum;
+    var realPos = peeked ? pos - 1 : pos;
+    accum = "";
+    if (realPos > 0){
+      temp += current.slice(0, realPos);
+      current = current.slice(realPos);
+      pos = peeked ? 1 : 0;
+    }
+    return temp;
+  }
+
+  return result;
+}
diff --git a/typo3/sysext/t3editor/jslib/t3editor.js b/typo3/sysext/t3editor/jslib/t3editor.js
new file mode 100755 (executable)
index 0000000..a7fee02
--- /dev/null
@@ -0,0 +1,1457 @@
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2007 Tobias Liebig <mail_typo3@etobi.de>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+/* t3editor.js is based on codemirror.js from the Codemirror editor. 
+ * See LICENSE file for further informations
+ */
+
+
+
+/**
+ * Browser checks
+ *  inspired by tinyMCE
+ */
+var ua = navigator.userAgent;
+var isMSIE = (navigator.appName == "Microsoft Internet Explorer");
+var isMSIE5 = this.isMSIE && (ua.indexOf('MSIE 5') != -1);
+var isMSIE5_0 = this.isMSIE && (ua.indexOf('MSIE 5.0') != -1);
+var isMSIE7 = this.isMSIE && (ua.indexOf('MSIE 7') != -1);
+var isGecko = ua.indexOf('Gecko') != -1; // Will also be true on Safari
+var isSafari = ua.indexOf('Safari') != -1;
+var isOpera = window['opera'] && opera.buildNumber ? true : false;
+var isMac = ua.indexOf('Mac') != -1;
+var isNS7 = ua.indexOf('Netscape/7') != -1;
+var isNS71 = ua.indexOf('Netscape/7.1') != -1;
+
+
+
+// collection of all t3editor instances on the current page
+var t3e_instances = {};
+
+
+
+/* CodeMirror main module
+ *
+ * Implements the CodeMirror constructor and prototype, which take care
+ * of initializing the editor and managing the highlighting and
+ * indentation, and some functions for transforming arbitrary DOM
+ * structures into plain sequences of <span> and <br> elements.
+ */
+
+// The MirrorOptions object is used to specify a default
+// configuration. If you specify such an object before loading this
+// file, the values you put into it will override the defaults given
+// below.
+var t3eOptions = window.t3eOptions || {};
+
+// safeKeys specifies the set of keys that will probably not modify
+//   the content of the editor, and thus do not have to be responded to.
+//   You usually won't have to change this.
+// reindentKeys gives the keys that should cause the editor to
+//   re-indent the current line
+// reindentAfterKeys works like reindentKeys, but in this case the
+//   key's normal effect is first allowed to take place. Use this for
+//   keys that might change the indentation level of the current line.
+// stylesheet is the filename of the stylesheet that should be used to
+//   colour the code in the editor.
+// parser should refer to a function that, when given a string stream
+//   (see stringstream.js), produces an object that acts as a stream of
+//   tokens plus some other functionality. See parsejavascript.js for an
+//   example and more information.
+// linesPerPass is the maximum amount of lines that the highlighter
+//   tries to colour in one shot. Setting this too high will cause the
+//   code to 'freeze' the browser for noticeable intervals.
+// passDelay gives the amount of milliseconds between colouring passes
+setdefault(t3eOptions,
+           {safeKeys: setObject("KEY_ARROW_UP", "KEY_ARROW_DOWN", "KEY_ARROW_LEFT", "KEY_ARROW_RIGHT", "KEY_END", "KEY_HOME",
+                                "KEY_PAGE_UP", "KEY_PAGE_DOWN", "KEY_SHIFT", "KEY_CTRL", "KEY_ALT", "KEY_SELECT"),
+           reindentKeys: setObject("KEY_TAB"),
+           reindentAfterKeys: setObject("KEY_RIGHT_SQUARE_BRACKET"),
+        stylesheet: PATH_t3e+"css/t3editor.css",
+        parser: parseTypoScript,
+           linesPerPass: 10,
+           passDelay: 500,
+        autoComplete: true,
+        acWords:5});
+// These default options can be overridden by passing a set of options
+// to a specific CodeMirror constructor.
+
+var t3editor = function(){
+  // The HTML elements whose content should be suffixed by a newline
+  // when converting them to flat text.
+  var newlineElements = setObject("P", "DIV", "LI");
+
+  // Helper function for traverseDOM. Flattens an arbitrary DOM node
+  // into an array of textnodes and <br> tags.
+  function simplifyDOM(root) {
+    var doc = root.ownerDocument;
+    var result = [];
+    var leaving = false;
+
+    function simplifyNode(node) {
+      leaving = false;
+
+      if (node.nodeType == 3) {
+        node.nodeValue = node.nodeValue.replace(/[\n\r]/g, "").replace(/[\t ]/g, nbsp);
+        result.push(node);
+      }
+      else if (node.nodeName == "BR" && node.childNodes.length == 0) {
+        result.push(node);
+      }
+      else {
+        forEach(node.childNodes, simplifyNode);
+        if (!leaving && newlineElements.hasOwnProperty(node.nodeName)) {
+          leaving = true;
+          el = withDocument(doc, SPAN);
+                 result.push(withDocument(doc, BR));
+        }
+      }
+    }
+
+    simplifyNode(root);
+    return result;
+  }
+
+  // Creates a MochiKit-style iterator that goes over a series of DOM
+  // nodes. The values it yields are strings, the textual content of
+  // the nodes. It makes sure that all nodes up to and including the
+  // one whose text is being yielded have been 'normalized' to be just
+  // <span> and <br> elements.
+  // See the story.html file for some short remarks about the use of
+  // continuation-passing style in this iterator.
+  function traverseDOM(start){
+    function yield(value, c){cc = c; return value;}
+    function push(fun, arg, c){return function(){return fun(arg, c);};}
+    function stop(){cc = stop; throw StopIteration;};
+    var cc = push(scanNode, start, stop);
+    var owner = start.ownerDocument;
+
+    // Create a function that can be used to insert nodes after the
+    // one given as argument.
+    function pointAt(node){
+      var parent = node.parentNode;
+      var next = node.nextSibling;
+      if (next)
+        return function(newnode){parent.insertBefore(newnode, next);};
+      else
+        return function(newnode){parent.appendChild(newnode);};
+    }
+    var point = null;
+
+    // Insert a normalized node at the current point. If it is a text
+    // node, wrap it in a <span>, and give that span a currentText
+    // property -- this is used to cache the nodeValue, because
+    // directly accessing nodeValue is horribly slow on some browsers.
+    // The dirty property is used by the highlighter to determine
+    // which parts of the document have to be re-highlighted.
+    function insertPart(part){
+      var text = "\n";
+      if (part.nodeType == 3) {
+        text = part.nodeValue;
+        part = withDocument(owner, partial(SPAN, {"class": "part"}, part));
+        part.currentText = text;
+      }
+      part.dirty = true;
+      point(part);
+      return text;
+    }
+
+    // Extract the text and newlines from a DOM node, insert them into
+    // the document, and yield the textual content. Used to replace
+    // non-normalized nodes.
+    function writeNode(node, c){
+      var toYield = [];
+      forEach(simplifyDOM(node), function(part) {
+        toYield.push(insertPart(part));
+      });
+      return yield(toYield.join(""), c);
+    }
+
+    // Check whether a node is a normalized <span> element.
+    function partNode(node){
+      if (node.nodeName == "SPAN" && node.childNodes.length == 1 && node.firstChild.nodeType == 3){
+        node.currentText = node.firstChild.nodeValue;
+        return true;
+      }
+      return false;
+    }
+
+    // Handle a node. Add its successor to the continuation if there
+    // is one, find out whether the node is normalized. If it is,
+    // yield its content, otherwise, normalize it (writeNode will take
+    // care of yielding).
+    function scanNode(node, c){
+      if (node.nextSibling)
+        c = push(scanNode, node.nextSibling, c);
+
+      if (partNode(node)){
+        return yield(node.currentText, c);
+      }
+      else if (node.nodeName == "BR") {
+        return yield("\n", c);
+      }
+      else {
+        point = pointAt(node);
+        removeElement(node);
+        return writeNode(node, c);
+      }
+    }
+
+    // MochiKit iterators are objects with a next function that
+    // returns the next value or throws StopIteration when there are
+    // no more values.
+    return {next: function(){return cc();}};
+  } // traverseDOM
+
+  var nbspRegexp = new RegExp(nbsp, "g");
+
+
+
+  function t3editor(theTextarea, index, options) {
+   
+   // Use passed options, if any, to override defaults.
+    this.options = options || {}
+    setdefault(this.options, t3eOptions);
+       
+    //History Array
+    this.history = [];
+    //Max History Size
+    this.historySize = 100;
+    //Init history position
+    this.currHistoryPosition = -1;
+
+       // memorize the textarea
+       this.textarea = $(theTextarea);
+    
+       this.documentname = this.textarea.readAttribute('alt');
+       
+       // count index (helpful if more than one editor is on the page)
+       this.index = index;
+
+    // create the wrapping div
+    this.outerdiv = $(createDOM("DIV", {
+       "class":        "t3e_outerdiv",
+       "id":           "t3e_"+this.textarea.getAttribute('id')
+       }));
+
+       // place the div before the textarea
+    this.textarea.parentNode.insertBefore(this.outerdiv,$(this.textarea));
+
+       // an overlay that covers the whole editor
+       this.modalOverlay = $(createDOM("DIV", {
+       "class":        "t3e_modalOverlay",
+               "id":           "t3e_modalOverlay_wait"
+       }));
+    this.modalOverlay.hide();
+    this.modalOverlay.setStyle(this.outerdiv.getDimensions());
+    this.modalOverlay.setStyle({opacity: 0.5});
+    this.outerdiv.appendChild(this.modalOverlay);
+       
+       this.helpOverlay = $(createDOM("DIV", {
+       "class":        "t3e_modalOverlay",
+       "id":           "t3e_modalOverlay_help"
+       }));
+    this.helpOverlay.innerHTML = "<h2>t3editor</h2>"+
+                                                                       "<p>put some helpful text here</p><br/><br/>"+
+                                                                       "<p>Hotkeys:</p>"+
+                                                                       "<p>"+
+                                                                       "<strong>CTRL-S</strong> send code to server<br/>"+
+                                                                       "<strong>CTRL-F11</strong> toggle fullscreen mode<br/>"+
+                                                                       "<strong>CTRL-SPACE</strong> auto-complete (based on letters at current cursor-position)<br/>"+
+                                                                       "<strong>CTRL-Z</strong> undo<br/>"+
+                                                                       "<strong>CTRL-Y</strong> redo<br/>"+
+                                                                       "</p><br/>"+
+                                                                       "<p><a href='javascript:void(0)' onclick='t3e_instances["+this.index+"].toggleHelp();'>click here to close this help window</a></p>"+
+                                                                       "";
+    this.helpOverlay.hide();
+       this.outerdiv.appendChild(this.helpOverlay);
+    
+       // wrapping the ilnenumbers
+    this.linenum_wrap = $(createDOM("DIV", {
+       "class":        "t3e_linenum_wrap"
+       }));
+       // the "linenumber" list itself
+    this.linenum = $(createDOM("DL", {
+       "class":        "t3e_linenum"
+       }));
+    this.linenum_wrap.appendChild(this.linenum);
+    this.outerdiv.appendChild(this.linenum_wrap);
+    
+    //autocomplete box
+    this.autoCompleteBox = $(createDOM("DIV",{"class":"t3e_autoCompleteBox"}));
+    this.autoCompleteBox.hide();
+    this.outerdiv.appendChild(this.autoCompleteBox);
+    
+       // wrapping the iframe
+    this.iframe_wrap = $(createDOM("DIV", {
+       "class":        "t3e_iframe_wrap"
+       }));
+
+       // the iframe (the actual "editor")
+    // display: block occasionally suppresses some Firefox bugs, so we
+    // always add it, redundant as it sounds.
+    this.iframe = $(createDOM("IFRAME", {
+       "style": "border: 0; display: block;",
+       "class": "t3e_iframe" 
+       }));
+
+    this.iframe_wrap.appendChild(this.iframe);
+    this.outerdiv.appendChild(this.iframe_wrap);
+    
+       // wrapping the footer/statusline
+    this.footer_wrap = $(createDOM("DIV", {
+       "class":        "t3e_footer_wrap"
+       }));
+    this.outerdiv.appendChild(this.footer_wrap);
+    
+       // this.fitem_resize = this.createFooterItem('#', false);
+    // this.footer_wrap.appendChild(this.fitem_resize);
+       
+       // footer item: show help Window
+         // TODO make this more flexible! And get rid of inline css and unsed options! 
+    this.fitem_help = this.createFooterItem('Help', true, 'toggleHelp');
+    this.footer_wrap.appendChild(this.fitem_help);
+       
+
+       // footer item: options menu
+       this.fitem_options_overlay = $(createDOM("DIV", {
+       "class":        "t3e_footer_overlay",
+       "id":           "t3e_footer_overlay_options"
+       }));
+       
+         // TODO make this more flexible! And get rid of inline css and unsed options!
+    this.fitem_options_overlay.innerHTML = '<ul>'+
+                               // '<li style="color:grey"><input type="checkbox" disabled="disabled" /> Syntax highlighting</li>'+ 
+                               '<li><input type="checkbox" onclick="t3e_instances['+this.index+'].fitem_options_overlay.hide();t3e_instances['+this.index+'].toggleAutoComplete();" id="t3e_autocomplete" checked="checked" /><label for="t3e_autocomplete">AutoCompletion</label></li>'+
+                               '<li><span onclick="t3e_instances['+this.index+'].fitem_options_overlay.hide();t3e_instances['+this.index+'].footeritem_demo_click();">Test snippets</span></li>'+
+                               '<li><input type="checkbox" onclick="t3e_instances['+this.index+'].fitem_options_overlay.hide();t3e_instances['+this.index+'].toggleFullscreen();" id="t3e_fullscreen" /> <label for="t3e_fullscreen">Fullscreen</label></li>'+
+                               // '<li style="color:grey"><input type="checkbox" disabled="disabled" /> other fancy stuff</li>'+
+                               '</ul>';
+    this.fitem_options_overlay.hide();
+    this.fitem_options = this.createFooterItem('Options', true, this.fitem_options_overlay);
+    this.footer_wrap.appendChild(this.fitem_options);
+    this.footer_wrap.appendChild(this.fitem_options_overlay);
+    
+       
+       // footer item: status field (total line numbers)
+    this.fitem_status = this.createFooterItem('', false);
+    this.footer_wrap.appendChild(this.fitem_status);
+    
+    // footer item: "name" of the document (taken from textarea alt-attribut), and save indicator
+    this.fitem_name = this.createFooterItem(this.documentname, false);
+    this.footer_wrap.appendChild(this.fitem_name);
+       
+       
+    
+       // window and document objects from the iframe
+       this.win = this.iframe.contentWindow;
+    this.doc = this.win.document;
+    
+       // make the iframe "editable"
+       this.doc.designMode = "on";
+    
+    this.doc.open();
+    this.doc.write("<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"" + t3eOptions.stylesheet + "\"/></head>" +
+                   "<body class=\"editbox\" spellcheck=\"false\"></body></html>");
+    this.doc.close();
+
+
+       // new Resizable(this.outerdiv,{handle:$(this.fitem_resize)});
+
+    // An array of known dirty nodes, nodes that have been modified
+    // since they were last parsed.
+    this.dirty = [];
+
+       // dimensions
+    this.width   = $(this.textarea).getDimensions().width;
+    this.height  = $(this.textarea).getDimensions().height;
+
+       var content = this.textarea.value;
+
+       // hide the textarea
+    this.textarea.hide();
+
+    // Some browsers immediately produce a <body> in a new <iframe>,
+    // others only do so later and fire an onload event when they do.
+    if (this.doc.body) {
+      this.init(content);
+    } else {
+      connect(this.iframe, "onload", bind(function(){disconnectAll(this.iframe, "onload"); this.init(content);}, this));
+    }
+  }
+
+
+
+  t3editor.prototype = {
+
+       textModified: false,    // editor-content has been modified
+       saveAjaxEvent: null,    // Event for save code with ajax        
+       
+    // Called after we are sure that our frame has a body
+    init: function (code) {
+      this.container = this.doc.body;
+      
+         // fetch key press events
+         connect(this.doc, "onkeydown", method(this, "keyDown"));
+      connect(this.doc, "onkeyup", method(this, "keyUp"));
+         
+         // fetch scroll events for updateing line numbers
+         connect(this.doc, "onscroll", method(this, "scroll"));
+      connect(this.win, "onscroll", method(this, "scroll"));
+      
+      //fetch mouse click event
+      connect(this.doc, "onclick", method(this, "click"));
+    
+      // get the form object (needed for Ajax saving)
+      var form = $(this.textarea.form)
+         this.saveButtons = form.getInputs('submit', 'submit');
+
+      // initialize ajax saving events
+      this.saveAjaxEvent = this.saveAjax.bind(this);
+      this.saveButtons.each(function(button) {
+       Event.observe(button,'click',this.saveAjaxEvent);
+      }.bind(this));
+      
+         // resize the editor
+      this.resize(this.width, this.height);
+         
+      //Import code to editor. If code is empty the method importCode put a BR or SPAN into the codewindow - dependence on browser
+      this.importCode(code);
+         
+         // set focus
+         this.win.focus();
+        var cursor = new select.Cursor(this.container);
+       cursor.focus();
+    
+    },
+       
+       // for demonstation only!
+       footeritem_demo_click: function() {
+               // insertNewlineAtCursor(this.win);
+        
+        // focus editor and cursor
+        this.win.focus();
+        var cursor = new select.Cursor(this.container);
+        cursor.start = this.cursorObj;
+        cursor.focus();
+
+               select.insertTextAtCursor(this.win, "page = PAGE");select.insertNewlineAtCursor(this.win);
+               select.insertTextAtCursor(this.win, "page {");     select.insertNewlineAtCursor(this.win);
+               select.insertTextAtCursor(this.win, "  10 = TEXT");select.insertNewlineAtCursor(this.win);
+               select.insertTextAtCursor(this.win, "  10.value = Hello World!");               select.insertNewlineAtCursor(this.win);
+               select.insertTextAtCursor(this.win, "}");                       select.insertNewlineAtCursor(this.win);
+               
+               this.markCursorDirty();
+               this.scheduleHighlight();
+
+               // this.doc.execCommand("undo", false, null);
+       },
+       
+    // toggle between the textarea and t3editor
+       toggleView: function(checkboxEnabled)   {
+               if (checkboxEnabled) {
+                       this.textarea.value = this.getCode();
+                       this.outerdiv.hide();
+                       this.textarea.show();
+                       this.saveButtons.each(function(button) {
+                       Event.stopObserving(button,'click',this.saveAjaxEvent);
+               }.bind(this));
+               } else {
+                       this.importCode(this.textarea.value);
+                       this.textarea.hide();
+                       this.outerdiv.show();
+                       this.saveButtons.each(function(button) {
+                       Event.observe(button,'click',this.saveAjaxEvent);
+               }.bind(this));
+               }
+       },
+
+       // create an item for the footer line and connect an event
+    createFooterItem: function(title, mouseover, clickAction)  {
+       var item = $(createDOM("DIV", {
+               "class":        "t3e_footer_item"
+       }));
+       item.innerHTML = title;
+       
+       if (mouseover) {
+                       item.addClassName('t3e_clickable');
+               Event.observe(item, "mouseover", function(e){Event.element(e).addClassName('t3e_footeritem_active');} );
+               Event.observe(item, "mouseout",  function(e){Event.element(e).removeClassName('t3e_footeritem_active');} );
+               }
+               
+               if (typeof clickAction == 'object') { // display an overlay
+                       Event.observe(item, "click",  function(e){ clickAction.toggle(); } );
+               
+               } else if (typeof clickAction == 'string' && clickAction != '') {       // execute a method
+                       connect(item, "onclick", method(this, clickAction+''));
+               }
+               
+       return item;
+    },
+    
+       // resize the editor
+    resize: function(width, height)    {
+               if (this.outerdiv) {
+                       
+                       // TODO: make it more flexible, get rid of "hardcoded" numbers!
+                       
+                       newheight = (height - 1);
+                       newwidth  = (width + 11);
+                       if (isMSIE) newwidth = newwidth + 8;
+
+                       this.outerdiv.setStyle({
+                                       height: newheight,
+                       width: newwidth
+                });
+
+                       this.linenum_wrap.setStyle({
+                               height: (height - 22)   // less footer height (TODO)
+                       });
+
+                       numwwidth = this.linenum_wrap.getWidth();
+                       if (isMSIE)  numwwidth = numwwidth - 17;
+                       if (!isMSIE) numwwidth = numwwidth - 11;        
+
+                       this.iframe.setStyle({
+                   height: (height - 22),      // less footer height (TODO)
+                               width:  (width - numwwidth)
+                       });
+                       
+                       this.modalOverlay.setStyle(this.outerdiv.getDimensions());
+               }
+       },
+
+       // toggle between normal view and fullscreen mode
+       toggleFullscreen : function()   {
+               if (this.outerdiv.hasClassName('t3e_fullscreen')) {
+                       // turn fullscreen off
+                       this.outerdiv.removeClassName('t3e_fullscreen');
+                       h = this.textarea.getDimensions().height;
+                       w = this.textarea.getDimensions().width;
+                       
+                       // hide the scrollbar of the body
+                       $$('body')[0].setStyle({overflow : ''});
+                       
+               } else {
+                       // turn fullscreen on
+                       this.outerdiv.addClassName('t3e_fullscreen');
+                       h = window.innerHeight ? window.innerHeight : $$('body')[0].getHeight();
+                       w = window.innerWidth ? window.innerWidth : $$('body')[0].getWidth();
+                       
+                       // TODO: proof if this is needed anymore
+                       w = w - 13;
+                       
+                       // hide the scrollbar of the body
+                       $$('body')[0].setStyle({overflow : 'hidden'});
+               }
+
+               this.resize(w,h);
+       },
+       
+       toggleHelp: function()  {
+               this.modalOverlay.toggle();
+               this.helpOverlay.toggle();\r
+       },
+
+    
+    //toggle AutoCompletation beetwen on and off
+    toggleAutoComplete : function() {
+        this.options.autoComplete = (this.options.autoComplete)?false:true;
+    },
+    
+    //autocomplete box
+    autoComplete : function() {
+        this.clicked = false;
+        //get lastword into this.lastWord
+        this.getLastWord();
+        // init vars for up/down moving in word list
+        this.ac_up = 0;
+        this.ac_down = this.options.acWords-1;
+        
+        //refresh cursorObj
+        var cursor = new select.Cursor(this.container);
+        this.cursorObj = cursor.start;
+        //init currWord, used in word list. Contain selected word
+        this.currWord = -1;
+        
+        // If lastword is not empty and not space - continue
+        if (this.lastWord!='&nbsp;' && this.lastWord){
+            // get list of words
+            this.words = this.getCompleteWordsByTrigger(this.lastWord.toLowerCase());
+            // if words are found - show box
+            if (this.words.length > 0){
+                // make UL list of completation words
+                var html = '<ul>';
+                for (i=0;i<this.words.length;i++){
+                    html+= '<li style="height:16px;vertical-align:middle;" id="ac_word_'+i+'" onclick="t3e_instances['+this.index+'].clicked=true;t3e_instances['+this.index+'].insertCurrWordAtCursor();" onmouseover="t3e_instances['+this.index+'].highlightCurrWord('+i+');"><span class="word_'+this.words[i].type+'">'+this.words[i].word+'</span></li>';
+                }
+                html+='</ul>';
+                //put HTML and show box
+                this.autoCompleteBox.innerHTML = html;
+                this.autoCompleteBox.show();
+                this.autoCompleteBox.scrollTop = 0;
+                //  init styles
+                if (this.words.length > this.options.acWords){
+                    this.autoCompleteBox.style.overflowY = 'scroll';
+                    if (isGecko){
+                        this.autoCompleteBox.style.height = (this.options.acWords*($("ac_word_0").offsetHeight))+'px';
+                    }else{
+                        this.autoCompleteBox.style.height = (this.options.acWords*($("ac_word_0").offsetHeight))+4+'px';
+                        this.autoCompleteBox.style.width = this.autoCompleteBox.offsetWidth+20+'px';
+                    }
+                    
+                }else{
+                    this.autoCompleteBox.style.overflowY = 'auto';
+                    this.autoCompleteBox.style.height = 'auto';
+                    this.autoCompleteBox.style.width = 'auto'; // '0px';
+                }
+                
+                // positioned box to word
+                this.autoCompleteBox.style.left = Position.cumulativeOffset(this.iframe)[0]-Position.cumulativeOffset(this.outerdiv)[0]+Position.cumulativeOffset(cursor.start)[0]+cursor.start.offsetWidth;
+                this.autoCompleteBox.style.top = Position.cumulativeOffset(this.iframe)[1]-Position.cumulativeOffset(this.outerdiv)[1]+Position.cumulativeOffset(cursor.start)[1]+cursor.start.offsetHeight-this.container.scrollTop;
+                // set flag to 1 - needed for continue typing word. 
+                this.ac = 1;    
+                //highlight first word in list
+                this.highlightCurrWord(0);
+            } 
+        }
+    },
+    // Get word where cursor focused
+    getLastWord : function (){
+        var cursor = new select.Cursor(this.container);
+        if (cursor.start){
+            this.lastTrigger = this.lastWord;
+            this.lastWord = (cursor.start.innerHTML)?cursor.start.innerHTML:'';
+        }
+    },
+    
+    // highlighitng word in autocomplete box by id
+    highlightCurrWord : function (id) {
+        if (this.currWord!=-1){
+            $('ac_word_'+this.currWord).className = '';
+        }
+        $('ac_word_'+id).className = 'active';
+        this.currWord = id;
+    },
+    
+    //insert selected word into text from autocompletebox
+    insertCurrWordAtCursor: function (){
+        var trigger = this.lastWord;
+        var insertText = this.words[this.currWord].word;
+        //if MSIE and select word my mouse click
+        var cursor = new select.Cursor(this.container);
+        if (isMSIE && this.clicked){
+            if (trigger.length > 0){
+                this.cursorObj.innerHTML = insertText;
+                this.win.focus();
+                cursor.start = this.cursorObj;
+                cursor.focus();
+                this.highlightAtCursor(cursor);
+            }
+        }
+        // if Safari browser
+        else if (isSafari){
+             if (trigger.length > 0){
+                this.cursorObj.innerHTML = insertText;
+                if (this.clicked){
+                   this.win.focus();
+                }
+                cursor.start = this.cursorObj;
+                cursor.focus();
+                this.highlightAtCursor(cursor);            
+            }
+        }
+        //for all others times
+        else{
+            if (trigger.length > 0){
+                cursor.start.innerHTML = '';
+            }
+            select.insertTextAtCursor (this.win,insertText);
+            if (this.clicked){
+                this.win.focus();    
+            }
+            cursor.focus();
+            this.highlightAtCursor(cursor);
+        }
+        // set ac flag to 0 - autocomplete is finish
+        this.ac = 0;
+        //hide box
+        this.autoCompleteBox.hide();
+    },
+    //return words for autocomplete by trigger (part of word)
+    getCompleteWordsByTrigger : function (trigger){
+        result = [];
+        
+        for(word in typoscriptWords){
+            lword = word.toLowerCase();
+            if (lword.indexOf(trigger) === 0){
+                var wordObj = new Object();
+                wordObj.word = word;
+                wordObj.type = typoscriptWords[word];
+                result.push(wordObj);
+            }
+        }        
+        return result;
+    },
+    
+    //move cursor in autcomplete box up
+    autoCompleteBoxMoveUpCursor : function () {
+        // if previous position was first - then move cursor to last word if not than position --
+        if (this.currWord == 0){
+            var id = this.words.length-1;
+        }else{
+            var id = this.currWord-1;
+        }
+        // hightlight new cursor position
+        this.highlightCurrWord (id);
+        //update id of first and last showing words and scroll box
+        if (this.currWord < this.ac_up || this.currWord == (this.words.length-1)){
+            this.ac_up = this.currWord;
+            this.ac_down = this.currWord+(this.options.acWords-1);
+            if (this.ac_up === this.words.length-1){
+                this.ac_down = this.words.length-1;
+                this.ac_up = this.ac_down-(this.options.acWords-1);
+            }
+            this.autoCompleteBox.scrollTop = this.ac_up*16;
+        }
+    },
+    //move cursor in autocomplete box down
+    autoCompleteBoxMoveDownCursor : function () {
+        // if previous position was last word in list - then move cursor to first word if not than  position ++
+        if (this.currWord == this.words.length-1){
+            var id = 0;
+        }else{
+            var id = this.currWord+1;
+        }
+        // hightlight new cursor position
+        this.highlightCurrWord (id);
+         //update id of first and last showing words and scroll box
+        if (this.currWord > this.ac_down || this.currWord==0){
+            this.ac_down = this.currWord;
+            this.ac_up = this.currWord-(this.options.acWords-1);
+            if (this.ac_down == 0){
+                this.ac_up = 0;
+                this.ac_down = this.options.acWords-1;
+            }
+            this.autoCompleteBox.scrollTop = this.ac_up*16;
+        }
+    },
+    // put code to history
+    pushToHistory:function () {
+        var obj = {};
+        //create SPAN mark of cursor
+        var cursorEl  = this.win.document.createElement("SPAN");
+        cursorEl.id = "cursor";       
+        this.refreshCursorObj();
+        // added mark to code
+        if (this.initable){
+            if (!this.cursorObj){
+                if (this.container.firstChild){
+                   this.win.document.body.insertBefore(cursorEl,this.container.firstChild);
+                }
+            }else{
+                this.win.document.body.insertBefore(cursorEl,this.cursorObj);
+            }
+        }else{
+            this.win.document.body.appendChild(cursorEl);
+        }
+        //save code and text to history object
+        obj.code = this.container.innerHTML;
+        obj.text = this.getCode();
+        // check if was undo/redo than refresh history array
+        if (this.currHistoryPosition+1 < this.history.length){
+            this.history = this.history.slice (0,this.currHistoryPosition+1);
+            this.currHistoryPosition = this.history.length-1;
+        }
+        //push history oject to history array
+        this.history.push(obj);
+        this.currHistoryPosition++;
+        //check limit of history size
+        if (this.currHistoryPosition > this.historySize){
+            this.history = this.history.slice ((this.history.length-this.historySize-1));
+            this.currHistoryPosition = this.history.length-1;
+        }
+    },
+    
+    //undo function
+    undo: function () {
+        //check if position in history not first
+        if (this.currHistoryPosition > 0){
+            this.currHistoryPosition--;
+            var obj = this.history[this.currHistoryPosition];
+            if (!obj){return ;}
+            //insert code from history
+            this.container.innerHTML = obj.code;
+            //focus cursor to next el of marked span
+            var cursor = new select.Cursor(this.container);
+            var cursorEl = this.win.document.getElementById('cursor');
+            if (cursorEl){
+                cursor.start = cursorEl.nextSibling;
+                cursor.focus();
+            }
+        }
+        
+    },
+    
+    //redo function
+    redo: function () {
+        //check if position in history not last
+        if (this.currHistoryPosition < this.history.length){
+            this.currHistoryPosition++;
+            var obj = this.history[this.currHistoryPosition];
+            if (!obj){return ;}
+            //insert code from history
+            this.container.innerHTML = obj.code;
+            //focus cursor to next el of marked span
+            var cursor = new select.Cursor(this.container);
+            var cursorEl = this.win.document.getElementById('cursor');
+            if (cursorEl){
+                cursor.start = cursorEl.nextSibling;
+                cursor.focus();
+            }
+        }
+        
+    },
+    // check changes in history
+    checkHistoryChanges:function () {
+        
+        var code = this.container.innerHTML;
+        if (this.undoable == 1){
+            this.undoable = 0;
+            return ;
+        }
+        if (this.redoable == 1){
+            this.redoable = 0;
+            return ;
+        }
+        if (!this.history[this.currHistoryPosition]){
+            this.pushToHistory();
+            return ;
+        }
+        if (this.getCode(code) != this.history[this.currHistoryPosition].text){
+            this.pushToHistory();
+        }
+        
+    },
+
+       // update the line numbers
+    updateLinenum: function()      {
+               var theMatch = this.container.innerHTML.match(/<br/gi);
+        if (!theMatch) {
+            theMatch = '1';
+        } else if (isMSIE) { 
+                       theMatch.push('1');
+               }
+
+        var bodyContentLineCount = theMatch.length;
+        disLineCount = this.linenum.childNodes.length;
+        while (disLineCount != bodyContentLineCount)    {
+               if (disLineCount > bodyContentLineCount)        {
+                   this.linenum.removeChild(this.linenum.lastChild);
+                   disLineCount--;
+               } else if (disLineCount < bodyContentLineCount) {
+                   ln = $(document.createElement('dt'));
+                   ln.update(disLineCount+1+'.');
+                   ln.addClassName(disLineCount%2==1?'even':'odd');
+                   ln.setAttribute('id','ln'+(disLineCount+1));
+                   this.linenum.appendChild(ln);
+                   disLineCount++;
+               }
+        }
+
+               this.fitem_status.update(bodyContentLineCount + ' lines');
+               this.fitem_name.update(this.documentname + (this.textModified?' <span alt="document has been modified">*</span>':''));
+    },
+
+       // scroll the line numbers
+    scroll: function()  {
+               var scrOfX = 0, scrOfY = 0;
+               if( typeof( this.win.pageYOffset ) == 'number' ) {
+                   // Netscape compliant
+                   scrOfY = this.win.pageYOffset;
+                   scrOfX = this.win.pageXOffset;
+               } else if( this.doc.body && ( this.doc.body.scrollLeft || this.doc.body.scrollTop ) ) {
+                   // DOM compliant
+                   scrOfY = this.doc.body.scrollTop;
+                   scrOfX = this.doc.body.scrollLeft;
+               } else if( this.doc.documentElement && ( this.doc.documentElement.scrollLeft || this.doc.documentElement.scrollTop ) ) {
+                   // IE6 standards compliant mode
+                   scrOfY = this.doc.documentElement.scrollTop;
+                   scrOfX = this.doc.documentElement.scrollLeft;
+               }
+        this.linenum_wrap.scrollTop = scrOfY;
+    },
+    
+    // click event. Refresh cursor object. if autocomplete is not finish - finish it and hide box
+    click: function()  {
+        if (this.ac === 1){this.ac = 0;this.autoCompleteBox.hide();}
+        this.refreshCursorObj();
+    },
+
+    // Split a chunk of code into lines, put them in the frame, and
+    // schedule them to be coloured.
+    importCode: function(code) {
+      replaceChildNodes(this.container);
+
+      if (code == "\n" || code == "\r\n" || code == "\r"){code = '';}
+      var lines = code.replace(/[ \t]/g, nbsp).replace(/\r\n?/g, "\n").split("\n");
+
+      for (var i = 0; i != lines.length; i++) {
+        if (i > 0)
+          this.container.appendChild(withDocument(this.doc, BR));
+        var line = lines[i];
+        if (line.length > 0)
+          this.container.appendChild(this.doc.createTextNode(line));
+      }
+      if (code == "") {
+        var empty = this.win.document.createElement('BR');//(isGecko && !isSafari)?this.win.document.createElement('BR'):this.win.document.createElement('SPAN');
+       this.container.appendChild(empty);
+      }
+
+      if (this.container.firstChild){
+               this.addDirtyNode(this.container.firstChild);
+        this.scheduleHighlight(); // this.highlightDirty();
+      }
+         this.updateLinenum();
+    },
+
+    // Extract the code from the editor.
+    getCode: function() {
+      if (!this.container.firstChild)
+        return "";
+
+      var accum = [];
+      forEach(traverseDOM(this.container.firstChild), method(accum, "push"));
+      return accum.join("").replace(nbspRegexp, " ");
+    },
+
+    // Intercept enter and any keys that are specified to re-indent
+    // the current line.
+    keyDown: function(event) {
+      var name = event.key().string;
+
+      if (name == "KEY_ENTER") {
+            event.stop();
+                       if (this.ac === 1)      {
+               this.insertCurrWordAtCursor();
+            } else if (!isMac) {
+                select.insertNewlineAtCursor(this.win);
+                   this.indentAtCursor();
+            }
+            this.updateLinenum();
+                       
+         } else if (name == "KEY_S" && event.modifier().ctrl) {        // save via ajax request
+               this.saveAjax();
+               event.stop();
+               return;
+                       
+      } else if (name == "KEY_F11" && event.modifier().ctrl) { // toogle fullscreen mode
+               this.toggleFullscreen();
+               event.stop();
+               return;
+                       
+      } else if (name == "KEY_SPACEBAR" && event.modifier().ctrl && this.options.autoComplete){ // call autocomplete if autocomplete turn on
+        this.autoComplete();
+        event.stop();
+      } else if (name=="KEY_ARROW_UP" && this.ac == 1){ // move up cursor in autocomplete box
+        event.stop();
+        window.setTimeout('t3e_instances['+this.index+'].autoCompleteBoxMoveUpCursor()',100);
+      } else if (name=="KEY_ARROW_DOWN" && this.ac == 1){ // move down cursor in autocomplete box
+        event.stop();
+        window.setTimeout('t3e_instances['+this.index+'].autoCompleteBoxMoveDownCursor();',100);
+      } else if (name=="KEY_ESCAPE" && this.ac === 1){ // if autocomplete box is showing. by ESC press it's hide and autocomplete is finish
+            this.ac = 0;
+            this.autoCompleteBox.hide();
+      } else if (name=='KEY_Z' && event.modifier().ctrl){
+         this.undoable = 1;
+         this.undo();
+         event.stop();
+      } else if (name=='KEY_Y' && event.modifier().ctrl){
+         this.redoable = 1;
+         this.redo();
+         event.stop();
+      }
+    },
+
+    // Re-indent when a key in options.reindentAfterKeys is released,
+    // mark the node at the cursor dirty when a non-safe key is
+    // released.
+    keyUp: function(event) {
+      var name = event.key().string;
+      if (this.options.reindentAfterKeys.hasOwnProperty(name))
+        this.indentAtCursor();
+      else if (!this.options.safeKeys.hasOwnProperty(name)) {
+        this.markCursorDirty();
+        this.checkTextModified();
+         }
+         
+       if (this.ac===1){ // if autocomplete now is not finish, but started and continue typing - refresh autocomplete box
+            this.getLastWord();
+            if (this.lastTrigger!=this.lastWord){
+                this.autoCompleteBox.hide();
+                this.ac = 0;
+                this.autoComplete();     
+            }
+       } 
+      
+      if (name == "KEY_ENTER" || name == "KEY_BACKSPACE" || name == "KEY_DELETE" ){
+          this.updateLinenum();
+      }
+       
+      this.refreshCursorObj();
+    },
+       
+    refreshCursorObj: function () {
+        var cursor = new select.Cursor(this.container);
+        this.cursorObj = cursor.start;
+    },
+
+
+       // check if code in editor has been modified since last saving
+    checkTextModified: function() {
+         if (!this.textModified) {
+       this.textModified = true;
+               this.updateLinenum();
+      }
+    },
+
+
+       // send ajax request to save the code
+       saveAjax: function(event) {
+               if (event) {
+                       // event = new Event(event);
+                       Event.stop(event);
+               }
+               
+               this.modalOverlay.show();
+               this.textarea.value = this.getCode();
+               
+               /* erst ab prototype 1.5.1
+               Form.request($(this.textarea.form),{
+                       onComplete: function(){ alert('Form data saved!'); }
+               });
+               */
+               
+               formdata = "submitAjax=1&" + Form.serialize($(this.textarea.form));
+
+               var myAjax = new Ajax.Request(
+                       $(this.textarea.form).action, 
+                       { method: "post",
+                         parameters: formdata, 
+                         onComplete: this.saveAjaxOnSuccess.bind(this)
+                       });
+       },
+
+       // callback if ajax saving was successful
+       saveAjaxOnSuccess: function(ajaxrequest) {
+               if (ajaxrequest.status == 200
+                       && ajaxrequest.responseText == "OK") {
+                       this.textModified = false;
+                       this.updateLinenum();
+               } else {
+                       // TODO: handle if session is timed out
+                       alert("An error occured while saving the data.");
+               };
+               this.modalOverlay.hide();
+               
+       },
+
+
+    // Ensure that the start of the line the cursor is on is parsed
+    // and coloured properly, so that the correct indentation can be
+    // computed.
+    highlightAtCursor: function(cursor) {
+      if (cursor.valid) {
+        var node = cursor.start || this.container.firstChild;
+        if (node) {
+         // If the node is a text node, it will be recognized as
+         // dirty anyway, and some browsers do not allow us to add
+         // properties to text nodes.
+          if (node.nodeType != 3)
+            node.dirty = true;
+         // Store selection, highlight, restore selection.
+          var sel = select.markSelection(this.win);
+          this.highlight(node);
+          select.selectMarked(sel);
+         // Cursor information is probably no longer valid after
+         // highlighting.
+          cursor = new select.Cursor(this.container);
+        }
+      }
+      return cursor;
+    },
+
+    // Adjust the amount of whitespace at the start of the line that
+    // the cursor is on so that it is indented properly.
+    indentAtCursor: function() {
+      var cursor = new select.Cursor(this.container);
+      // The line has to have up-to-date lexical information, so we
+      // highlight it first.
+      cursor = this.highlightAtCursor(cursor);
+      // If we couldn't determine the place of the cursor, there's
+      // nothing to indent.
+      if (!cursor.valid)
+        return;
+
+      // start is the <br> before the current line, or null if this is
+      // the first line.
+      var start = cursor.startOfLine();
+      // whiteSpace is the whitespace span at the start of the line,
+      // or null if there is no such node.
+      var whiteSpace = start ? start.nextSibling : this.container.lastChild;
+      if (whiteSpace && !hasClass(whiteSpace, "whitespace"))
+        whiteSpace = null;
+
+      // Sometimes the first character on a line can influence the
+      // correct indentation, so we retrieve it.
+      var firstText = whiteSpace ? whiteSpace.nextSibling : start ? start.nextSibling : this.container.firstChild;
+      var firstChar = (start && firstText && firstText.currentText) ? firstText.currentText.charAt(0) : "";
+
+      // Ask the lexical context for the correct indentation, and
+      // compute how much this differs from the current indentation.
+     
+         var indent = start ? start.lexicalContext.indentation(firstChar) : 0;
+      var indentDiff = indent - (whiteSpace ? whiteSpace.currentText.length : 0);
+
+      // If there is too much, this is just a matter of shrinking a span.
+      if (indentDiff < 0) {
+        whiteSpace.currentText = repeatString(nbsp, indent);
+        whiteSpace.firstChild.nodeValue = whiteSpace.currentText;
+      }
+      // Not enough...
+      else if (indentDiff > 0) {
+       // If there is whitespace, we grow it.
+        if (whiteSpace) {
+          whiteSpace.currentText += repeatString(nbsp, indentDiff);
+          whiteSpace.firstChild.nodeValue = whiteSpace.currentText;
+        }
+       // Otherwise, we have to add a new whitespace node.
+        else {
+          whiteSpace = withDocument(this.doc, function(){return SPAN({"class": "part whitespace"}, repeatString(nbsp, indentDiff))});
+          if (start)
+            insertAfter(whiteSpace, start);
+          else
+            insertAtStart(whiteSpace, this.containter);
+        }
+       // If the cursor is at the start of the line, move it to after
+       // the whitespace.
+        if (cursor.start == start)
+          cursor.start = whiteSpace;
+      }
+         
+         if (cursor.start == whiteSpace)
+        cursor.focus();
+    },
+
+    // highlight is a huge function defined below.
+    highlight: highlight,
+
+    // Find the node that the cursor is in, mark it as dirty, and make
+    // sure a highlight pass is scheduled.
+    markCursorDirty: function() {
+      var cursor = new select.Cursor(this.container);
+      if (cursor.valid) {
+        var node = cursor.start || this.container.firstChild;
+        if (node) {
+          this.addDirtyNode(node);
+                 this.scheduleHighlight();
+        }
+      }
+    },
+
+    // Add a node to the set of dirty nodes, if it isn't already in
+    // there.
+    addDirtyNode: function(node) {
+      if (this.dirty.indexOf(node) == -1) {
+        if (node.nodeType != 3)
+          node.dirty = true;
+        this.dirty.push(node);
+      }
+    },
+
+    // Cause a highlight pass to happen in options.passDelay
+    // milliseconds. Clear the existing timeout, if one exists. This
+    // way, the passes do not happen while the user is typing, and
+    // should as unobtrusive as possible.
+    scheduleHighlight: function() {
+         if (this.highlightTimeout) clearTimeout(this.highlightTimeout);
+         this.highlightTimeout = setTimeout(bind(this.highlightDirty, this), this.options.passDelay);
+    },
+
+    // Fetch one dirty node, and remove it from the dirty set.
+    getDirtyNode: function() {
+      while (this.dirty.length > 0) {
+        var found = this.dirty.pop();
+       // If the node has been coloured in the meantime, or is no
+       // longer in the document, it should not be returned.
+        if ((found.dirty || found.nodeType == 3) && found.parentNode)
+          return found;
+      }
+      return null;
+    },
+
+    // Pick dirty nodes, and highlight them, until
+    // options.linesPerPass lines have been highlighted. The highlight
+    // method will continue to next lines as long as it finds dirty
+    // nodes. It returns an object indicating the amount of lines
+    // left, and information about the place where it stopped. If
+    // there are dirty nodes left after this function has spent all
+    // its lines, it shedules another highlight to finish the job.
+    highlightDirty: function() {
+         var lines = this.options.linesPerPass;
+      var sel = select.markSelection(this.win);
+      var start;
+      while (lines > 0 && (start = this.getDirtyNode())){
+        var result = this.highlight(start, lines);
+        if (result) {
+          lines = result.left;
+          if (result.node && result.dirty)
+            this.addDirtyNode(result.node);
+        }
+      }
+      select.selectMarked(sel);
+         if (start)
+        this.scheduleHighlight();
+    }
+  }
+
+  // The function that does the actual highlighting/colouring (with
+  // help from the parser and the DOM normalizer). Its interface is
+  // rather overcomplicated, because it is used in different
+  // situations: ensuring that a certain line is highlighted, or
+  // highlighting up to X lines starting from a certain point. The
+  // 'from' argument gives the node at which it should start. If this
+  // is null, it will start at the beginning of the frame. When a
+  // number of lines is given with the 'lines' argument, it will colour
+  // no more than that amount. If at any time it comes across a
+  // 'clean' line (no dirty nodes), it will stop.
+  function highlight(from, lines){
+    var container = this.container;
+    var document = this.doc;
+//     this.updateLinenum();
+
+    if (!container.firstChild)
+      return;
+    // Backtrack to the first node before from that has a partial
+    // parse stored.
+    while (from && !from.parserFromHere)
+      from = from.previousSibling;
+    // If we are at the end of the document, do nothing.
+    if (from && !from.nextSibling)
+      return;
+
+    // Check whether a part (<span> node) and the corresponding token
+    // match.
+    function correctPart(token, part){
+      return !part.reduced && part.currentText == token.value && hasClass(part, token.style);
+    }
+    // Shorten the text associated with a part by chopping off
+    // characters from the front. Note that only the currentText
+    // property gets changed. For efficiency reasons, we leave the
+    // nodeValue alone -- we set the reduced flag to indicate that
+    // this part must be replaced.
+    function shortenPart(part, minus){
+      part.currentText = part.currentText.substring(minus);
+      part.reduced = true;
+    }
+    // Create a part corresponding to a given token.
+    function tokenPart(token){
+      var part = withDocument(document, partial(SPAN, {"class": "part " + token.style}, token.value));
+      part.currentText = token.value;
+      return part;
+    }
+
+    // Get the token stream. If from is null, we start with a new
+    // parser from the start of the frame, otherwise a partial parse
+    // is resumed.
+    var parsed = from ? from.parserFromHere(multiStringStream(traverseDOM(from.nextSibling)))
+      : this.options.parser(multiStringStream(traverseDOM(container.firstChild)));
+
+    // parts is a wrapper that makes it possible to 'delay' going to
+    // the next DOM node until we are completely done with the one
+    // before it. This is necessary because we are constantly poking
+    // around in the DOM tree, and if the next node is fetched to
+    // early it might get replaced before it is used.
+    var parts = {
+      current: null,
+      forward: false,
+      // Get the current part.
+      get: function(){
+        if (!this.current)
+          this.current = from ? from.nextSibling : container.firstChild;
+        else if (this.forward)
+          this.current = this.current.nextSibling;
+        this.forward = false;
+        return this.current;
+      },
+      // Advance to the next part (do not fetch it yet).
+      next: function(){
+        if (this.forward)
+          this.get();
+        this.forward = true;
+      },
+      // Remove the current part from the DOM tree, and move to the
+      // next.
+      remove: function(){
+        this.current = this.get().previousSibling;
+        container.removeChild(this.current ? this.current.nextSibling : container.firstChild);
+        this.forward = true;
+      },
+      // Advance to the next part that is not empty, discarding empty
+      // parts.
+      nextNonEmpty: function(){
+        var part = this.get();
+        while (part.nodeName == "SPAN" && part.currentText == ""){
+          var old = part;
+          this.remove();
+          part = this.get();
+         // Adjust selection information, if any. See select.js for
+         // details.
+          select.replaceSelection(old.firstChild, part.firstChild || part, 0, 0);
+        }
+        return part;
+      }
+    };
+
+    var lineDirty = false;
+
+    // This forEach loops over the tokens from the parsed stream, and
+    // at the same time uses the parts object to proceed through the
+    // corresponding DOM nodes.
+    forEach(parsed, function(token){
+      var part = parts.nextNonEmpty();
+      if (token.value == "\n"){
+       // The idea of the two streams actually staying synchronized
+       // is such a long shot that we explicitly check.
+        if (part.nodeName != "BR")
+          throw "Parser out of sync. Expected BR.";
+        if (part.dirty || !part.lexicalContext)
+          lineDirty = true;
+       // Every <br> gets a copy of the parser state and a lexical
+       // context assigned to it. The first is used to be able to
+       // later resume parsing from this point, the second is used
+       // for indentation.
+        part.parserFromHere = parsed.copy();
+        part.lexicalContext = token.lexicalContext;
+        part.dirty = false;
+       // A clean line means we are done. Throwing a StopIteration is
+       // the way to break out of a MochiKit forEach loop.
+        if ((lines !== undefined && --lines <= 0) || !lineDirty)
+          throw StopIteration;
+        lineDirty = false;
+        parts.next();
+      }
+      else {
+        if (part.nodeName != "SPAN")
+          throw "Parser out of sync. Expected SPAN.";
+        if (part.dirty)
+          lineDirty = true;
+
+       // If the part matches the token, we can leave it alone.
+        if (correctPart(token, part)){
+          part.dirty = false;
+          parts.next();
+        }
+       // Otherwise, we have to fix it.
+        else {
+          lineDirty = true;
+         // Insert the correct part.
+          var newPart = tokenPart(token);
+          container.insertBefore(newPart, part);
+          var tokensize = token.value.length;
+          var offset = 0;
+         // Eat up parts until the text for this token has been
+         // removed, adjusting the stored selection info (see
+         // select.js) in the process.
+          while (tokensize > 0) {
+            part = parts.get();
+            var partsize = part.currentText.length;
+            select.replaceSelection(part.firstChild, newPart.firstChild, tokensize, offset);
+            if (partsize > tokensize){
+              shortenPart(part, tokensize);
+              tokensize = 0;
+            }
+            else {
+              tokensize -= partsize;
+              offset += partsize;
+              parts.remove();
+            }
+          }
+        }
+      }
+    });
+    this.refreshCursorObj();
+    this.initable = 1;
+    window.setTimeout ('t3e_instances['+this.index+'].checkHistoryChanges();',100);
+    // The function returns some status information that is used by
+    // hightlightDirty to determine whether and where it has to
+    // continue.
+    return {left: lines,
+            node: parts.get(),
+            dirty: lineDirty};
+  }
+
+  return t3editor;
+}();
+
+
+// ------------------------------------------------------------------------
+
+
+
+function t3editor_toggleEditor(checkbox,index) {
+       if (index == undefined) {
+               $$('textarea.t3editor').each(
+                       function(textarea,i) {
+                               t3editor_toggleEditor(checkbox,i);
+                       }
+               );      \r
+       } else {
+               if (t3e_instances[index] != undefined) {
+                       var t3e = t3e_instances[index];
+                       t3e.toggleView(checkbox.checked);
+               } else if (!checkbox.checked) {
+                       var t3e = new t3editor($$('textarea.t3editor')[index], index);
+                       t3e_instances[index] = t3e;
+               }\r
+       }       
+}
+
+// ------------------------------------------------------------------------
+
+
+/**
+ * everything ready: turn textareas into fancy editors
+ */
+Event.observe(window,'load',function() {
+       $$('textarea.t3editor').each(
+               function(textarea,i) {
+                       if ($('t3editor_disableEditor_'+(i+1)+'_checkbox') && !$('t3editor_disableEditor_'+(i+1)+'_checkbox').checked) {
+                               var t3e = new t3editor(textarea,i);
+                               t3e_instances[i] = t3e;
+                       }
+               }
+       );
+});
diff --git a/typo3/sysext/t3editor/jslib/tokenizejavascript.js b/typo3/sysext/t3editor/jslib/tokenizejavascript.js
new file mode 100644 (file)
index 0000000..d723f58
--- /dev/null
@@ -0,0 +1,193 @@
+/* Tokenizer for JavaScript code */
+
+var tokenizeJavaScript = function(){
+  // 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 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", "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, "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", "keyword"), "function": result("function", "keyword"), "catch": result("catch", "keyword"),
+      "for": result("for", "keyword"), "case": result("case", "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\$_]/);
+  function isWhiteSpace(ch){
+    // Unfortunately, IE's regexp matcher thinks non-breaking spaces
+    // aren't whitespace. Also, in our scheme newlines are no
+    // whitespace (they are another special case).
+    return ch != "\n" && (ch == nbsp || /\s/.test(ch));
+  }
+
+  // This function produces a MochiKit-style iterator that tokenizes
+  // the output of the given stringstream (see stringstream.js).
+  // Tokens are objects with a type, style, and value property. The
+  // value contains the textual content of the token. Because this may
+  // include trailing whitespace (for efficiency reasons), some
+  // tokens, such a variable names, also have a name property
+  // containing their actual textual value.
+  return function(source){
+    // Produce a value to return. Automatically skips and includes any
+    // whitespace. The base argument is prepended to the value
+    // property and assigned to the name property -- this is used when
+    // the caller has already extracted the text from the stream
+    // himself.
+    function result(type, style, base){
+      nextWhile(isWhiteSpace);
+      var value = {type: type, style: style, value: (base ? base + source.get() : source.get())};
+      if (base) value.name = base;
+      return value;
+    }
+
+    // Advance the text stream over characters for which test returns
+    // true. (The characters that are 'consumed' like this can later
+    // be retrieved by calling source.get()).
+    function nextWhile(test){
+      var next;
+      while((next = source.peek()) && test(next))
+        source.next();
+    }
+    // Advance the stream until the given character (not preceded by a
+    // backslash) is encountered (or a newline is found).
+    function nextUntilUnescaped(end){
+      var escaped = false;
+      var next;
+      while((next = source.peek()) && next != "\n"){
+        source.next();
+        if (next == end && !escaped)
+          break;
+        escaped = next == "\\";
+      }
+    }
+  
+    function readHexNumber(){
+      source.next(); // skip the 'x'
+      nextWhile(isHexDigit);
+      return result("number", "atom");
+    }
+    function readNumber(){
+      nextWhile(isDigit);
+      if (source.peek() == "."){
+        source.next();
+        nextWhile(isDigit);
+      }
+      if (source.peek() == "e" || source.peek() == "E"){
+        source.next();
+        if (source.peek() == "-")
+          source.next();
+        nextWhile(isDigit);
+      }
+      return result("number", "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(){
+      nextWhile(isWordChar);
+      var word = source.get();
+      var known = keywords.hasOwnProperty(word) && keywords.propertyIsEnumerable(word) && keywords[word];
+      return known ? result(known.type, known.style, word) : result("variable", "variable", word);
+    }
+    function readRegexp(){
+      nextUntilUnescaped("/");
+      nextWhile(matcher(/[gi]/));
+      return result("regexp", "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 (inComment) to indicate whether we
+    // are inside a /* */ sequence.
+    function readMultilineComment(start){
+      this.inComment = true;
+      var maybeEnd = (start == "*");
+      while(true){
+        var next = source.peek();
+        if (next == "\n")
+          break;
+        source.next();
+        if (next == "/" && maybeEnd){
+          this.inComment = false;
+          break;
+        }
+        maybeEnd = (next == "*");
+      }
+      return result("comment", "comment");
+    }
+
+    // Fetch the next token. Dispatches on first character in the
+    // stream, or first two characters when the first is a slash. The
+    // || things are a silly trick to keep simple cases on a single
+    // line.
+    function next(){
+      var token = null;
+      var ch = source.next();
+      if (ch == "\n")
+        token = {type: "newline", style: "whitespace", value: source.get()};
+      else if (this.inComment)
+        token = readMultilineComment.call(this, ch);
+      else if (isWhiteSpace(ch))
+        token = nextWhile(isWhiteSpace) || result("whitespace", "whitespace");
+      else if (ch == "\"" || ch == "'")
+        token = nextUntilUnescaped(ch) || result("string", "string");
+      // with punctuation, the type of the token is the symbol itself
+      else if (/[\[\]{}\(\),;\:\.]/.test(ch))
+        token = result(ch, "punctuation");
+      else if (ch == "0" && (source.peek() == "x" || source.peek() == "X"))
+        token = readHexNumber();
+      else if (isDigit(ch))
+        token = readNumber();
+      else if (ch == "/"){
+        next = source.peek();
+        if (next == "*")
+          token = readMultilineComment.call(this, ch);
+        else if (next == "/")
+          token = nextUntilUnescaped(null) || result("comment", "comment");
+        else if (this.regexp)
+          token = readRegexp();
+        else
+          token = nextWhile(isOperatorChar) || result("operator", "operator");
+      }
+      else if (isOperatorChar(ch))
+        token = nextWhile(isOperatorChar) || result("operator", "operator");
+      else
+        token = readWord();
+
+      // JavaScript's syntax rules for when a slash might be the start
+      // of a regexp and when it is just a division operator are kind
+      // of non-obvious. This decides, based on the current token,
+      // whether the next token could be a regular expression.
+      if (token.style != "whitespace" && token != "comment")
+        this.regexp = token.type == "operator" || token.type == "keyword c" || token.type.match(/[\[{}\(,;:]/);
+      return token;
+    }
+
+    // Wrap it in an iterator. The state (regexp and inComment) is
+    // exposed because a parser will need to save it when making a
+    // copy of its state.
+    return {next: next, regexp: true, inComment: false};
+  }
+}();
diff --git a/typo3/sysext/t3editor/jslib/tokenizetyposcript.js b/typo3/sysext/t3editor/jslib/tokenizetyposcript.js
new file mode 100755 (executable)
index 0000000..0556099
--- /dev/null
@@ -0,0 +1,1373 @@
+/* Tokenizer for TypoScript code 
+ * 
+ * based on tokenizejavascript.js by Marijn Haverbeke
+ */
+
+// List of "reserved" word in typoscript and a css-class
+var typoscriptWords = {
+       '_CSS_DEFAULT_STYLE'    : 'keyword',
+       '_DEFAULT_PI_VARS'              : 'keyword',
+       '_GIFBUILDER'                   : 'keyword',
+       '_LOCAL_LANG'                   : 'keyword',
+       'CARRAY'                                : 'keyword',
+       'CASE'                                  : 'keyword',
+       'CLEARGIF'                              : 'keyword',
+       'COA'                                   : 'keyword',
+       'COA_INT'                               : 'keyword',
+       'COBJ_ARRAY'                    : 'keyword',
+       'COLUMNS'                               : 'keyword',
+       'CONFIG'                                : 'keyword',
+       'CONSTANTS'                             : 'keyword',
+       'CONTENT'                               : 'keyword',
+       'CTABLE'                                : 'keyword',
+       'CType'                                 : 'keyword',
+       'DB'                                    : 'keyword',
+       'DOCUMENT_BODY'                 : 'keyword',
+       'EDITPANEL'                             : 'keyword',
+       'EFFECT'                                : 'keyword',
+       'FE_DATA'                               : 'keyword',
+       'FE_TABLE'                              : 'keyword',
+       'FEData'                                : 'keyword',
+       'FILE'                                  : 'keyword',
+       'FORM'                                  : 'keyword',
+       'FRAME'                                 : 'keyword',
+       'FRAMESET'                              : 'keyword',
+       'GIFBUILDER'                    : 'keyword',
+       'global'                                : 'keyword',
+       'globalString'                  : 'keyword',
+       'globalVar'                             : 'keyword',
+       'GMENU'                                 : 'keyword',
+       'GMENU_FOLDOUT'                 : 'keyword',
+       'GMENU_LAYERS'                  : 'keyword',
+       'GP'                                    : 'keyword',
+       'HMENU'                                 : 'keyword',
+       'HRULER'                                : 'keyword',
+       'HTML'                                  : 'keyword',
+       'IENV'                                  : 'keyword',
+       'IMAGE'                                 : 'keyword',
+       'IMG_RESOURCE'                  : 'keyword',
+       'IMGMENU'                               : 'keyword',
+       'IMGMENUITEM'                   : 'keyword',
+       'IMGTEXT'                               : 'keyword',
+       'INCLUDE_TYPOSCRIPT'    : 'keyword',
+       'includeLibs'                   : 'keyword',
+       'JSMENU'                                : 'keyword',
+       'JSMENUITEM'                    : 'keyword',
+       'LIT'                                   : 'keyword',
+       'LOAD_REGISTER'                 : 'keyword',
+       'META'                                  : 'keyword',
+       'MULTIMEDIA'                    : 'keyword',
+       'OTABLE'                                : 'keyword',
+       'PAGE'                                  : 'keyword',
+       'PAGE_TARGET'                   : 'keyword',
+       'PAGE_TSCONFIG_ID'              : 'keyword',
+       'PAGE_TSCONFIG_IDLIST'  : 'keyword',
+       'PAGE_TSCONFIG_STR'             : 'keyword',
+       'PHP_SCRIPT'                    : 'keyword',
+       'PHP_SCRIPT_EXT'                : 'keyword',
+       'PHP_SCRIPT_INT'                : 'keyword',
+       'RECORDS'                               : 'keyword',
+       'REMOTE_ADDR'                   : 'keyword',
+       'RESTORE_REGISTER'              : 'keyword',
+       'RTE'                                   : 'keyword',
+       'SEARCHRESULT'                  : 'keyword',
+       'SHARED'                                : 'keyword',
+       'TCAdefaults'                   : 'keyword',
+       'TCEFORM'                               : 'keyword',
+       'TCEMAIN'                               : 'keyword',
+       'TEMPLATE'                              : 'keyword',
+       'TEXT'                                  : 'keyword',
+       'TMENU'                                 : 'keyword',
+       'TMENU_LAYERS'                  : 'keyword',
+       'TMENUITEM'                             : 'keyword',
+       'TSFE'                                  : 'keyword',
+       'USER'                                  : 'keyword',
+       'USER_INT'                              : 'keyword',
+       'userFunc'                              : 'keyword',
+       
+       '_offset'                               : 'reserved',
+       'absRefPrefix'  : 'reserved',
+       'accessibility' : 'reserved',
+       'accessKey'     : 'reserved',
+       'addAttributes' : 'reserved',
+       'addExtUrlsAndShortCuts'        : 'reserved',
+       'addItems'      : 'reserved',
+       'additionalHeaders'     : 'reserved',
+       'additionalParams'      : 'reserved',
+       'addParams'     : 'reserved',
+       'addQueryString'        : 'reserved',
+       'adjustItemsH'  : 'reserved',
+       'adjustSubItemsH'       : 'reserved',
+       'adminPanelStyles'      : 'reserved',
+       'after' : 'reserved',
+       'afterImg'      : 'reserved',
+       'afterImgLink'  : 'reserved',
+       'afterImgTagParams'     : 'reserved',
+       'afterROImg'    : 'reserved',
+       'afterWrap'     : 'reserved',
+       'age'   : 'reserved',
+       'alertPopups'   : 'reserved',
+       'align' : 'reserved',
+       'allow' : 'reserved',
+       'allowCaching'  : 'reserved',
+       'allowedAttribs'        : 'reserved',
+       'allowedClasses'        : 'reserved',
+       'allowedCols'   : 'reserved',
+       'allowEdit'     : 'reserved',
+       'allowedNewTables'      : 'reserved',
+       'allowNew'      : 'reserved',
+       'allowTags'     : 'reserved',
+       'allowTVlisting'        : 'reserved',
+       'allSaveFunctions'      : 'reserved',
+       'allStdWrap'    : 'reserved',
+       'allWrap'       : 'reserved',
+       'alternateBgColors'     : 'reserved',
+       'alternativeSortingField'       : 'reserved',
+       'alternativeTempPath'   : 'reserved',
+       'altImgResource'        : 'reserved',
+       'altLabels'     : 'reserved',
+       'altTarget'     : 'reserved',
+       'altText'       : 'reserved',
+       'altUrl'        : 'reserved',
+       'altUrl_noDefaultParams'        : 'reserved',
+       'altWrap'       : 'reserved',
+       'always'        : 'reserved',
+       'alwaysActivePIDlist'   : 'reserved',
+       'alwaysLink'    : 'reserved',
+       'alwaysShowClickMenuInTopFrame' : 'reserved',
+       'andWhere'      : 'reserved',
+       'angle' : 'reserved',
+       'antiAlias'     : 'reserved',
+       'append'        : 'reserved',
+       'applyTotalH'   : 'reserved',
+       'applyTotalW'   : 'reserved',
+       'archive'       : 'reserved',
+       'archiveTypoLink'       : 'reserved',
+       'arrayReturnMode'       : 'reserved',
+       'arrowACT'      : 'reserved',
+       'arrowImgParams'        : 'reserved',
+       'arrowNO'       : 'reserved',
+       'ATagAfterWrap' : 'reserved',
+       'ATagBeforeWrap'        : 'reserved',
+       'ATagParams'    : 'reserved',
+       'ATagTitle'     : 'reserved',
+       'attribute'     : 'reserved',
+       'autoInsertPID' : 'reserved',
+       'autoLevels'    : 'reserved',
+       'autonumber'    : 'reserved',
+       'backColor'     : 'reserved',
+       'background'    : 'reserved',
+       'badMess'       : 'reserved',
+       'baseURL'       : 'reserved',
+       'before'        : 'reserved',
+       'beforeImg'     : 'reserved',
+       'beforeImgLink' : 'reserved',
+       'beforeImgTagParams'    : 'reserved',
+       'beforeROImg'   : 'reserved',
+       'beforeWrap'    : 'reserved',
+       'begin' : 'reserved',
+       'beLoginLinkIPList'     : 'reserved',
+       'beLoginLinkIPList_login'       : 'reserved',
+       'beLoginLinkIPList_logout'      : 'reserved',
+       'bgCol' : 'reserved',
+       'bgImg' : 'reserved',
+       'blankStrEqFalse'       : 'reserved',
+       'blur'  : 'reserved',
+       'bm'    : 'reserved',
+       'bodyTag'       : 'reserved',
+       'bodyTagAdd'    : 'reserved',
+       'bodyTagCObject'        : 'reserved',
+       'bodyTagMargins'        : 'reserved',
+       'bodytext'      : 'reserved',
+       'border'        : 'reserved',
+       'borderCol'     : 'reserved',
+       'bordersWithin' : 'reserved',
+       'borderThick'   : 'reserved',
+       'bottomBackColor'       : 'reserved',
+       'bottomContent' : 'reserved',
+       'bottomHeight'  : 'reserved',
+       'bottomImg'     : 'reserved',
+       'bottomImg_mask'        : 'reserved',
+       'br'    : 'reserved',
+       'brTag' : 'reserved',
+       'bullet'        : 'reserved',
+       'bulletlist'    : 'reserved',
+       'bytes' : 'reserved',
+       'cache_clearAtMidnight' : 'reserved',
+       'cache_period'  : 'reserved',
+       'caption'       : 'reserved',
+       'caption_stdWrap'       : 'reserved',
+       'captionAlign'  : 'reserved',
+       'captionHeader' : 'reserved',
+       'captionSplit'  : 'reserved',
+       'case'  : 'reserved',
+       'casesensitiveComp'     : 'reserved',
+       'cellpadding'   : 'reserved',
+       'cellspacing'   : 'reserved',
+       'centerImgACT'  : 'reserved',
+       'centerImgCUR'  : 'reserved',
+       'centerImgNO'   : 'reserved',
+       'centerLeftImgACT'      : 'reserved',
+       'centerLeftImgCUR'      : 'reserved',
+       'centerLeftImgNO'       : 'reserved',
+       'centerRightImgACT'     : 'reserved',
+       'centerRightImgCUR'     : 'reserved',
+       'centerRightImgNO'      : 'reserved',
+       'char'  : 'reserved',
+       'charcoal'      : 'reserved',
+       'charMapConfig' : 'reserved',
+       'check' : 'reserved',
+       'class' : 'reserved',
+       'classesAnchor' : 'reserved',
+       'classesCharacter'      : 'reserved',
+       'classesImage'  : 'reserved',
+       'classesParagraph'      : 'reserved',
+       'classicPageEditMode'   : 'reserved',
+       'clear' : 'reserved',
+       'clearCache'    : 'reserved',
+       'clearCache_disable'    : 'reserved',
+       'clearCache_pageGrandParent'    : 'reserved',
+       'clearCache_pageSiblingChildren'        : 'reserved',
+       'clearCacheCmd' : 'reserved',
+       'clearCacheLevels'      : 'reserved',
+       'clearCacheOfPages'     : 'reserved',
+       'clickMenuTimeOut'      : 'reserved',
+       'clickTitleMode'        : 'reserved',
+       'clipboardNumberPads'   : 'reserved',
+       'cMargins'      : 'reserved',
+       'cObjNum'       : 'reserved',
+       'collapse'      : 'reserved',
+       'color' : 'reserved',
+       'color1'        : 'reserved',
+       'color2'        : 'reserved',
+       'color3'        : 'reserved',
+       'color4'        : 'reserved',
+       'colors'        : 'reserved',
+       'colour'        : 'reserved',
+       'colPos_list'   : 'reserved',
+       'colRelations'  : 'reserved',
+       'cols'  : 'reserved',
+       'colSpace'      : 'reserved',
+       'comment_auto'  : 'reserved',
+       'commentWrap'   : 'reserved',
+       'compensateFieldWidth'  : 'reserved',
+       'compX' : 'reserved',
+       'compY' : 'reserved',
+       'condensedMode' : 'reserved',
+       'conf'  : 'reserved',
+       'constants'     : 'reserved',
+       'content_from_pid_allowOutsideDomain'   : 'reserved',
+       'contextMenu'   : 'reserved',
+       'copyLevels'    : 'reserved',
+       'count_HMENU_MENUOBJ'   : 'reserved',
+       'count_menuItems'       : 'reserved',
+       'count_MENUOBJ' : 'reserved',
+       'create'        : 'reserved',
+       'createFoldersInEB'     : 'reserved',
+       'crop'  : 'reserved',
+       'csConv'        : 'reserved',
+       'CSS_inlineStyle'       : 'reserved',
+       'current'       : 'reserved',
+       'curUid'        : 'reserved',
+       'cWidth'        : 'reserved',
+       'data'  : 'reserved',
+       'dataWrap'      : 'reserved',
+       'date'  : 'reserved',
+       'date_stdWrap'  : 'reserved',
+       'datePrefix'    : 'reserved',
+       'debug' : 'reserved',
+       'debugData'     : 'reserved',
+       'debugFunc'     : 'reserved',
+       'debugItemConf' : 'reserved',
+       'debugRenumberedObject' : 'reserved',
+       'default'       : 'reserved',
+       'defaultAlign'  : 'reserved',
+       'defaultCmd'    : 'reserved',
+       'defaultFileUploads'    : 'reserved',
+       'defaultHeaderType'     : 'reserved',
+       'defaultOutput' : 'reserved',
+       'defaults'      : 'reserved',
+       'defaultType'   : 'reserved',
+       'delete'        : 'reserved',
+       'denyTags'      : 'reserved',
+       'depth' : 'reserved',
+       'DESC'  : 'reserved',
+       'dimensions'    : 'reserved',
+       'directionLeft' : 'reserved',
+       'directionUp'   : 'reserved',
+       'disableAdvanced'       : 'reserved',
+       'disableAllHeaderCode'  : 'reserved',
+       'disableAltText'        : 'reserved',
+       'disableBigButtons'     : 'reserved',
+       'disableCacheSelector'  : 'reserved',
+       'disableCharsetHeader'  : 'reserved',
+       'disableCMlayers'       : 'reserved',
+       'disabled'      : 'reserved',
+       'disableDelete' : 'reserved',
+       'disableDocModuleInAB'  : 'reserved',
+       'disableDocSelector'    : 'reserved',
+       'disableHideAtCopy'     : 'reserved',
+       'disableIconLinkToContextmenu'  : 'reserved',
+       'disableItems'  : 'reserved',
+       'disableNewContentElementWizard'        : 'reserved',
+       'disableNoMatchingValueElement' : 'reserved',
+       'disablePageExternalUrl'        : 'reserved',
+       'disablePrefixComment'  : 'reserved',
+       'disablePrependAtCopy'  : 'reserved',
+       'disableSearchBox'      : 'reserved',
+       'disableSingleTableView'        : 'reserved',
+       'disableTabInTextarea'  : 'reserved',
+       'displayActiveOnLoad'   : 'reserved',
+       'displayContent'        : 'reserved',
+       'displayFieldIcons'     : 'reserved',
+       'displayIcons'  : 'reserved',
+       'displayMessages'       : 'reserved',
+       'displayQueries'        : 'reserved',
+       'displayRecord' : 'reserved',
+       'displayTimes'  : 'reserved',
+       'distributeX'   : 'reserved',
+       'distributeY'   : 'reserved',
+       'DIV'   : 'reserved',
+       'doctype'       : 'reserved',
+       'doctypeSwitch' : 'reserved',
+       'doktype'       : 'reserved',
+       'doNotLinkIt'   : 'reserved',
+       'doNotShowLink' : 'reserved',
+       'doNotStripHTML'        : 'reserved',
+       'dontCheckPid'  : 'reserved',
+       'dontFollowMouse'       : 'reserved',
+       'dontHideOnMouseUp'     : 'reserved',
+       'dontLinkIfSubmenu'     : 'reserved',
+       'dontShowPalettesOnFocusInAB'   : 'reserved',
+       'dontWrapInTable'       : 'reserved',
+       'doubleBrTag'   : 'reserved',
+       'doublePostCheck'       : 'reserved',
+       'dWorkArea'     : 'reserved',
+       'edge'  : 'reserved',
+       'edit_docModuleUplaod'  : 'reserved',
+       'edit_docModuleUpload'  : 'reserved',
+       'edit_RTE'      : 'reserved',
+       'edit_showFieldHelp'    : 'reserved',
+       'edit_wideDocument'     : 'reserved',
+       'editFieldsAtATime'     : 'reserved',
+       'editFormsOnPage'       : 'reserved',
+       'editIcons'     : 'reserved',
+       'editNoPopup'   : 'reserved',
+       'editPanel'     : 'reserved',
+       'elements'      : 'reserved',
+       'emailMeAtLogin'        : 'reserved',
+       'emailMess'     : 'reserved',
+       'emboss'        : 'reserved',
+       'enable'        : 'reserved',
+       'encapsLines'   : 'reserved',
+       'encapsLinesStdWrap'    : 'reserved',
+       'encapsTagList' : 'reserved',
+       'entryLevel'    : 'reserved',
+       'equalH'        : 'reserved',
+       'everybody'     : 'reserved',
+       'excludeDoktypes'       : 'reserved',
+       'excludeUidList'        : 'reserved',
+       'expAll'        : 'reserved',
+       'expand'        : 'reserved',
+       'explode'       : 'reserved',
+       'ext'   : 'reserved',
+       'externalBlocks'        : 'reserved',
+       'extTarget'     : 'reserved',
+       'face'  : 'reserved',
+       'fe_adminLib'   : 'reserved',
+       'field' : 'reserved',
+       'fieldOrder'    : 'reserved',
+       'fieldRequired' : 'reserved',
+       'fields'        : 'reserved',
+       'fieldWrap'     : 'reserved',
+       'file'  : 'reserved',
+       'file1' : 'reserved',
+       'file2' : 'reserved',
+       'file3' : 'reserved',
+       'file4' : 'reserved',
+       'file5' : 'reserved',
+       'filelink'      : 'reserved',
+       'filelist'      : 'reserved',
+       'firstLabel'    : 'reserved',
+       'firstLabelGeneral'     : 'reserved',
+       'fixAttrib'     : 'reserved',
+       'flip'  : 'reserved',
+       'flop'  : 'reserved',
+       'foldSpeed'     : 'reserved',
+       'foldTimer'     : 'reserved',
+       'fontColor'     : 'reserved',
+       'fontFile'      : 'reserved',
+       'fontOffset'    : 'reserved',
+       'fontSize'      : 'reserved',
+       'fontSizeMultiplicator' : 'reserved',
+       'fontTag'       : 'reserved',
+       'forceDisplayFieldIcons'        : 'reserved',
+       'forceDisplayIcons'     : 'reserved',
+       'forceNoPopup'  : 'reserved',
+       'forceTemplateParsing'  : 'reserved',
+       'forceTypeValue'        : 'reserved',
+       'format'        : 'reserved',
+       'frame' : 'reserved',
+       'frameReloadIfNotInFrameset'    : 'reserved',
+       'frameSet'      : 'reserved',
+       'freezeMouseover'       : 'reserved',
+       'ftu'   : 'reserved',
+       'function'      : 'reserved',
+       'gamma' : 'reserved',
+       'gapBgCol'      : 'reserved',
+       'gapLineCol'    : 'reserved',
+       'gapLineThickness'      : 'reserved',
+       'gapWidth'      : 'reserved',
+       'get'   : 'reserved',
+       'getBorder'     : 'reserved',
+       'getLeft'       : 'reserved',
+       'getRight'      : 'reserved',
+       'globalNesting' : 'reserved',
+       'goodMess'      : 'reserved',
+       'gray'  : 'reserved',
+       'group' : 'reserved',
+       'groupBy'       : 'reserved',
+       'groupid'       : 'reserved',
+       'header'        : 'reserved',
+       'header_layout' : 'reserved',
+       'headerComment' : 'reserved',
+       'headerData'    : 'reserved',
+       'headerSpace'   : 'reserved',
+       'headTag'       : 'reserved',
+       'height'        : 'reserved',
+       'helpText'      : 'reserved',
+       'hidden'        : 'reserved',
+       'hiddenFields'  : 'reserved',
+       'hide'  : 'reserved',
+       'hideButCreateMap'      : 'reserved',
+       'hideMenuTimer' : 'reserved',
+       'hideMenuWhenNotOver'   : 'reserved',
+       'hidePStyleItems'       : 'reserved',
+       'hideRecords'   : 'reserved',
+       'hideSubmoduleIcons'    : 'reserved',
+       'highColor'     : 'reserved',
+       'history'       : 'reserved',
+       'hover' : 'reserved',
+       'hoverStyle'    : 'reserved',
+       'HTMLparser'    : 'reserved',
+       'HTMLparser_tags'       : 'reserved',
+       'htmlSpecialChars'      : 'reserved',
+       'htmlTag_dir'   : 'reserved',
+       'htmlTag_langKey'       : 'reserved',
+       'htmlTag_setParams'     : 'reserved',
+       'http'  : 'reserved',
+       'icon'  : 'reserved',
+       'icon_image_ext_list'   : 'reserved',
+       'icon_link'     : 'reserved',
+       'iconCObject'   : 'reserved',
+       'ifEmpty'       : 'reserved',
+       'image' : 'reserved',
+       'image_compression'     : 'reserved',
+       'image_effects' : 'reserved',
+       'image_frames'  : 'reserved',
+       'imageLinkWrap' : 'reserved',
+       'imagePath'     : 'reserved',
+       'images'        : 'reserved',
+       'imageWrapIfAny'        : 'reserved',
+       'imgList'       : 'reserved',
+       'imgMap'        : 'reserved',
+       'imgMapExtras'  : 'reserved',
+       'imgMax'        : 'reserved',
+       'imgNameNotRandom'      : 'reserved',
+       'imgNamePrefix' : 'reserved',
+       'imgObjNum'     : 'reserved',
+       'imgParams'     : 'reserved',
+       'imgPath'       : 'reserved',
+       'imgStart'      : 'reserved',
+       'import'        : 'reserved',
+       'inc'   : 'reserved',
+       'includeCSS'    : 'reserved',
+       'includeLibrary'        : 'reserved',
+       'includeNotInMenu'      : 'reserved',
+       'incT3Lib_htmlmail'     : 'reserved',
+       'index' : 'reserved',
+       'index_descrLgd'        : 'reserved',
+       'index_enable'  : 'reserved',
+       'index_externals'       : 'reserved',
+       'inlineStyle2TempFile'  : 'reserved',
+       'innerStdWrap'  : 'reserved',
+       'innerStdWrap_all'      : 'reserved',
+       'innerWrap'     : 'reserved',
+       'innerWrap2'    : 'reserved',
+       'input' : 'reserved',
+       'inputLevels'   : 'reserved',
+       'insertClassesFromRTE'  : 'reserved',
+       'insertData'    : 'reserved',
+       'insertDmailerBoundaries'       : 'reserved',
+       'intensity'     : 'reserved',
+       'intTarget'     : 'reserved',
+       'intval'        : 'reserved',
+       'invert'        : 'reserved',
+       'IProcFunc'     : 'reserved',
+       'itemArrayProcFunc'     : 'reserved',
+       'itemH' : 'reserved',
+       'items' : 'reserved',
+       'itemsProcFunc' : 'reserved',
+       'iterations'    : 'reserved',
+       'join'  : 'reserved',
+       'JSWindow'      : 'reserved',
+       'JSwindow_params'       : 'reserved',
+       'jumpurl'       : 'reserved',
+       'jumpUrl'       : 'reserved',
+       'jumpurl_enable'        : 'reserved',
+       'jumpurl_mailto_disable'        : 'reserved',
+       'jumpUrl_transferSession'       : 'reserved',
+       'keep'  : 'reserved',
+       'keepEntries'   : 'reserved',
+       'keepNonMatchedTags'    : 'reserved',
+       'key'   : 'reserved',
+       'label' : 'reserved',
+       'labelStdWrap'  : 'reserved',
+       'labelWrap'     : 'reserved',
+       'lang'  : 'reserved',
+       'language'      : 'reserved',
+       'language_alt'  : 'reserved',
+       'languageField' : 'reserved',
+       'layer_menu_id' : 'reserved',
+       'layerStyle'    : 'reserved',
+       'left'  : 'reserved',
+       'leftIcons'     : 'reserved',
+       'leftImgACT'    : 'reserved',
+       'leftImgCUR'    : 'reserved',
+       'leftImgNO'     : 'reserved',
+       'leftjoin'      : 'reserved',
+       'leftOffset'    : 'reserved',
+       'levels'        : 'reserved',
+       'leveluid'      : 'reserved',
+       'limit' : 'reserved',
+       'line'  : 'reserved',
+       'lineColor'     : 'reserved',
+       'lineThickness' : 'reserved',
+       'linkPrefix'    : 'reserved',
+       'linkTitleToSelf'       : 'reserved',
+       'linkVars'      : 'reserved',
+       'linkWrap'      : 'reserved',
+       'listNum'       : 'reserved',
+       'listOnlyInSingleTableView'     : 'reserved',
+       'lm'    : 'reserved',
+       'locale_all'    : 'reserved',
+       'localNesting'  : 'reserved',
+       'locationData'  : 'reserved',
+       'lockFilePath'  : 'reserved',
+       'lockPosition'  : 'reserved',
+       'lockPosition_addSelf'  : 'reserved',
+       'lockPosition_adjust'   : 'reserved',
+       'lockToIP'      : 'reserved',
+       'longdescURL'   : 'reserved',
+       'lowColor'      : 'reserved',
+       'lower' : 'reserved',
+       'LR'    : 'reserved',
+       'mailto'        : 'reserved',
+       'main'  : 'reserved',
+       'mainScript'    : 'reserved',
+       'makelinks'     : 'reserved',
+       'markerWrap'    : 'reserved',
+       'mask'  : 'reserved',
+       'max'   : 'reserved',
+       'maxAge'        : 'reserved',
+       'maxAgeDays'    : 'reserved',
+       'maxChars'      : 'reserved',
+       'maxH'  : 'reserved',
+       'maxHeight'     : 'reserved',
+       'maxItems'      : 'reserved',
+       'maxW'  : 'reserved',
+       'maxWidth'      : 'reserved',
+       'maxWInText'    : 'reserved',
+       'mayNotCreateEditShortcuts'     : 'reserved',
+       'menu_type'     : 'reserved',
+       'menuBackColor' : 'reserved',
+       'menuHeight'    : 'reserved',
+       'menuName'      : 'reserved',
+       'menuOffset'    : 'reserved',
+       'menuWidth'     : 'reserved',
+       'message_page_is_being_generated'       : 'reserved',
+       'message_preview'       : 'reserved',
+       'meta'  : 'reserved',
+       'metaCharset'   : 'reserved',
+       'method'        : 'reserved',
+       'min'   : 'reserved',
+       'minH'  : 'reserved',
+       'minItems'      : 'reserved',
+       'minW'  : 'reserved',
+       'mode'  : 'reserved',
+       'moduleMenuCollapsable' : 'reserved',
+       'MP_defaults'   : 'reserved',
+       'MP_disableTypolinkClosestMPvalue'      : 'reserved',
+       'MP_mapRootPoints'      : 'reserved',
+       'name'  : 'reserved',
+       'navFrameResizable'     : 'reserved',
+       'navFrameWidth' : 'reserved',
+       'nesting'       : 'reserved',
+       'netprintApplicationLink'       : 'reserved',
+       'neverHideAtCopy'       : 'reserved',
+       'newPageWiz'    : 'reserved',
+       'newRecordFromTable'    : 'reserved',
+       'newWindow'     : 'reserved',
+       'newWizards'    : 'reserved',
+       'next'  : 'reserved',
+       'niceText'      : 'reserved',
+       'nicetext'      : 'reserved',
+       'no_cache'      : 'reserved',
+       'no_search'     : 'reserved',
+       'noAttrib'      : 'reserved',
+       'noBlur'        : 'reserved',
+       'noCache'       : 'reserved',
+       'noCols'        : 'reserved',
+       'noCreateRecordsLink'   : 'reserved',
+       'noLink'        : 'reserved',
+       'noLinkUnderline'       : 'reserved',
+       'noMatchingValue_label' : 'reserved',
+       'noMenuMode'    : 'reserved',
+       'nonCachedSubst'        : 'reserved',
+       'nonTypoTagStdWrap'     : 'reserved',
+       'nonTypoTagUserFunc'    : 'reserved',
+       'nonWrappedTag' : 'reserved',
+       'noOrderBy'     : 'reserved',
+       'noPageTitle'   : 'reserved',
+       'noRows'        : 'reserved',
+       'noScaleUp'     : 'reserved',
+       'noStretchAndMarginCells'       : 'reserved',
+       'noThumbsInEB'  : 'reserved',
+       'noThumbsInRTEimageSelect'      : 'reserved',
+       'notification_email_charset'    : 'reserved',
+       'notification_email_encoding'   : 'reserved',
+       'notification_email_urlmode'    : 'reserved',
+       'noTrimWrap'    : 'reserved',
+       'noValueInsert' : 'reserved',
+       'obj'   : 'reserved',
+       'offset'        : 'reserved',
+       'offsetWrap'    : 'reserved',
+       'onlineWorkspaceInfo'   : 'reserved',
+       'onlyCurrentPid'        : 'reserved',
+       'opacity'       : 'reserved',
+       'orderBy'       : 'reserved',
+       'outerWrap'     : 'reserved',
+       'outline'       : 'reserved',
+       'outputLevels'  : 'reserved',
+       'override'      : 'reserved',
+       'overrideAttribs'       : 'reserved',
+       'overrideEdit'  : 'reserved',
+       'overrideId'    : 'reserved',
+       'overridePageModule'    : 'reserved',
+       'overrideWithExtension' : 'reserved',
+       'pageFrameObj'  : 'reserved',
+       'pageGenScript' : 'reserved',
+       'pageTitleFirst'        : 'reserved',
+       'parameter'     : 'reserved',
+       'params'        : 'reserved',
+       'parseFunc'     : 'reserved',
+       'parser'        : 'reserved',
+       'password'      : 'reserved',
+       'path'  : 'reserved',
+       'permissions'   : 'reserved',
+       'pid_list'      : 'reserved',
+       'pidInList'     : 'reserved',
+       'pixelSpaceFontSizeRef' : 'reserved',
+       'plaintextLib'  : 'reserved',
+       'plainTextStdWrap'      : 'reserved',
+       'postCObject'   : 'reserved',
+       'postLineBlanks'        : 'reserved',
+       'postLineChar'  : 'reserved',
+       'postLineLen'   : 'reserved',
+       'postUserFunc'  : 'reserved',
+       'postUserFuncInt'       : 'reserved',
+       'preBlanks'     : 'reserved',
+       'preCObject'    : 'reserved',
+       'prefix'        : 'reserved',
+       'prefixComment' : 'reserved',
+       'prefixLocalAnchors'    : 'reserved',
+       'prefixRelPathWith'     : 'reserved',
+       'preIfEmptyListNum'     : 'reserved',
+       'preLineBlanks' : 'reserved',
+       'preLineChar'   : 'reserved',
+       'preLineLen'    : 'reserved',
+       'prepend'       : 'reserved',
+       'preserveEntities'      : 'reserved',
+       'preUserFunc'   : 'reserved',
+       'prev'  : 'reserved',
+       'previewBorder' : 'reserved',
+       'prevnextToSection'     : 'reserved',
+       'printheader'   : 'reserved',
+       'prioriCalc'    : 'reserved',
+       'proc'  : 'reserved',
+       'processScript' : 'reserved',
+       'properties'    : 'reserved',
+       'protect'       : 'reserved',
+       'protectLvar'   : 'reserved',
+       'publish_levels'        : 'reserved',
+       'QEisDefault'   : 'reserved',
+       'quality'       : 'reserved',
+       'radio' : 'reserved',
+       'radioWrap'     : 'reserved',
+       'range' : 'reserved',
+       'rawUrlEncode'  : 'reserved',
+       'recipient'     : 'reserved',
+       'recursive'     : 'reserved',
+       'recursiveDelete'       : 'reserved',
+       'redirect'      : 'reserved',
+       'redirectToURL' : 'reserved',
+       'reduceColors'  : 'reserved',
+       'register'      : 'reserved',
+       'relativeToParentLayer' : 'reserved',
+       'relativeToTriggerItem' : 'reserved',
+       'relPathPrefix' : 'reserved',
+       'remap' : 'reserved',
+       'remapTag'      : 'reserved',
+       'removeBadHTML' : 'reserved',
+       'removeDefaultJS'       : 'reserved',
+       'removeIfEquals'        : 'reserved',
+       'removeIfFalse' : 'reserved',
+       'removeItems'   : 'reserved',
+       'removeObjectsOfDummy'  : 'reserved',
+       'removePrependedNumbers'        : 'reserved',
+       'removeTags'    : 'reserved',
+       'removeWrapping'        : 'reserved',
+       'renderCharset' : 'reserved',
+       'renderWrap'    : 'reserved',
+       'reset' : 'reserved',
+       'resources'     : 'reserved',
+       'resultObj'     : 'reserved',
+       'returnLast'    : 'reserved',
+       'returnUrl'     : 'reserved',
+       'rightImgACT'   : 'reserved',
+       'rightImgCUR'   : 'reserved',
+       'rightImgNO'    : 'reserved',
+       'rightjoin'     : 'reserved',
+       'rm'    : 'reserved',
+       'rmTagIfNoAttrib'       : 'reserved',
+       'RO_chBgColor'  : 'reserved',
+       'rotate'        : 'reserved',
+       'rows'  : 'reserved',
+       'rowSpace'      : 'reserved',
+       'RTEfullScreenWidth'    : 'reserved',
+       'rules' : 'reserved',
+       'sample'        : 'reserved',
+       'saveClipboard' : 'reserved',
+       'saveDocNew'    : 'reserved',
+       'secondRow'     : 'reserved',
+       'section'       : 'reserved',
+       'sectionIndex'  : 'reserved',
+       'select'        : 'reserved',
+       'select_key'    : 'reserved',
+       'selectFields'  : 'reserved',
+       'separator'     : 'reserved',
+       'set'   : 'reserved',
+       'setContentToCurrent'   : 'reserved',
+       'setCurrent'    : 'reserved',
+       'setfixed'      : 'reserved',
+       'setFixedHeight'        : 'reserved',
+       'setFixedWidth' : 'reserved',
+       'setJS_mouseOver'       : 'reserved',
+       'setJS_openPic' : 'reserved',
+       'setOnly'       : 'reserved',
+       'shadow'        : 'reserved',
+       'sharpen'       : 'reserved',
+       'shear' : 'reserved',
+       'short' : 'reserved',
+       'shortcut'      : 'reserved',
+       'shortcut_onEditId_dontSetPageTree'     : 'reserved',
+       'shortcut_onEditId_keepExistingExpanded'        : 'reserved',
+       'shortcutFrame' : 'reserved',
+       'shortcutGroups'        : 'reserved',
+       'shortcutIcon'  : 'reserved',
+       'show'  : 'reserved',
+       'showAccessRestrictedPages'     : 'reserved',
+       'showActive'    : 'reserved',
+       'showClipControlPanelsDespiteOfCMlayers'        : 'reserved',
+       'showFirst'     : 'reserved',
+       'showHiddenPages'       : 'reserved',
+       'showHiddenRecords'     : 'reserved',
+       'showHistory'   : 'reserved',
+       'showPageIdWithTitle'   : 'reserved',
+       'showTagFreeClasses'    : 'reserved',
+       'simulateDate'  : 'reserved',
+       'simulateStaticDocuments'       : 'reserved',
+       'simulateStaticDocuments_addTitle'      : 'reserved',
+       'simulateStaticDocuments_dontRedirectPathInfoError'     : 'reserved',
+       'simulateStaticDocuments_noTypeIfNoTitle'       : 'reserved',
+       'simulateStaticDocuments_pEnc'  : 'reserved',
+       'simulateStaticDocuments_pEnc_onlyP'    : 'reserved',
+       'simulateUserGroup'     : 'reserved',
+       'singlePid'     : 'reserved',
+       'site_author'   : 'reserved',
+       'site_reserved' : 'reserved',
+       'sitetitle'     : 'reserved',
+       'siteUrl'       : 'reserved',
+       'size'  : 'reserved',
+       'smallFormFields'       : 'reserved',
+       'solarize'      : 'reserved',
+       'sorting'       : 'reserved',
+       'source'        : 'reserved',
+       'space' : 'reserved',
+       'spaceAfter'    : 'reserved',
+       'spaceBefore'   : 'reserved',
+       'spaceBelowAbove'       : 'reserved',
+       'spaceLeft'     : 'reserved',
+       'spaceRight'    : 'reserved',
+       'spacing'       : 'reserved',
+       'spamProtectEmailAddresses'     : 'reserved',
+       'spamProtectEmailAddresses_atSubst'     : 'reserved',
+       'spamProtectEmailAddresses_lastDotSubst'        : 'reserved',
+       'special'       : 'reserved',
+       'splitChar'     : 'reserved',
+       'splitRendering'        : 'reserved',
+       'src'   : 'reserved',
+       'startInTaskCenter'     : 'reserved',
+       'stayFolded'    : 'reserved',
+       'stdheader'     : 'reserved',
+       'stdWrap'       : 'reserved',
+       'stdWrap2'      : 'reserved',
+       'strftime'      : 'reserved',
+       'stripHtml'     : 'reserved',
+       'styles'        : 'reserved',
+       'stylesheet'    : 'reserved',
+       'submenuObjSuffixes'    : 'reserved',
+       'subMenuOffset' : 'reserved',
+       'submit'        : 'reserved',
+       'subst_elementUid'      : 'reserved',
+       'substMarksSeparately'  : 'reserved',
+       'substring'     : 'reserved',
+       'swirl' : 'reserved',
+       'sword' : 'reserved',
+       'sword_noMixedCase'     : 'reserved',
+       'SWORD_PARAMS'  : 'reserved',
+       'sword_standAlone'      : 'reserved',
+       'sys_language_mode'     : 'reserved',
+       'sys_language_overlay'  : 'reserved',
+       'sys_language_softMergeIfNotBlank'      : 'reserved',
+       'sys_language_uid'      : 'reserved',
+       'table' : 'reserved',
+       'tableCellColor'        : 'reserved',
+       'tableParams'   : 'reserved',
+       'tables'        : 'reserved',
+       'tableStdWrap'  : 'reserved',
+       'tableStyle'    : 'reserved',
+       'tableWidth'    : 'reserved',
+       'tags'  : 'reserved',
+       'target'        : 'reserved',
+       'TDparams'      : 'reserved',
+       'templateContent'       : 'reserved',
+       'templateFile'  : 'reserved',
+       'text'  : 'reserved',
+       'textarea'      : 'reserved',
+       'textMargin'    : 'reserved',
+       'textMargin_outOfText'  : 'reserved',
+       'textMaxLength' : 'reserved',
+       'textObjNum'    : 'reserved',
+       'textPos'       : 'reserved',
+       'textStyle'     : 'reserved',
+       'thickness'     : 'reserved',
+       'thumbnailsByDefault'   : 'reserved',
+       'tile'  : 'reserved',
+       'time_stdWrap'  : 'reserved',
+       'tipafriendLib' : 'reserved',
+       'title' : 'reserved',
+       'titleLen'      : 'reserved',
+       'titleTagFunction'      : 'reserved',
+       'titleText'     : 'reserved',
+       'tm'    : 'reserved',
+       'token' : 'reserved',
+       'topOffset'     : 'reserved',
+       'totalWidth'    : 'reserved',
+       'transparentBackground' : 'reserved',
+       'transparentColor'      : 'reserved',
+       'trim'  : 'reserved',
+       'tsdebug_tree'  : 'reserved',
+       'type'  : 'reserved',
+       'typeNum'       : 'reserved',
+       'types' : 'reserved',
+       'typolinkCheckRootline' : 'reserved',
+       'uidInList'     : 'reserved',
+       'unset' : 'reserved',
+       'uploadFieldsInTopOfEB' : 'reserved',
+       'uploads'       : 'reserved',
+       'upper' : 'reserved',
+       'useCacheHash'  : 'reserved',
+       'useLargestItemX'       : 'reserved',
+       'useLargestItemY'       : 'reserved',
+       'user'  : 'reserved',
+       'userdefined'   : 'reserved',
+       'userfunction'  : 'reserved',
+       'userid'        : 'reserved',
+       'userIdColumn'  : 'reserved',
+       'USERNAME_substToken'   : 'reserved',
+       'userProc'      : 'reserved',
+       'value' : 'reserved',
+       'valueArray'    : 'reserved',
+       'wave'  : 'reserved',
+       'where' : 'reserved',
+       'width' : 'reserved',
+       'wiz'   : 'reserved',
+       'wordSpacing'   : 'reserved',
+       'workArea'      : 'reserved',
+       'wrap'  : 'reserved',
+       'wrap1' : 'reserved',
+       'wrap2' : 'reserved',
+       'wrap3' : 'reserved',
+       'wrapAfterTags' : 'reserved',
+       'wrapAlign'     : 'reserved',
+       'wrapFieldName' : 'reserved',
+       'wrapItemAndSub'        : 'reserved',
+       'wrapNonWrappedLines'   : 'reserved',
+       'wraps' : 'reserved',
+       'xhtml_cleaning'        : 'reserved',
+       'xmlprologue'   : 'reserved',
+       'xPosOffset'    : 'reserved',
+       'yPosOffset'    : 'reserved',
+       
+       'admPanel'      : 'keyword2',
+       'alt_print'     : 'keyword2',
+       'auth'  : 'keyword2',
+       'browser'       : 'keyword2',
+       'cache' : 'keyword2',
+       'CHECK' : 'keyword2',
+       'cObj'  : 'keyword2',
+       'cObject'       : 'keyword2',
+       'COMMENT'       : 'keyword2',
+       'config'        : 'keyword2',
+       'content'       : 'keyword2',
+       'copy'  : 'keyword2',
+       'CSS_inlineStyle'       : 'keyword2',
+       'cut'   : 'keyword2',
+       'dataArray'     : 'keyword2',
+       'dayofmonth'    : 'keyword2',
+       'dayofweek'     : 'keyword2',
+       'db_list'       : 'keyword2',
+       'device'        : 'keyword2',
+       'dynCSS'        : 'keyword2',
+       'edit'  : 'keyword2',
+       'edit_access'   : 'keyword2',
+       'edit_pageheader'       : 'keyword2',
+       'folder'        : 'keyword2',
+       'folderTree'    : 'keyword2',
+       'foldoutMenu'   : 'keyword2',
+       'Functions'     : 'keyword2',
+       'gmenu_foldout' : 'keyword2',
+       'gmenu_layers'  : 'keyword2',
+       'hostname'      : 'keyword2',
+       'hour'  : 'keyword2',
+       'imgList'       : 'keyword2',
+       'imgResource'   : 'keyword2',
+       'imgText'       : 'keyword2',
+       'info'  : 'keyword2',
+       'IP'    : 'keyword2',
+       'jsmenu'        : 'keyword2',
+       'JSwindow'      : 'keyword2',
+       'LABEL' : 'keyword2',
+       'layout'        : 'keyword2',
+       'lib'   : 'keyword2',
+       'loginUser'     : 'keyword2',
+       'marks' : 'keyword2',
+       'minute'        : 'keyword2',
+       'mod'   : 'keyword2',
+       'module'        : 'keyword2',
+       'month' : 'keyword2',
+       'move_wizard'   : 'keyword2',
+       'new'   : 'keyword2',
+       'new_wizard'    : 'keyword2',
+       'noResultObj'   : 'keyword2',
+       'numRows'       : 'keyword2',
+       'options'       : 'keyword2',
+       'page'  : 'keyword2',
+       'pageTree'      : 'keyword2',
+       'paste' : 'keyword2',
+       'perms' : 'keyword2',
+       'PIDinRootline' : 'keyword2',
+       'PIDupinRootline'       : 'keyword2',
+       'plugin'        : 'keyword2',
+       'postform'      : 'keyword2',
+       'postform_newThread'    : 'keyword2',
+       'preview'       : 'keyword2',
+       'publish'       : 'keyword2',
+       'RADIO' : 'keyword2',
+       'renderObj'     : 'keyword2',
+       'REQ'   : 'keyword2',
+       'RTE'   : 'keyword2',
+       'RTE_compliant' : 'keyword2',
+       'select'        : 'keyword2',
+       'setup' : 'keyword2',
+       'split' : 'keyword2',
+       'stat'  : 'keyword2',
+       'stat_apache'   : 'keyword2',
+       'stat_apache_logfile'   : 'keyword2',
+       'stat_apache_noHost'    : 'keyword2',
+       'stat_apache_notExtended'       : 'keyword2',
+       'stat_apache_pagenames' : 'keyword2',
+       'stat_excludeBEuserHits'        : 'keyword2',
+       'stat_excludeIPList'    : 'keyword2',
+       'stat_mysql'    : 'keyword2',
+       'stat_titleLen' : 'keyword2',
+       'stat_typeNumList'      : 'keyword2',
+       'stdWrap'       : 'keyword2',
+       'subparts'      : 'keyword2',
+       'system'        : 'keyword2',
+       'temp'  : 'keyword2',
+       'template'      : 'keyword2',
+       'treeLevel'     : 'keyword2',
+       'tsdebug'       : 'keyword2',
+       'typolink'      : 'keyword2',
+       'url'   : 'keyword2',
+       'useragent'     : 'keyword2',
+       'userFunc'      : 'keyword2',
+       'version'       : 'keyword2',
+       'view'  : 'keyword2',
+       'workOnSubpart' : 'keyword2',
+       
+       'ACT'   : 'keyword3',
+       'ACTIFSUB'      : 'keyword3',
+       'ACTIFSUBRO'    : 'keyword',
+       'ACTRO' : 'keyword3',
+       'all'   : 'keyword3',
+       'arrowACT'      : 'keyword3',
+       'arrowNO'       : 'keyword3',
+       'ascii' : 'keyword3',
+       'atLeast'       : 'keyword3',
+       'atMost'        : 'keyword3',
+       'BE'    : 'keyword3',
+       'be_groups'     : 'keyword3',
+       'be_users'      : 'keyword3',
+       'BOX'   : 'keyword3',
+       'browse'        : 'keyword3',
+       'bullets'       : 'keyword3',
+       'CUR'   : 'keyword3',
+       'CURIFSUB'      : 'keyword3',
+       'CURIFSUBRO'    : 'keyword3',
+       'CURRO' : 'keyword3',
+       'default'       : 'keyword3',
+       'description'   : 'keyword3',
+       'directory'     : 'keyword3',
+       'directReturn'  : 'keyword3',
+       'div'   : 'keyword3',
+       'else'  : 'keyword3',
+       'email' : 'keyword3',
+       'end'   : 'keyword3',
+       'equals'        : 'keyword3',
+       'external'      : 'keyword3',
+       'false' : 'keyword3',
+       'FE'    : 'keyword3',
+       'fe_groups'     : 'keyword3',
+       'fe_users'      : 'keyword3',
+       'feadmin'       : 'keyword3',
+       'header'        : 'keyword3',
+       'html'  : 'keyword3',
+       'id'    : 'keyword3',
+       'if'    : 'keyword3',
+       'ifEmpty'       : 'keyword3',
+       'IFSUB' : 'keyword3',
+       'IFSUBRO'       : 'keyword3',
+       'image' : 'keyword3',
+       'inBranch'      : 'keyword3',
+       'isFalse'       : 'keyword3',
+       'isGreaterThan' : 'keyword3',
+       'isInList'      : 'keyword3',
+       'isLessThan'    : 'keyword3',
+       'isPositive'    : 'keyword3',
+       'isTrue'        : 'keyword3',
+       'keyword3'      : 'keyword3',
+       'language'      : 'keyword3',
+       'leveltitle'    : 'keyword3',
+       'list'  : 'keyword3',
+       'login' : 'keyword3',
+       'mailform'      : 'keyword3',
+       'media' : 'keyword3',
+       'menu'  : 'keyword3',
+       'mod'   : 'keyword3',
+       'multimedia'    : 'keyword3',
+       'negate'        : 'keyword3',
+       'NEW'   : 'keyword3',
+       'NO'    : 'keyword3',
+       'none'  : 'keyword3',
+       'pages' : 'keyword3',
+       'pages_language_overlay'        : 'keyword3',
+       'parseFunc_RTE' : 'keyword3',
+       'pid'   : 'keyword3',
+       'required'      : 'keyword3',
+       'RO'    : 'keyword3',
+       'rootline'      : 'keyword3',
+       'script'        : 'keyword3',
+       'search'        : 'keyword3',
+       'shortcut'      : 'keyword3',
+       'sitemap'       : 'keyword3',
+       'SPC'   : 'keyword3',
+       'splash'        : 'keyword3',
+       'sys_dmail'     : 'keyword3',
+       'sys_domain'    : 'keyword3',
+       'sys_filemounts'        : 'keyword3',
+       'sys_note'      : 'keyword3',
+       'sys_template'  : 'keyword3',
+       'tabel' : 'keyword3',
+       'text'  : 'keyword3',
+       'textpic'       : 'keyword3',
+       'this'  : 'keyword3',
+       'top'   : 'keyword3',
+       'true'  : 'keyword3',
+       'tt_address'    : 'keyword3',
+       'tt_board'      : 'keyword3',
+       'tt_board_list' : 'keyword3',
+       'tt_board_tree' : 'keyword3',
+       'tt_calender'   : 'keyword3',
+       'tt_content'    : 'keyword3',
+       'tt_guest'      : 'keyword3',
+       'tt_news'       : 'keyword3',
+       'tt_poll'       : 'keyword3',
+       'tt_products'   : 'keyword3',
+       'tt_rating'     : 'keyword3',
+       'twice' : 'keyword3',
+       'tx_automaketemplate_pi1'       : 'keyword3',
+       'tx_belog_webinfo'      : 'keyword3',
+       'tx_browserpagetitle'   : 'keyword3',
+       'tx_browserpagetitle_browser_title'     : 'keyword3',
+       'tx_chcforum_pi1'       : 'keyword3',
+       'tx_cms_layout' : 'keyword3',
+       'tx_cms_webinfo_hits'   : 'keyword3',
+       'tx_cms_webinfo_lang'   : 'keyword3',
+       'tx_cms_webinfo_page'   : 'keyword3',
+       'tx_cssstyledcontent_pi1'       : 'keyword3',
+       'tx_dephpot_pi1'        : 'keyword3',
+       'tx_extkey'     : 'keyword3',
+       'tx_extkey_controllers' : 'keyword3',
+       'tx_extkey_login'       : 'keyword3',
+       'tx_extrapagecmoptions' : 'keyword3',
+       'tx_funcwizards_webfunc'        : 'keyword3',
+       'tx_gooffotoboek_pi1'   : 'keyword3',
+       'tx_impexp'     : 'keyword3',
+       'tx_impexp_clickmenu'   : 'keyword3',
+       'tx_impexp_modfunc1'    : 'keyword3',
+       'tx_indexed_search_extparse'    : 'keyword3',
+       'tx_indexedsearch'      : 'keyword3',
+       'tx_indexedsearch_indexer'      : 'keyword3',
+       'tx_indexedsearch_lexer'        : 'keyword3',
+       'tx_indexedsearch_modfunc1'     : 'keyword3',
+       'tx_indexedsearch_modfunc2'     : 'keyword3',
+       'tx_indexedsearch_pihook'       : 'keyword3',
+       'tx_infopagetsconfig_webinfo'   : 'keyword3',
+       'tx_install'    : 'keyword3',
+       'tx_lzgallery_pi1'      : 'keyword3',
+       'tx_mhajaxsearch_pi1'   : 'keyword3',
+       'tx_mhajaxsearch_q'     : 'keyword3',
+       'tx_mhajaxsearch_result'        : 'keyword3',
+       'tx_mhajaxsearch_search'        : 'keyword3',
+       'tx_newloginbox_pi1'    : 'keyword3',
+       'tx_newloginbox_pi3'    : 'keyword3',
+       'tx_open_printlink'     : 'keyword3',
+       'tx_pdfgenerator'       : 'keyword3',
+       'tx_realurl_advanced'   : 'keyword3',
+       'tx_realurl_enable'     : 'keyword3',
+       'tx_realurl_pathsegment'        : 'keyword3',
+       'tx_realurl_pi1'        : 'keyword3',
+       'tx_rlmptmplselector'   : 'keyword3',
+       'tx_rlmptmplselector_pi1'       : 'keyword3',
+       'tx_sochat_pi1' : 'keyword3',
+       'tx_srfeuserregister_pi1'       : 'keyword3',
+       'tx_sv_auth'    : 'keyword3',
+       'tx_sv_authbase'        : 'keyword3',
+       'tx_sysaction'  : 'keyword3',
+       'tx_templavoila_pi1'    : 'keyword3',
+       'tx_terdoc_pi1' : 'keyword3',
+       'tx_ttnews'     : 'keyword3',
+       'tx_ttnews_catmenu'     : 'keyword3',
+       'tx_ttnews_itemsProcFunc'       : 'keyword3',
+       'tx_ttnews_tcemain'     : 'keyword3',
+       'tx_ttnews_treeview='   : 'keyword3',
+       'tx_ttproducts_pi1'     : 'keyword3',
+       'tx_veguestbook_pi1'    : 'keyword3',
+       'tx_version_cm1'        : 'keyword3',
+       'tx_vjchat_chat'        : 'keyword3',
+       'tx_vjchat_pi1' : 'keyword3',
+       'tx_wizardcrpages_webfunc_2'    : 'keyword3',
+       'tx_wizardsortpages_webfunc_2'  : 'keyword3',
+       'tx_wwwebstats4u_pi1'   : 'keyword3',
+       'uid'   : 'keyword3',
+       'uniqueGlobal'  : 'keyword3',
+       'uniqueLocal'   : 'keyword3',
+       'unsetEmpty'    : 'keyword3',
+       'updated'       : 'keyword3',
+       'uploads'       : 'keyword3',
+       'us'    : 'keyword3',
+       'user_task'     : 'keyword3',
+       'USERDEF1'      : 'keyword3',
+       'USERDEF1RO'    : 'keyword3',
+       'USERDEF2'      : 'keyword3',
+       'USERDEF2RO'    : 'keyword3',
+       'usergroup'     : 'keyword3',
+       'USR'   : 'keyword3',
+       'USRRO' : 'keyword3',
+       'web_func'      : 'keyword3',
+       'web_info'      : 'keyword3',
+       'web_layout'    : 'keyword3',
+       'web_list'      : 'keyword3',
+       'web_ts'        : 'keyword',
+       'xhtml_strict'  : 'keyword3',
+       'xhtml_trans'   : 'keyword3',
+       'XY'    : 'keyword3',
+       'ypMenu'        : 'keyword3'
+}
+
+var tokenizeTypoScript = function(){
+
+  // Some helper regexp matchers.
+  var isOperatorChar = matcher(/[\+\-\*\&\%\/=<>!\?]/);
+  var isDigit = matcher(/[0-9]/);
+  var isHexDigit = matcher(/[0-9A-Fa-f]/);
+  var isWordChar = matcher(/[\w\$_]/);
+  function isWhiteSpace(ch){
+    // Unfortunately, IE's regexp matcher thinks non-breaking spaces
+    // aren't whitespace. Also, in our scheme newlines are no
+    // whitespace (they are another special case).
+    return ch != "\n" && (ch == nbsp || /\s/.test(ch));
+  }
+
+  // This function produces a MochiKit-style iterator that tokenizes
+  // the output of the given stringstream (see stringstream.js).
+  // Tokens are objects with a type, style, and value property. The
+  // value contains the textual content of the token. Because this may
+  // include trailing whitespace (for efficiency reasons), some
+  // tokens, such a variable names, also have a name property
+  // containing their actual textual value.
+  return function(source){
+    // Produce a value to return. Automatically skips and includes any
+    // whitespace. The base argument is prepended to the value
+    // property and assigned to the name property -- this is used when
+    // the caller has already extracted the text from the stream
+    // himself.
+    function result(type, style, base){
+      // nextWhile(isWhiteSpace); - comment thats line because needed for autocomplete
+      var value = {type: type, style: style, value: (base ? base + source.get() : source.get())};
+      if (base) value.name = base;
+      return value;
+    }
+
+    // Advance the text stream over characters for which test returns
+    // true. (The characters that are 'consumed' like this can later
+    // be retrieved by calling source.get()).
+    function nextWhile(test){
+      var next;
+      while((next = source.peek()) && test(next))
+        source.next();
+    }
+    // Advance the stream until the given character (not preceded by a
+    // backslash) is encountered (or a newline is found).
+    function nextUntilUnescaped(end){
+      var escaped = false;
+      var next;
+      while((next = source.peek()) && next != "\n"){
+        source.next();
+        if (next == end && !escaped)
+          break;
+        escaped = next == "\\";
+      }
+    }
+  
+    function readHexNumber(){
+      source.next(); // skip the 'x'
+      nextWhile(isHexDigit);
+      return result("number", "atom");
+    }
+    function readNumber(){
+      nextWhile(isDigit);
+      if (source.peek() == "."){
+        source.next();
+        nextWhile(isDigit);
+      }
+      if (source.peek() == "e" || source.peek() == "E"){
+        source.next();
+        if (source.peek() == "-")
+          source.next();
+        nextWhile(isDigit);
+      }
+      return result("number", "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(){
+      nextWhile(isWordChar);
+      var word = source.get();
+      var known = typoscriptWords.hasOwnProperty(word) && {type: 'keyword', style: typoscriptWords[word]};
+      return known ? result(known.type, known.style, word) : result("variable", "other", word);
+    }
+    function readRegexp(){
+      nextUntilUnescaped("/");
+      nextWhile(matcher(/[gi]/));
+      return result("regexp", "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 (inComment) to indicate whether we
+    // are inside a /* */ sequence.
+    function readMultilineComment(start){
+      this.inComment = true;
+      var maybeEnd = (start == "*");
+      while(true){
+        var next = source.peek();
+        if (next == "\n")
+          break;
+        source.next();
+        if (next == "/" && maybeEnd){
+          this.inComment = false;
+          break;
+        }
+        maybeEnd = (next == "*");
+      }
+      return result("comment", "comment");
+    }
+
+    // Fetch the next token. Dispatches on first character in the
+    // stream, or first two characters when the first is a slash. The
+    // || things are a silly trick to keep simple cases on a single
+    // line.
+    function next(){
+      var token = null;
+      var ch = source.next();
+      if (ch == "\n")
+        token = {type: "newline", style: "whitespace", value: source.get()};
+      else if (this.inComment)
+        token = readMultilineComment.call(this, ch);
+      else if (isWhiteSpace(ch))
+        token = nextWhile(isWhiteSpace) || result("whitespace", "whitespace");
+      else if (ch == "\"" || ch == "'")
+        token = nextUntilUnescaped(ch) || result("string", "string");
+      // with punctuation, the type of the token is the symbol itself
+      else if (/[\[\]{}\(\),;\:\.]/.test(ch))
+        token = result(ch, "punctuation");
+      else if (ch == "0" && (source.peek() == "x" || source.peek() == "X"))
+        token = readHexNumber();
+      else if (isDigit(ch))
+        token = readNumber();
+      else if (ch == "/"){
+        next = source.peek();
+        if (next == "*")
+          token = readMultilineComment.call(this, ch);
+        else if (next == "/")
+          token = nextUntilUnescaped(null) || result("comment", "comment");
+        else if (this.regexp)
+          token = readRegexp();
+        else
+          token = nextWhile(isOperatorChar) || result("operator", "operator");
+      } else if (ch == "#")
+        token = nextUntilUnescaped(null) || result("comment", "comment");
+      else if (isOperatorChar(ch))
+        token = nextWhile(isOperatorChar) || result("operator", "operator");
+      else
+        token = readWord();
+
+      // JavaScript's syntax rules for when a slash might be the start
+      // of a regexp and when it is just a division operator are kind
+      // of non-obvious. This decides, based on the current token,
+      // whether the next token could be a regular expression.
+      if (token.style != "whitespace" && token != "comment")
+        this.regexp = token.type == "operator" || token.type == "keyword c" || token.type.match(/[\[{}\(,;:]/);
+      return token;
+    }
+
+    // Wrap it in an iterator. The state (regexp and inComment) is
+    // exposed because a parser will need to save it when making a
+    // copy of its state.
+    return {next: next, regexp: true, inComment: false};
+  }
+}();
diff --git a/typo3/sysext/t3editor/jslib/util.js b/typo3/sysext/t3editor/jslib/util.js
new file mode 100644 (file)
index 0000000..53c6960
--- /dev/null
@@ -0,0 +1,76 @@
+/* A few useful utility functions. */
+
+// Retrieve the next value from an iterator, or return an alternative
+// value if the iterator is at its end.
+function nextOr(iter, alternative){
+  try {
+    return iter.next();
+  }
+  catch (e) {
+    if (e != StopIteration)
+      throw e;
+    else return alternative;
+  }
+}
+
+// Create an ojbect to represent a set. Takes any number of strings as
+// arguments, and returns an object in which the properties named by
+// these strings are set to true.
+function setObject(){
+  var obj = {};
+  forEach(arguments, function(value){
+    obj[value] = true;
+  });
+  return obj;
+}
+
+// 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);
+}
+
+function repeatString(str, times) {
+  var result = [];
+  while(times--) result.push(str);
+  return result.join("");
+}
+
+// Insert a DOM node after another node.
+function insertAfter(newNode, oldNode) {
+  var parent = oldNode.parentNode;
+  var next = oldNode.nextSibling;
+  if (next)
+    parent.insertBefore(newNode, next);
+  else
+    parent.appendChild(newNode);
+  return newNode;
+}
+
+// Insert a dom node at the start of a container.
+function insertAtStart(node, container) {
+  if (container.firstChild)
+    container.insertBefore(node, container.firstChild);
+  else
+    container.appendChild(node);
+  return node;
+}
+
+// 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 = String.fromCharCode(160);