* t3editor: Fix a little typo in tsref.xml and convert DOS to Unix linebreaks in...
authorMichael Stucki <michael.stucki@typo3.org>
Mon, 22 Jun 2009 16:32:23 +0000 (16:32 +0000)
committerMichael Stucki <michael.stucki@typo3.org>
Mon, 22 Jun 2009 16:32:23 +0000 (16:32 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@5607 709f56b5-9817-0410-a4d7-c38de5d9e867

typo3/sysext/t3editor/jslib/ts_codecompletion/completionresult.js
typo3/sysext/t3editor/jslib/ts_codecompletion/descriptionPlugin.js
typo3/sysext/t3editor/jslib/ts_codecompletion/tscodecompletion.js
typo3/sysext/t3editor/jslib/ts_codecompletion/tsparser.js
typo3/sysext/t3editor/jslib/ts_codecompletion/tsref.js
typo3/sysext/t3editor/tsref/tsref.xml

index 9e29413..8aafefb 100644 (file)
-/***************************************************************\r
-* Copyright notice\r
-*\r
-* (c) 2008-2009 Stephan Petzl <spetzl@gmx.at> and Christian Kartnig <office@hahnepeter.de> \r
-* All rights reserved\r
-*\r
-* This script is part of the TYPO3 project. The TYPO3 project is\r
-* free software; you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation; either version 2 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* The GNU General Public License can be found at\r
-* http://www.gnu.org/copyleft/gpl.html.\r
-* A copy is found in the textfile GPL.txt and important notices to the license\r
-* from the author is found in LICENSE.txt distributed with these scripts.\r
-*\r
-*\r
-* This script is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* This copyright notice MUST APPEAR in all copies of the script!\r
-***************************************************************/\r
-/**\r
- * @fileoverview contains the CompletionResult class \r
- */ \r
-\r
-/** \r
- * @class this class post-processes the result from the codecompletion, so that it can be\r
- * displayed in the next step.\r
- * @constructor\r
- * @param tsRef the TsRef Tree\r
- * @param tsTreeNode the current Node in the codetree built by the parser\r
- * @return a new CompletionResult instance\r
- */\r
-var CompletionResult = function(tsRef,tsTreeNode) {\r
-       var currentTsTreeNode = tsTreeNode;\r
-       var tsRef = tsRef;\r
-\r
-       /**\r
-        * returns the type of the currentTsTreeNode\r
-        */\r
-       this.getType = function() {\r
-               var val = currentTsTreeNode.getValue();\r
-               if (tsRef.isType(val)) {\r
-                       return tsRef.getType(val);\r
-               } else {\r
-                       return null;\r
-               }\r
-       }\r
-\r
-       /**\r
-        * returns a list of possible path completions (proposals), which is:\r
-        * a list of the children of the current TsTreeNode (= userdefined properties)\r
-        * and a list of properties allowed for the current object in the TsRef\r
-        * remove all words from list that don't start with the string in filter\r
-        * @param {String} filter beginning of the words contained in the proposal list\r
-        * @returns an Array of Proposals\r
-        */\r
-       this.getFilteredProposals = function(filter) {\r
-\r
-               var defined = new Array();\r
-               var propArr = new Array();\r
-               var childNodes = currentTsTreeNode.getChildNodes();\r
-               var value = currentTsTreeNode.getValue();\r
-               // first get the childNodes of the Node (=properties defined by the user)\r
-               for (key in childNodes) {\r
-                       if (typeof(childNodes[key].value) != "undefined") {\r
-                               propObj = new Object();\r
-                               propObj.word = key;\r
-                               if(tsRef.typeHasProperty(value,childNodes[key].name)){\r
-                                       propObj.cssClass = 'definedTSREFProperty';\r
-                                       propObj.type = childNodes[key].value;\r
-                               } else {\r
-                                       propObj.cssClass = 'userProperty';\r
-                                       if (tsRef.isType(childNodes[key].value)) {\r
-                                               propObj.type = childNodes[key].value;\r
-                                       } else {\r
-                                               propObj.type = '';\r
-                                       }\r
-                               }\r
-                               propArr.push(propObj);\r
-                               defined[key] = true;\r
-                       }\r
-               }\r
-\r
-               // then get the tsref properties\r
-               var props = tsRef.getPropertiesFromTypeId(currentTsTreeNode.getValue());\r
-               for (key in props) {\r
-                       // show just the TSREF properties - no properties of the array-prototype and no properties which have been defined by the user\r
-                       if (props[key].value != null && !defined[key]) {\r
-                               propObj = new Object();\r
-                               propObj.word = key;\r
-                               propObj.cssClass = 'undefinedTSREFProperty';\r
-                               propObj.type = props[key].value;\r
-                               propArr.push(propObj);\r
-                       }\r
-               }\r
-\r
-               var result = [];\r
-               var wordBeginning = "";\r
-               for (var i=0; i < propArr.length;i++) {\r
-                       wordBeginning = propArr[i].word.substring(0, filter.length);\r
-                       if (filter == "" || filter == null || wordBeginning.toLowerCase() == filter.toLowerCase()) {\r
-                               result.push(propArr[i]);\r
-                       }\r
-               }\r
-               return result;\r
-       }\r
-}\r
+/***************************************************************
+* Copyright notice
+*
+* (c) 2008-2009 Stephan Petzl <spetzl@gmx.at> and Christian Kartnig <office@hahnepeter.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!
+***************************************************************/
+/**
+ * @fileoverview contains the CompletionResult class 
+ */ 
+
+/** 
+ * @class this class post-processes the result from the codecompletion, so that it can be
+ * displayed in the next step.
+ * @constructor
+ * @param tsRef the TsRef Tree
+ * @param tsTreeNode the current Node in the codetree built by the parser
+ * @return a new CompletionResult instance
+ */
+var CompletionResult = function(tsRef,tsTreeNode) {
+       var currentTsTreeNode = tsTreeNode;
+       var tsRef = tsRef;
+
+       /**
+        * returns the type of the currentTsTreeNode
+        */
+       this.getType = function() {
+               var val = currentTsTreeNode.getValue();
+               if (tsRef.isType(val)) {
+                       return tsRef.getType(val);
+               } else {
+                       return null;
+               }
+       }
+
+       /**
+        * returns a list of possible path completions (proposals), which is:
+        * a list of the children of the current TsTreeNode (= userdefined properties)
+        * and a list of properties allowed for the current object in the TsRef
+        * remove all words from list that don't start with the string in filter
+        * @param {String} filter beginning of the words contained in the proposal list
+        * @returns an Array of Proposals
+        */
+       this.getFilteredProposals = function(filter) {
+
+               var defined = new Array();
+               var propArr = new Array();
+               var childNodes = currentTsTreeNode.getChildNodes();
+               var value = currentTsTreeNode.getValue();
+               // first get the childNodes of the Node (=properties defined by the user)
+               for (key in childNodes) {
+                       if (typeof(childNodes[key].value) != "undefined") {
+                               propObj = new Object();
+                               propObj.word = key;
+                               if(tsRef.typeHasProperty(value,childNodes[key].name)){
+                                       propObj.cssClass = 'definedTSREFProperty';
+                                       propObj.type = childNodes[key].value;
+                               } else {
+                                       propObj.cssClass = 'userProperty';
+                                       if (tsRef.isType(childNodes[key].value)) {
+                                               propObj.type = childNodes[key].value;
+                                       } else {
+                                               propObj.type = '';
+                                       }
+                               }
+                               propArr.push(propObj);
+                               defined[key] = true;
+                       }
+               }
+
+               // then get the tsref properties
+               var props = tsRef.getPropertiesFromTypeId(currentTsTreeNode.getValue());
+               for (key in props) {
+                       // show just the TSREF properties - no properties of the array-prototype and no properties which have been defined by the user
+                       if (props[key].value != null && !defined[key]) {
+                               propObj = new Object();
+                               propObj.word = key;
+                               propObj.cssClass = 'undefinedTSREFProperty';
+                               propObj.type = props[key].value;
+                               propArr.push(propObj);
+                       }
+               }
+
+               var result = [];
+               var wordBeginning = "";
+               for (var i=0; i < propArr.length;i++) {
+                       wordBeginning = propArr[i].word.substring(0, filter.length);
+                       if (filter == "" || filter == null || wordBeginning.toLowerCase() == filter.toLowerCase()) {
+                               result.push(propArr[i]);
+                       }
+               }
+               return result;
+       }
+}
index a96b282..5d1f22f 100644 (file)
-/***************************************************************\r
-* Copyright notice\r
-*\r
-* (c) 2008-2009 Stephan Petzl <spetzl@gmx.at> and Christian Kartnig <office@hahnepeter.de> \r
-* All rights reserved\r
-*\r
-* This script is part of the TYPO3 project. The TYPO3 project is\r
-* free software; you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation; either version 2 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* The GNU General Public License can be found at\r
-* http://www.gnu.org/copyleft/gpl.html.\r
-* A copy is found in the textfile GPL.txt and important notices to the license\r
-* from the author is found in LICENSE.txt distributed with these scripts.\r
-*\r
-*\r
-* This script is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* This copyright notice MUST APPEAR in all copies of the script!\r
-***************************************************************/\r
-\r
-/**\r
- * @class Descriptionbox plugin for the t3editor-codecompletion which displays the datatype \r
- * and the desciption for each property displayed in the completionbox\r
- * @constructor\r
- * @return A new DescriptionPlugin instance    \r
- **/\r
-\r
-var DescriptionPlugin = function() {\r
-       var outerdiv;\r
-       var descriptionBox;\r
-       var completionBox;\r
-       var tsRef;\r
-       var pluginMeta;\r
-\r
-       this.init = function(pluginContext,plugin) {\r
-               pluginMeta = plugin;\r
-               outerdiv = pluginContext.outerdiv;\r
-               completionBox = pluginContext.codeCompleteBox;\r
-               tsRef = pluginContext.tsRef;\r
-               descriptionBox = new Element("DIV", {"class": "t3e_descriptionBox"});\r
-               descriptionBox.hide();\r
-               outerdiv.appendChild(descriptionBox);\r
-       }\r
-       this.afterMouseOver = function(currWordObj,compResult) {\r
-               refreshBox(currWordObj,compResult);\r
-       }\r
-       this.afterKeyDown = function(currWordObj,compResult) {\r
-               refreshBox(currWordObj,compResult);\r
-       }\r
-       this.afterKeyUp = function(currWordObj,compResult) {\r
-               refreshBox(currWordObj,compResult);\r
-       }\r
-       this.afterCCRefresh = function(currWordObj,compResult) {\r
-               refreshBox(currWordObj,compResult);\r
-       }\r
-       function descriptionLoaded(desc) {\r
-               $('TSREF_description').innerHTML = desc;\r
-       }\r
-\r
-       function refreshBox(proposalObj,compResult) {\r
-               var type = compResult.getType();\r
-\r
-               if (type && type.properties[proposalObj.word]) {\r
-                       // first a container has to be built\r
-                       descriptionBox.innerHTML  = '<div class="TSREF_type_label">Object-type: </div><div class="TSREF_type">'+type.typeId+'</div>';\r
-                       descriptionBox.innerHTML += '<div class="TSREF_type_label">Property-type: </div><div class="TSREF_type">'+type.properties[proposalObj.word].value+'</div><br/>';\r
-                       descriptionBox.innerHTML += '<div class="TSREF_description_label">TSREF-description:</div><div id="TSREF_description"><img src="../../../gfx/spinner.gif" border="0" alt="one moment please..."/></div>';\r
-                       var prop = type.properties[proposalObj.word];\r
-                       // if there is another request for a description in the queue -> cancel it\r
-\r
-                       window.clearTimeout(this.lastTimeoutId);\r
-                       // add a request for a description onto the queue, but wait for 0.5 seconds\r
-                       // (look if user really wants to see the description of this property, if not -> don't load it)\r
-                       this.lastTimeoutId = prop.getDescription.bind(prop).delay(0.5,descriptionLoaded);\r
-                       descriptionBox.show();\r
-               } else if (proposalObj.type) {\r
-                       descriptionBox.innerHTML = '<div class="TSREF_type_label">TSREF-type: </div><div class="TSREF_type">'+proposalObj.type+'</div><br/>';\r
-                       descriptionBox.show();\r
-               } else {\r
-                       descriptionBox.innerHTML = '';\r
-                       descriptionBox.hide();\r
-               }\r
-\r
-\r
-               descriptionBox.scrollTop = 0;\r
-               descriptionBox.style.overflowY = 'scroll';\r
-               descriptionBox.style.class = 'descriptionBox';\r
-               var leftOffset = parseInt(completionBox.getStyle('left').gsub('px','')) + parseInt(completionBox.getStyle('width').gsub('px','')) + 5;\r
-               leftOffset += 'px';\r
-               descriptionBox.setStyle({\r
-                       top: completionBox.getStyle('top'),\r
-                       left: leftOffset\r
-               });\r
-       }\r
-\r
-       this.endCodeCompletion = function(){\r
-               descriptionBox.hide();  \r
-       }\r
-}\r
+/***************************************************************
+* Copyright notice
+*
+* (c) 2008-2009 Stephan Petzl <spetzl@gmx.at> and Christian Kartnig <office@hahnepeter.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!
+***************************************************************/
+
+/**
+ * @class Descriptionbox plugin for the t3editor-codecompletion which displays the datatype 
+ * and the desciption for each property displayed in the completionbox
+ * @constructor
+ * @return A new DescriptionPlugin instance    
+ **/
+
+var DescriptionPlugin = function() {
+       var outerdiv;
+       var descriptionBox;
+       var completionBox;
+       var tsRef;
+       var pluginMeta;
+
+       this.init = function(pluginContext,plugin) {
+               pluginMeta = plugin;
+               outerdiv = pluginContext.outerdiv;
+               completionBox = pluginContext.codeCompleteBox;
+               tsRef = pluginContext.tsRef;
+               descriptionBox = new Element("DIV", {"class": "t3e_descriptionBox"});
+               descriptionBox.hide();
+               outerdiv.appendChild(descriptionBox);
+       }
+       this.afterMouseOver = function(currWordObj,compResult) {
+               refreshBox(currWordObj,compResult);
+       }
+       this.afterKeyDown = function(currWordObj,compResult) {
+               refreshBox(currWordObj,compResult);
+       }
+       this.afterKeyUp = function(currWordObj,compResult) {
+               refreshBox(currWordObj,compResult);
+       }
+       this.afterCCRefresh = function(currWordObj,compResult) {
+               refreshBox(currWordObj,compResult);
+       }
+       function descriptionLoaded(desc) {
+               $('TSREF_description').innerHTML = desc;
+       }
+
+       function refreshBox(proposalObj,compResult) {
+               var type = compResult.getType();
+
+               if (type && type.properties[proposalObj.word]) {
+                       // first a container has to be built
+                       descriptionBox.innerHTML  = '<div class="TSREF_type_label">Object-type: </div><div class="TSREF_type">'+type.typeId+'</div>';
+                       descriptionBox.innerHTML += '<div class="TSREF_type_label">Property-type: </div><div class="TSREF_type">'+type.properties[proposalObj.word].value+'</div><br/>';
+                       descriptionBox.innerHTML += '<div class="TSREF_description_label">TSREF-description:</div><div id="TSREF_description"><img src="../../../gfx/spinner.gif" border="0" alt="one moment please..."/></div>';
+                       var prop = type.properties[proposalObj.word];
+                       // if there is another request for a description in the queue -> cancel it
+
+                       window.clearTimeout(this.lastTimeoutId);
+                       // add a request for a description onto the queue, but wait for 0.5 seconds
+                       // (look if user really wants to see the description of this property, if not -> don't load it)
+                       this.lastTimeoutId = prop.getDescription.bind(prop).delay(0.5,descriptionLoaded);
+                       descriptionBox.show();
+               } else if (proposalObj.type) {
+                       descriptionBox.innerHTML = '<div class="TSREF_type_label">TSREF-type: </div><div class="TSREF_type">'+proposalObj.type+'</div><br/>';
+                       descriptionBox.show();
+               } else {
+                       descriptionBox.innerHTML = '';
+                       descriptionBox.hide();
+               }
+
+
+               descriptionBox.scrollTop = 0;
+               descriptionBox.style.overflowY = 'scroll';
+               descriptionBox.style.class = 'descriptionBox';
+               var leftOffset = parseInt(completionBox.getStyle('left').gsub('px','')) + parseInt(completionBox.getStyle('width').gsub('px','')) + 5;
+               leftOffset += 'px';
+               descriptionBox.setStyle({
+                       top: completionBox.getStyle('top'),
+                       left: leftOffset
+               });
+       }
+
+       this.endCodeCompletion = function(){
+               descriptionBox.hide();  
+       }
+}
index 89116a2..2b5de78 100644 (file)
-/***************************************************************\r
-* Copyright notice\r
-*\r
-* (c) 2008-2009 Stephan Petzl <spetzl@gmx.at> and Christian Kartnig <office@hahnepeter.de> \r
-* All rights reserved\r
-*\r
-* This script is part of the TYPO3 project. The TYPO3 project is\r
-* free software; you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation; either version 2 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* The GNU General Public License can be found at\r
-* http://www.gnu.org/copyleft/gpl.html.\r
-* A copy is found in the textfile GPL.txt and important notices to the license\r
-* from the author is found in LICENSE.txt distributed with these scripts.\r
-*\r
-*\r
-* This script is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* This copyright notice MUST APPEAR in all copies of the script!\r
-***************************************************************/\r
-\r
-/**\r
- * @fileoverview contains the TsCodeCompletion class\r
- */\r
-\r
-/**\r
- * Construct a new TsCodeCompletion object.\r
- * @class This is the main class of the codeCompletion.\r
- * it is directly invoked by the editor. It instantiates all other classes\r
- * manages the control flow and takes care of the completionbox\r
- *\r
- * @constructor\r
- * @param codeMirror codeMirror instance, for retrieving the cursor position\r
- * @param outerdiv div that contains the editor, for DOM manipulation\r
- * @return A new TsCodeCompletion instance\r
- */\r
-var TsCodeCompletion = function(codeMirror,outerdiv) {\r
-       // private Vars\r
-       var tsRef  = new TsRef();\r
-       var mirror = codeMirror;\r
-       var options = {ccWords : 10};\r
-       // t3editor index (=0 if there is just one editor on the page, should be set from outside)\r
-       var index = 0;\r
-\r
-       var currWord = 0;\r
-       var cc_up;\r
-       var cc_down;\r
-       var mousePos = {x:0,y:0};\r
-       var proposals;\r
-       var compResult;\r
-       var cc = 0;\r
-       var linefeedsPrepared = false;\r
-       var currentCursorPosition = null;\r
-\r
-       Event.observe(document,'mousemove',saveMousePos, false);\r
-\r
-       // load the external templates ts-setup into extTsObjTree\r
-       var extTsObjTree = new Object();\r
-       var parser = new TsParser(tsRef,extTsObjTree);\r
-       loadExtTemplatesAsync();\r
-\r
-       //Event.observe(document, 'mousemove', setMousePos);\r
-\r
-       // TODO port pugin to t3editor.js\r
-\r
-       // plugin-array will be retrieved through AJAX from the conf array\r
-       // plugins can be attached by regular TYPO3-extensions\r
-       var plugins = [];\r
-\r
-//     we add the description plugin here because its packed with the codecompletion currently\r
-//     maybe we will swap it to an external plugin in future\r
-       var plugin = new Object();\r
-       plugin.extpath = PATH_t3e;\r
-       plugin.classpath =  'jslib/ts_codecompletion/descriptionPlugin.js';\r
-       plugin.classname = 'DescriptionPlugin';\r
-\r
-       plugins.push(plugin);\r
-\r
-\r
-//     TODO cleanup\r
-//     to roll back linebreaks inserted by hitting enter, the current node has to be stored before the codecompletion outside of the eventlistener\r
-//     var nodeBeforeInsert;\r
-\r
-\r
-       var codeCompleteBox = new Element("DIV", {\r
-               "class": "t3e_codeCompleteBox"\r
-       });\r
-       codeCompleteBox.hide();\r
-       outerdiv.appendChild(codeCompleteBox);\r
-\r
-//     TODO do we need this toolbar?\r
-       var toolbardiv = new Element("DIV", {\r
-               "class": "t3e_toolbar"\r
-       });\r
-       toolbardiv.show();\r
-       outerdiv.appendChild(toolbardiv);\r
-\r
-//     load the external xml-reference\r
-       tsRef.loadTsrefAsync();\r
-\r
-//     plugins will be provided with the pluginContext\r
-       var pluginContext = new Object();\r
-       pluginContext.outerdiv = outerdiv;\r
-       pluginContext.codeCompleteBox = codeCompleteBox;\r
-       pluginContext.toolbardiv = toolbardiv;\r
-       pluginContext.tsRef = tsRef;\r
-       pluginContext.parser = parser;\r
-       pluginContext.plugins = plugins;\r
-\r
-//     should we use a pluginmanager so no for loops are required on each hook?\r
-//     e.g. pluginmanager.call('afterKeyUp',....);\r
-       loadPluginArray();        \r
-\r
-\r
-       /**\r
-        * loads the array of registered codecompletion plugins\r
-        * to register a plugin you have to add an array to the localconf\r
-        * $TYPO3_CONF_VARS['EXTCONF']['t3editor']['plugins'][] = array( \r
-        *      'extpath' => t3lib_div::getIndpEnv('TYPO3_SITE_URL').t3lib_extMgm::siteRelPath($_EXTKEY),\r
-        *    'classpath' => 'js/my_plugin.js',\r
-        *    'classname'=> 'MyPlugin'\r
-        * );\r
-        */\r
-       function loadPluginArray() {\r
-               var urlParameters = '&ajaxID=tx_t3editor::getPlugins';\r
-               new Ajax.Request(\r
-                       URL_typo3 + 'ajax.php',\r
-                               {\r
-                               parameters: urlParameters,\r
-                               method: 'get',\r
-                               onSuccess: function(transport) {\r
-                                       var loadedPlugins = eval('('+ transport.responseText +')');\r
-                                       plugins = plugins.concat(loadedPlugins);\r
-                                       // register an internal plugin\r
-                                       loadPlugins();\r
-                               }\r
-                       }\r
-               );\r
-       }\r
-\r
-       /**\r
-        *  instantiates all plugins and adds the instances to the plugin array\r
-        */\r
-       function loadPlugins() {\r
-               for (var i = 0; i < plugins.length ; i++) {\r
-                       var script = document.createElement('script');\r
-                       script.setAttribute('type', 'text/javascript');\r
-                       script.setAttribute('src', plugins[i].extpath+plugins[i].classpath);\r
-                       document.getElementsByTagName('head')[0].appendChild(script);\r
-                       window.setTimeout(makeInstance.bind(this,plugins[i],i),1000);\r
-               } \r
-       }\r
-\r
-       /**\r
-        *  makes a single plugin instance\r
-        */\r
-       function makeInstance(plugin, i) {\r
-               try {\r
-                       var localname = "plugins[" + i + "].obj";\r
-                       eval(localname+' = new '+plugin.classname+'();');\r
-                       var obj = eval(localname);\r
-               } catch(e) {\r
-                       throw("error occured while trying to make new instance of \""+plugin.classname+"\"! maybe syntax error or wrong filepath?");\r
-                       return;\r
-               }\r
-               obj.init(pluginContext,plugin);\r
-       }\r
-\r
-       /**\r
-        * all external templates along the rootline have to be loaded, \r
-        * this function retrieves the JSON code by comitting a AJAX request\r
-        */    \r
-       function loadExtTemplatesAsync() {\r
-               var urlParameters = '&ajaxID=tx_t3editor_codecompletion::loadTemplates&pageId=' + getGetVar('id');\r
-               new Ajax.Request(\r
-                       URL_typo3 + 'ajax.php',\r
-                       {\r
-                               method: 'get',\r
-                               parameters: urlParameters,\r
-                               onSuccess: function(transport) {\r
-                                       extTsObjTree.c = eval('('+ transport.responseText +')');\r
-                                       resolveExtReferencesRec(extTsObjTree.c);\r
-                               }\r
-                       }\r
-               );\r
-       }\r
-\r
-       /**\r
-        * since the references are not resolved server side we have to do it client-side\r
-        * benefit: less loading time due to less data which has to be transmitted    \r
-        */\r
-       function resolveExtReferencesRec(childNodes) {\r
-               for(var key in childNodes) {\r
-                       var childNode;\r
-                       // if the childnode has a value and there is a parto of a reference operator ('<') \r
-                       // and it does not look like a html tag ('>') \r
-                       if (childNodes[key].v && childNodes[key].v[0] == '<' && childNodes[key].v.indexOf('>') == -1 ){\r
-                               var path = childNodes[key].v.replace(/</,"").strip();\r
-                               // if there are still whitespaces its no path\r
-                               if (path.indexOf(' ') == -1) {\r
-                                       childNode = getExtChildNode(path);\r
-                                       // if the node was found - reference it\r
-                                       if (childNode != null) {\r
-                                               childNodes[key] = childNode;\r
-                                       }\r
-                               }  \r
-                       }\r
-                       // if there was no reference-resolving then we go deeper into the tree\r
-                       if (!childNode && childNodes[key].c) {\r
-                               resolveExtReferencesRec(childNodes[key].c);\r
-                       }\r
-               }\r
-       }\r
-\r
-       function getExtChildNode(path) {\r
-               var extTree = extTsObjTree;\r
-               var path = path.split('.');\r
-               var pathSeg;\r
-               var i;\r
-               for ( i=0 ; i < path.length; i++) {\r
-                       pathSeg = path[i];\r
-                       if(extTree.c == null || extTree.c[pathSeg] == null) \r
-                               return null;\r
-                       extTree = extTree.c[pathSeg];\r
-               }\r
-               return extTree;\r
-       }\r
-\r
-       /**\r
-        * replaces editor functions insertNewlineAtCursor and indentAtCursor \r
-        * with modified ones that only execute when codecompletion box is not shown\r
-        */\r
-//     TODO check if this wokrs correctly after updating the codemirror base\r
-       function prepareLinefeeds() {\r
-               mirror.editor.win.select.insertNewlineAtCursor_original = mirror.editor.win.select.insertNewlineAtCursor;\r
-               mirror.editor.win.select.insertNewlineAtCursor = function(window) {\r
-                       if (cc==0) {\r
-                               mirror.editor.win.select.insertNewlineAtCursor_original(window);   \r
-                       }\r
-               };\r
-               mirror.editor.indentAtCursor_original = mirror.editor.indentAtCursor;\r
-               mirror.editor.indentAtCursor = function() {\r
-                       if (cc==0) {\r
-                               mirror.editor.indentAtCursor_original();   \r
-                       }\r
-               };\r
-               linefeedsPrepared = true;\r
-       }\r
-\r
-       /**\r
-        * Eventhandler function for mouseclicks\r
-        * ends the codecompletion\r
-        * @param event fired prototype event object      \r
-        * @type void   \r
-        */     \r
-       this.click = function(event) {\r
-               endAutoCompletion();\r
-       }\r
-\r
-       function getFilter(cursorNode){\r
-               if(cursorNode.currentText) {\r
-                       var filter = cursorNode.currentText.replace('.','');\r
-                       return filter.replace(/\s/g,"");\r
-               } else {\r
-                       return "";\r
-               }\r
-       }\r
-\r
-        function getCursorNode() {\r
-               var cursorNode = mirror.editor.win.select.selectionTopNode(mirror.editor.win.document.body, false);\r
-               // cursorNode is null if the cursor is positioned at the beginning of the first line\r
-               if (cursorNode == null) {\r
-                       cursorNode = mirror.editor.container.firstChild;\r
-               } else if (cursorNode.tagName=='BR') {\r
-                      // if cursor is at the end of the line -> jump to beginning of the next line\r
-                       cursorNode = cursorNode.nextSibling;\r
-              }\r
-               return cursorNode;\r
-        }\r
-\r
-\r
-       function getCurrentLine(cursor) {\r
-               var line = "";\r
-               var currentNode = cursor.start.node.parentNode;\r
-               while (currentNode.tagName !='BR') {\r
-                       if (currentNode.hasChildNodes() \r
-                                       && currentNode.firstChild.nodeType == 3 \r
-                                       && currentNode.currentText.length > 0) {\r
-                               line = currentNode.currentText + line; \r
-                       }\r
-                       if (currentNode.previousSibling == null) {\r
-                               break;\r
-                       } else {\r
-                               currentNode = currentNode.previousSibling;     \r
-                       }\r
-               }\r
-               return line;\r
-       }\r
-\r
-       /**\r
-        * Eventhandler function executed after keystroke release\r
-        * triggers CC on pressed dot and typing on   \r
-        * @param event fired prototype event object\r
-        * @type void      \r
-        */     \r
-       this.keyUp = function(event) {\r
-               var keycode = event.keyCode;\r
-               if  (keycode == 190) {\r
-                       refreshCodeCompletion();\r
-               } else if (cc == 1) {\r
-                       if (keycode != Event.KEY_DOWN && keycode != Event.KEY_UP) {\r
-                               refreshCodeCompletion();\r
-                       }\r
-               }\r
-       }\r
-\r
-       /**\r
-        * Eventhandler function executed after keystroke release\r
-        * triggers CC on pressed dot and typing on   \r
-        * @param event fired prototype event object\r
-        * @type void\r
-        */     \r
-       this.keyDown = function(event) {\r
-\r
-//             prepareLinefeeds() gets called the first time keyDown is executed.\r
-//             we have to put this here, cause in the constructor mirror.editor is not yet loaded \r
-               if (!linefeedsPrepared) {\r
-                       prepareLinefeeds();\r
-               }\r
-               var keycode = event.keyCode;\r
-               if (cc == 1) {\r
-                       if (keycode == Event.KEY_UP) {\r
-                               // arrow up:  move up cursor in codecomplete box\r
-                               event.stop();\r
-                               codeCompleteBoxMoveUpCursor();\r
-                               for (var i=0; i<plugins.length; i++) {\r
-                                       if (plugins[i].obj && plugins[i].obj.afterKeyUp) \r
-                                               plugins[i].obj.afterKeyUp(proposals[currWord],compResult);\r
-                               }\r
-\r
-                       } else if (keycode == Event.KEY_DOWN) {\r
-                               // Arrow down: move down cursor in codecomplete box\r
-                               event.stop();\r
-                               codeCompleteBoxMoveDownCursor();\r
-                               for (var i=0; i<plugins.length; i++){\r
-                                       if (plugins[i].obj && plugins[i].obj.afterKeyDown)\r
-                                               plugins[i].obj.afterKeyDown(proposals[currWord],compResult);\r
-                               }\r
-\r
-                       } else if (keycode == Event.KEY_ESC || keycode == Event.KEY_LEFT || keycode== Event.KEY_RIGHT) { \r
-                               // Esc, Arrow Left, Arrow Right: if codecomplete box is showing, hide it\r
-                               endAutoCompletion();\r
-\r
-                       } else if (keycode == Event.KEY_RETURN) {\r
-                               event.stop();\r
-                               if (currWord != -1) {\r
-                                       insertCurrWordAtCursor();\r
-                               }\r
-                               endAutoCompletion();\r
-\r
-                       } else if (keycode == 32 && !event.ctrlKey) {\r
-                               endAutoCompletion();\r
-\r
-                       } else if (keycode == 32 && event.ctrlKey) {\r
-                               refreshCodeCompletion();\r
-\r
-                       } else if (keycode == Event.KEY_BACKSPACE) {\r
-                               var cursorNode = mirror.editor.win.select.selectionTopNode(mirror.editor.win.document.body, false);\r
-                               if (cursorNode.innerHTML == '.') {\r
-                                       // force full refresh at keyUp \r
-                                       compResult = null; \r
-                               }\r
-                       }\r
-\r
-               } else { // if autocompletion is deactivated and ctrl+space is pressed\r
-                       if (keycode == 32 && event.ctrlKey) {\r
-                               event.stop();\r
-                               refreshCodeCompletion();\r
-                       }\r
-               }\r
-       }\r
-\r
-       function refreshCodeCompletion() {\r
-               // init vars for up/down moving in word list\r
-               cc_up = 0;\r
-               cc_down = options.ccWords-1;\r
-\r
-               // clear the last completion wordposition\r
-               currWord = -1;\r
-               mirror.editor.highlightAtCursor();\r
-\r
-               // retrieves the node right to the cursor\r
-               currentCursorPosition = mirror.editor.win.select.markSelection(mirror.editor.win);\r
-               cursorNode = getCursorNode();\r
-\r
-               // the cursornode has to be stored cause inserted breaks have to be deleted after pressing enter if the codecompletion is active\r
-               var filter = getFilter(cursorNode);\r
-\r
-               if (compResult == null || cursorNode.innerHTML == '.') {\r
-                       // TODO: implement cases: operatorCompletion reference/copy path completion (formerly found in getCompletionResults())\r
-                       var currentTsTreeNode = parser.buildTsObjTree(mirror.editor.container.firstChild, cursorNode);\r
-                       compResult = new CompletionResult(tsRef,currentTsTreeNode);\r
-               }\r
-\r
-               proposals = compResult.getFilteredProposals(filter);\r
-\r
-               // if proposals are found - show box\r
-               if (proposals.length > 0) {\r
-\r
-                       // make UL list of completation proposals\r
-                       var html = '<ul>';\r
-                       for (i = 0; i < proposals.length; i++) {\r
-                               html += '<li style="height:16px;vertical-align:middle;" ' +\r
-                               'id="cc_word_' + i + '" ' +\r
-                               'onclick="t3e_instances[' + index + '].tsCodeCompletion.insertCurrWordAtCursor(' + i + ');t3e_instances[' + index + '].tsCodeCompletion.endAutoCompletion();" ' +\r
-                               'onmouseover="t3e_instances[' + index + '].tsCodeCompletion.onMouseOver(' + i + ',event);">' +\r
-                               '<span class="word_' + proposals[i].cssClass + '">' +\r
-                               proposals[i].word +\r
-                               '</span></li>';\r
-                       }\r
-                       html += '</ul>';\r
-\r
-                       // put HTML and show box\r
-                       codeCompleteBox.innerHTML = html;\r
-                       codeCompleteBox.show();\r
-                       codeCompleteBox.scrollTop = 0;\r
-\r
-                       // init styles\r
-\r
-                       codeCompleteBox.style.overflowY = 'scroll';\r
-                       if (Prototype.Browser.Gecko) {\r
-                               codeCompleteBox.style.height = (options.ccWords * ($("cc_word_0").offsetHeight)) + 'px';\r
-                       } else {\r
-                               codeCompleteBox.style.height = (options.ccWords * ($("cc_word_0").offsetHeight)) + 4 + 'px';\r
-                               codeCompleteBox.style.width = codeCompleteBox.offsetWidth + 20 + 'px';\r
-                       }\r
-\r
-                       var leftpos = (Position.cumulativeOffset($$('.t3e_iframe_wrap')[index])[0] + Position.cumulativeOffset(cursorNode)[0] + cursorNode.offsetWidth) + 'px';\r
-                       var toppos = (Position.cumulativeOffset(cursorNode)[1] + cursorNode.offsetHeight - Element.cumulativeScrollOffset(cursorNode)[1]) + 'px';\r
-                       codeCompleteBox.setStyle({left: leftpos,top:  toppos});\r
-\r
-                       // set flag to 1 - needed for continue typing word. \r
-                       cc = 1;\r
-\r
-                       // highlight first word in list\r
-                       highlightCurrWord(0);\r
-                       for (var i=0;i<plugins.length;i++) {\r
-                               if (plugins[i].obj && plugins[i].obj.afterCCRefresh)\r
-                                       plugins[i].obj.afterCCRefresh(proposals[currWord],compResult);\r
-                       }\r
-               } else {\r
-                       endAutoCompletion();\r
-               }\r
-       }\r
-\r
-\r
-\r
-\r
-       /**\r
-        * hides codecomplete box and resets completionResult\r
-        * afterwards the interceptor method endCodeCompletion gets called\r
-        * @type void      \r
-        */    \r
-       this.endAutoCompletion = function() {\r
-               endAutoCompletion();\r
-       }  \r
-\r
-       function endAutoCompletion(){\r
-               cc = 0;\r
-               codeCompleteBox.hide();\r
-//             force full refresh  \r
-               compResult = null;\r
-               for (var i=0;i<plugins.length;i++) {\r
-                       if (plugins[i].obj && plugins[i].obj.endCodeCompletion)\r
-                               plugins[i].obj.endCodeCompletion();\r
-               }\r
-       }\r
-\r
-\r
-//     move cursor in autcomplete box up\r
-       function codeCompleteBoxMoveUpCursor() {\r
-               // if previous position was first or position not initialized - then move cursor to last word, else decrease position\r
-               if (currWord == 0 || currWord == -1) {\r
-                       var id = proposals.length - 1;\r
-               } else {\r
-                       var id = currWord - 1;\r
-               }\r
-               // hightlight new cursor position\r
-               highlightCurrWord(id);\r
-               // update id of first and last showing proposals and scroll box\r
-               if (currWord < cc_up || currWord == (proposals.length - 1)) {\r
-                       cc_up = currWord;\r
-                       cc_down = currWord + (options.ccWords - 1);\r
-                       if (cc_up === (proposals.length - 1)) {\r
-                               cc_down = proposals.length - 1;\r
-                               cc_up = cc_down - (options.ccWords - 1);\r
-                       }\r
-                       codeCompleteBox.scrollTop = cc_up * 16;\r
-               }\r
-       }\r
-\r
-//     move cursor in codecomplete box down\r
-       function codeCompleteBoxMoveDownCursor() {\r
-               // if previous position was last word in list - then move cursor to first word if not than      position ++\r
-               if (currWord == proposals.length - 1) {\r
-                       var id = 0;\r
-               } else {\r
-                       var id = currWord + 1;\r
-               }\r
-               // highlight new cursor position\r
-               highlightCurrWord(id);\r
-\r
-               // update id of first and last showing proposals and scroll box\r
-               if (currWord > cc_down || currWord == 0) {\r
-                       cc_down = currWord;\r
-                       cc_up = currWord - (options.ccWords - 1);\r
-                       if (cc_down == 0) {\r
-                               cc_up = 0;\r
-                               cc_down = options.ccWords - 1;\r
-                       }\r
-                       codeCompleteBox.scrollTop = cc_up * 16;\r
-               }\r
-       }\r
-\r
-       function saveMousePos(event){\r
-               mousePos.x = event.clientX;\r
-               mousePos.y = event.clientY;\r
-       } \r
-       /**\r
-        * highlights entry in codecomplete box by id\r
-        * @param {int} id\r
-        * @type void\r
-        */\r
-       this.onMouseOver = function(id,event){\r
-               highlightCurrWord(id,event);\r
-               for(var i=0;i<plugins.length;i++){\r
-                       if(plugins[i].obj && plugins[i].obj.afterMouseOver) plugins[i].obj.afterMouseOver(proposals[currWord],compResult);\r
-               }\r
-       }\r
-       function highlightCurrWord(id,event) {\r
-//             if it is a mouseover event\r
-               if(event){\r
-                       // if mousecoordinates haven't changed -> mouseover was triggered by scrolling of the result list -> don't highlight another word (return) \r
-                       if(mousePos.x == event.clientX && mousePos.y == event.clientY)\r
-                               return;\r
-                       mousePos.x = event.clientX;\r
-                       mousePos.y = event.clientY;\r
-               }\r
-               if (currWord != -1) {\r
-                       $('cc_word_' + currWord).className = '';\r
-               }\r
-               $('cc_word_' + id).className = 'active';\r
-               currWord = id;\r
-       }\r
-\r
-       /**\r
-        * Insert the currently selected item in the proposal list\r
-        * of the codecompletion box into the editor div at cursor position\r
-        * @type void\r
-        * @see #highlightCurrWord\r
-        */\r
-       this.insertCurrWordAtCursor = function(){\r
-               insertCurrWordAtCursor();\r
-       }\r
-       // insert selected word into text from codecompletebox\r
-       function insertCurrWordAtCursor() {\r
-               var word = proposals[currWord].word;\r
-               mirror.editor.highlightAtCursor();\r
-               var cursorNode = getCursorNode();\r
-               if (cursorNode.currentText \r
-                          && cursorNode.currentText != '.' \r
-                          && cursorNode.currentText.strip() != '' ) {\r
-                  cursorNode.innerHTML = '';\r
-                   cursorNode.currentText = '';\r
-               }\r
-               mirror.replaceSelection(word);\r
-               // set cursor behind the selection\r
-               var select = mirror.editor.win.select;\r
-               var start = select.cursorPos(mirror.editor.container, true),\r
-               end = select.cursorPos(mirror.editor.container, false);\r
-               if (!start || !end) return;\r
-               select.setCursorPos(mirror.editor.container, end, end);\r
-       }\r
-\r
-\r
-//     TODO remove if unneeded\r
-       /**\r
-        * determines what kind of completion is possible and return a array of proposals\r
-        * if we have no suggestions, the list will be empty\r
-        */ \r
-       /*\r
-function getCompletionResult(startNode, cursor) {\r
-var compResult;\r
-buildTsObjTree(startNode, cursor);\r
-\r
-// is there an operator left of the current curser Position (= in the currentLine)\r
-var op = getOperator(currentLine); \r
-if (op != -1) {\r
-  // is it a reference/copy operator?\r
-  if (op.indexOf("<") != -1) {\r
-       // show path completion\r
-       compResult = getPathCompletion(currentTsTreeNode);\r
-  } else {\r
-       // show what ?????     \r
-       // biggest mystery!!\r
-       // think about!\r
-  } \r
-// no operator in the line\r
-} else {\r
-\r
-  // whitespace after last characters? -> show operators\r
-  if(currentLine.substr(-1,1) == " ") {\r
-       compResult = getOperatorCompletion();\r
-  // no whitespace? we're in a path!\r
-  } else {\r
-       compResult = getPathCompletion(currentTsTreeNode);\r
-  }\r
-}\r
-\r
-return compResult;\r
-}*/\r
-\r
-       /**\r
-        * retrieves the get-variable with the specified name\r
-        */\r
-       function getGetVar(name){\r
-               var get_string = document.location.search;\r
-               var return_value = '';\r
-               var value;\r
-               do { //This loop is made to catch all instances of any get variable.\r
-                       var name_index = get_string.indexOf(name + '=');\r
-                       if (name_index != -1) {\r
-                               get_string = get_string.substr(name_index + name.length + 1, get_string.length - name_index);\r
-                               end_of_value = get_string.indexOf('&');\r
-                               if (end_of_value != -1) {\r
-                                       value = get_string.substr(0, end_of_value);\r
-                               } else {\r
-                                       value = get_string;\r
-                               }\r
-\r
-                               if (return_value == '' || value == '') {\r
-                                       return_value += value;\r
-                               } else {\r
-                                       return_value += ', ' + value;\r
-                               }\r
-                       }\r
-               } while(name_index != -1);\r
-\r
-//             Restores all the blank spaces.\r
-               var space = return_value.indexOf('+');\r
-               while(space != -1) {\r
-                       return_value = return_value.substr(0, space) + ' ' + \r
-                       return_value.substr(space + 1, return_value.length);\r
-                       space = return_value.indexOf('+');\r
-               }\r
-\r
-               return(return_value);        \r
-       }\r
+/***************************************************************
+* Copyright notice
+*
+* (c) 2008-2009 Stephan Petzl <spetzl@gmx.at> and Christian Kartnig <office@hahnepeter.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!
+***************************************************************/
+
+/**
+ * @fileoverview contains the TsCodeCompletion class
+ */
+
+/**
+ * Construct a new TsCodeCompletion object.
+ * @class This is the main class of the codeCompletion.
+ * it is directly invoked by the editor. It instantiates all other classes
+ * manages the control flow and takes care of the completionbox
+ *
+ * @constructor
+ * @param codeMirror codeMirror instance, for retrieving the cursor position
+ * @param outerdiv div that contains the editor, for DOM manipulation
+ * @return A new TsCodeCompletion instance
+ */
+var TsCodeCompletion = function(codeMirror,outerdiv) {
+       // private Vars
+       var tsRef  = new TsRef();
+       var mirror = codeMirror;
+       var options = {ccWords : 10};
+       // t3editor index (=0 if there is just one editor on the page, should be set from outside)
+       var index = 0;
+
+       var currWord = 0;
+       var cc_up;
+       var cc_down;
+       var mousePos = {x:0,y:0};
+       var proposals;
+       var compResult;
+       var cc = 0;
+       var linefeedsPrepared = false;
+       var currentCursorPosition = null;
+
+       Event.observe(document,'mousemove',saveMousePos, false);
+
+       // load the external templates ts-setup into extTsObjTree
+       var extTsObjTree = new Object();
+       var parser = new TsParser(tsRef,extTsObjTree);
+       loadExtTemplatesAsync();
+
+       //Event.observe(document, 'mousemove', setMousePos);
+
+       // TODO port pugin to t3editor.js
+
+       // plugin-array will be retrieved through AJAX from the conf array
+       // plugins can be attached by regular TYPO3-extensions
+       var plugins = [];
+
+//     we add the description plugin here because its packed with the codecompletion currently
+//     maybe we will swap it to an external plugin in future
+       var plugin = new Object();
+       plugin.extpath = PATH_t3e;
+       plugin.classpath =  'jslib/ts_codecompletion/descriptionPlugin.js';
+       plugin.classname = 'DescriptionPlugin';
+
+       plugins.push(plugin);
+
+
+//     TODO cleanup
+//     to roll back linebreaks inserted by hitting enter, the current node has to be stored before the codecompletion outside of the eventlistener
+//     var nodeBeforeInsert;
+
+
+       var codeCompleteBox = new Element("DIV", {
+               "class": "t3e_codeCompleteBox"
+       });
+       codeCompleteBox.hide();
+       outerdiv.appendChild(codeCompleteBox);
+
+//     TODO do we need this toolbar?
+       var toolbardiv = new Element("DIV", {
+               "class": "t3e_toolbar"
+       });
+       toolbardiv.show();
+       outerdiv.appendChild(toolbardiv);
+
+//     load the external xml-reference
+       tsRef.loadTsrefAsync();
+
+//     plugins will be provided with the pluginContext
+       var pluginContext = new Object();
+       pluginContext.outerdiv = outerdiv;
+       pluginContext.codeCompleteBox = codeCompleteBox;
+       pluginContext.toolbardiv = toolbardiv;
+       pluginContext.tsRef = tsRef;
+       pluginContext.parser = parser;
+       pluginContext.plugins = plugins;
+
+//     should we use a pluginmanager so no for loops are required on each hook?
+//     e.g. pluginmanager.call('afterKeyUp',....);
+       loadPluginArray();        
+
+
+       /**
+        * loads the array of registered codecompletion plugins
+        * to register a plugin you have to add an array to the localconf
+        * $TYPO3_CONF_VARS['EXTCONF']['t3editor']['plugins'][] = array( 
+        *      'extpath' => t3lib_div::getIndpEnv('TYPO3_SITE_URL').t3lib_extMgm::siteRelPath($_EXTKEY),
+        *    'classpath' => 'js/my_plugin.js',
+        *    'classname'=> 'MyPlugin'
+        * );
+        */
+       function loadPluginArray() {
+               var urlParameters = '&ajaxID=tx_t3editor::getPlugins';
+               new Ajax.Request(
+                       URL_typo3 + 'ajax.php',
+                               {
+                               parameters: urlParameters,
+                               method: 'get',
+                               onSuccess: function(transport) {
+                                       var loadedPlugins = eval('('+ transport.responseText +')');
+                                       plugins = plugins.concat(loadedPlugins);
+                                       // register an internal plugin
+                                       loadPlugins();
+                               }
+                       }
+               );
+       }
+
+       /**
+        *  instantiates all plugins and adds the instances to the plugin array
+        */
+       function loadPlugins() {
+               for (var i = 0; i < plugins.length ; i++) {
+                       var script = document.createElement('script');
+                       script.setAttribute('type', 'text/javascript');
+                       script.setAttribute('src', plugins[i].extpath+plugins[i].classpath);
+                       document.getElementsByTagName('head')[0].appendChild(script);
+                       window.setTimeout(makeInstance.bind(this,plugins[i],i),1000);
+               } 
+       }
+
+       /**
+        *  makes a single plugin instance
+        */
+       function makeInstance(plugin, i) {
+               try {
+                       var localname = "plugins[" + i + "].obj";
+                       eval(localname+' = new '+plugin.classname+'();');
+                       var obj = eval(localname);
+               } catch(e) {
+                       throw("error occured while trying to make new instance of \""+plugin.classname+"\"! maybe syntax error or wrong filepath?");
+                       return;
+               }
+               obj.init(pluginContext,plugin);
+       }
+
+       /**
+        * all external templates along the rootline have to be loaded, 
+        * this function retrieves the JSON code by comitting a AJAX request
+        */    
+       function loadExtTemplatesAsync() {
+               var urlParameters = '&ajaxID=tx_t3editor_codecompletion::loadTemplates&pageId=' + getGetVar('id');
+               new Ajax.Request(
+                       URL_typo3 + 'ajax.php',
+                       {
+                               method: 'get',
+                               parameters: urlParameters,
+                               onSuccess: function(transport) {
+                                       extTsObjTree.c = eval('('+ transport.responseText +')');
+                                       resolveExtReferencesRec(extTsObjTree.c);
+                               }
+                       }
+               );
+       }
+
+       /**
+        * since the references are not resolved server side we have to do it client-side
+        * benefit: less loading time due to less data which has to be transmitted    
+        */
+       function resolveExtReferencesRec(childNodes) {
+               for(var key in childNodes) {
+                       var childNode;
+                       // if the childnode has a value and there is a parto of a reference operator ('<') 
+                       // and it does not look like a html tag ('>') 
+                       if (childNodes[key].v && childNodes[key].v[0] == '<' && childNodes[key].v.indexOf('>') == -1 ){
+                               var path = childNodes[key].v.replace(/</,"").strip();
+                               // if there are still whitespaces its no path
+                               if (path.indexOf(' ') == -1) {
+                                       childNode = getExtChildNode(path);
+                                       // if the node was found - reference it
+                                       if (childNode != null) {
+                                               childNodes[key] = childNode;
+                                       }
+                               }  
+                       }
+                       // if there was no reference-resolving then we go deeper into the tree
+                       if (!childNode && childNodes[key].c) {
+                               resolveExtReferencesRec(childNodes[key].c);
+                       }
+               }
+       }
+
+       function getExtChildNode(path) {
+               var extTree = extTsObjTree;
+               var path = path.split('.');
+               var pathSeg;
+               var i;
+               for ( i=0 ; i < path.length; i++) {
+                       pathSeg = path[i];
+                       if(extTree.c == null || extTree.c[pathSeg] == null) 
+                               return null;
+                       extTree = extTree.c[pathSeg];
+               }
+               return extTree;
+       }
+
+       /**
+        * replaces editor functions insertNewlineAtCursor and indentAtCursor 
+        * with modified ones that only execute when codecompletion box is not shown
+        */
+//     TODO check if this wokrs correctly after updating the codemirror base
+       function prepareLinefeeds() {
+               mirror.editor.win.select.insertNewlineAtCursor_original = mirror.editor.win.select.insertNewlineAtCursor;
+               mirror.editor.win.select.insertNewlineAtCursor = function(window) {
+                       if (cc==0) {
+                               mirror.editor.win.select.insertNewlineAtCursor_original(window);   
+                       }
+               };
+               mirror.editor.indentAtCursor_original = mirror.editor.indentAtCursor;
+               mirror.editor.indentAtCursor = function() {
+                       if (cc==0) {
+                               mirror.editor.indentAtCursor_original();   
+                       }
+               };
+               linefeedsPrepared = true;
+       }
+
+       /**
+        * Eventhandler function for mouseclicks
+        * ends the codecompletion
+        * @param event fired prototype event object      
+        * @type void   
+        */     
+       this.click = function(event) {
+               endAutoCompletion();
+       }
+
+       function getFilter(cursorNode){
+               if(cursorNode.currentText) {
+                       var filter = cursorNode.currentText.replace('.','');
+                       return filter.replace(/\s/g,"");
+               } else {
+                       return "";
+               }
+       }
+
+        function getCursorNode() {
+               var cursorNode = mirror.editor.win.select.selectionTopNode(mirror.editor.win.document.body, false);
+               // cursorNode is null if the cursor is positioned at the beginning of the first line
+               if (cursorNode == null) {
+                       cursorNode = mirror.editor.container.firstChild;
+               } else if (cursorNode.tagName=='BR') {
+                      // if cursor is at the end of the line -> jump to beginning of the next line
+                       cursorNode = cursorNode.nextSibling;
+              }
+               return cursorNode;
+        }
+
+
+       function getCurrentLine(cursor) {
+               var line = "";
+               var currentNode = cursor.start.node.parentNode;
+               while (currentNode.tagName !='BR') {
+                       if (currentNode.hasChildNodes() 
+                                       && currentNode.firstChild.nodeType == 3 
+                                       && currentNode.currentText.length > 0) {
+                               line = currentNode.currentText + line; 
+                       }
+                       if (currentNode.previousSibling == null) {
+                               break;
+                       } else {
+                               currentNode = currentNode.previousSibling;     
+                       }
+               }
+               return line;
+       }
+
+       /**
+        * Eventhandler function executed after keystroke release
+        * triggers CC on pressed dot and typing on   
+        * @param event fired prototype event object
+        * @type void      
+        */     
+       this.keyUp = function(event) {
+               var keycode = event.keyCode;
+               if  (keycode == 190) {
+                       refreshCodeCompletion();
+               } else if (cc == 1) {
+                       if (keycode != Event.KEY_DOWN && keycode != Event.KEY_UP) {
+                               refreshCodeCompletion();
+                       }
+               }
+       }
+
+       /**
+        * Eventhandler function executed after keystroke release
+        * triggers CC on pressed dot and typing on   
+        * @param event fired prototype event object
+        * @type void
+        */     
+       this.keyDown = function(event) {
+
+//             prepareLinefeeds() gets called the first time keyDown is executed.
+//             we have to put this here, cause in the constructor mirror.editor is not yet loaded 
+               if (!linefeedsPrepared) {
+                       prepareLinefeeds();
+               }
+               var keycode = event.keyCode;
+               if (cc == 1) {
+                       if (keycode == Event.KEY_UP) {
+                               // arrow up:  move up cursor in codecomplete box
+                               event.stop();
+                               codeCompleteBoxMoveUpCursor();
+                               for (var i=0; i<plugins.length; i++) {
+                                       if (plugins[i].obj && plugins[i].obj.afterKeyUp) 
+                                               plugins[i].obj.afterKeyUp(proposals[currWord],compResult);
+                               }
+
+                       } else if (keycode == Event.KEY_DOWN) {
+                               // Arrow down: move down cursor in codecomplete box
+                               event.stop();
+                               codeCompleteBoxMoveDownCursor();
+                               for (var i=0; i<plugins.length; i++){
+                                       if (plugins[i].obj && plugins[i].obj.afterKeyDown)
+                                               plugins[i].obj.afterKeyDown(proposals[currWord],compResult);
+                               }
+
+                       } else if (keycode == Event.KEY_ESC || keycode == Event.KEY_LEFT || keycode== Event.KEY_RIGHT) { 
+                               // Esc, Arrow Left, Arrow Right: if codecomplete box is showing, hide it
+                               endAutoCompletion();
+
+                       } else if (keycode == Event.KEY_RETURN) {
+                               event.stop();
+                               if (currWord != -1) {
+                                       insertCurrWordAtCursor();
+                               }
+                               endAutoCompletion();
+
+                       } else if (keycode == 32 && !event.ctrlKey) {
+                               endAutoCompletion();
+
+                       } else if (keycode == 32 && event.ctrlKey) {
+                               refreshCodeCompletion();
+
+                       } else if (keycode == Event.KEY_BACKSPACE) {
+                               var cursorNode = mirror.editor.win.select.selectionTopNode(mirror.editor.win.document.body, false);
+                               if (cursorNode.innerHTML == '.') {
+                                       // force full refresh at keyUp 
+                                       compResult = null; 
+                               }
+                       }
+
+               } else { // if autocompletion is deactivated and ctrl+space is pressed
+                       if (keycode == 32 && event.ctrlKey) {
+                               event.stop();
+                               refreshCodeCompletion();
+                       }
+               }
+       }
+
+       function refreshCodeCompletion() {
+               // init vars for up/down moving in word list
+               cc_up = 0;
+               cc_down = options.ccWords-1;
+
+               // clear the last completion wordposition
+               currWord = -1;
+               mirror.editor.highlightAtCursor();
+
+               // retrieves the node right to the cursor
+               currentCursorPosition = mirror.editor.win.select.markSelection(mirror.editor.win);
+               cursorNode = getCursorNode();
+
+               // the cursornode has to be stored cause inserted breaks have to be deleted after pressing enter if the codecompletion is active
+               var filter = getFilter(cursorNode);
+
+               if (compResult == null || cursorNode.innerHTML == '.') {
+                       // TODO: implement cases: operatorCompletion reference/copy path completion (formerly found in getCompletionResults())
+                       var currentTsTreeNode = parser.buildTsObjTree(mirror.editor.container.firstChild, cursorNode);
+                       compResult = new CompletionResult(tsRef,currentTsTreeNode);
+               }
+
+               proposals = compResult.getFilteredProposals(filter);
+
+               // if proposals are found - show box
+               if (proposals.length > 0) {
+
+                       // make UL list of completation proposals
+                       var html = '<ul>';
+                       for (i = 0; i < proposals.length; i++) {
+                               html += '<li style="height:16px;vertical-align:middle;" ' +
+                               'id="cc_word_' + i + '" ' +
+                               'onclick="t3e_instances[' + index + '].tsCodeCompletion.insertCurrWordAtCursor(' + i + ');t3e_instances[' + index + '].tsCodeCompletion.endAutoCompletion();" ' +
+                               'onmouseover="t3e_instances[' + index + '].tsCodeCompletion.onMouseOver(' + i + ',event);">' +
+                               '<span class="word_' + proposals[i].cssClass + '">' +
+                               proposals[i].word +
+                               '</span></li>';
+                       }
+                       html += '</ul>';
+
+                       // put HTML and show box
+                       codeCompleteBox.innerHTML = html;
+                       codeCompleteBox.show();
+                       codeCompleteBox.scrollTop = 0;
+
+                       // init styles
+
+                       codeCompleteBox.style.overflowY = 'scroll';
+                       if (Prototype.Browser.Gecko) {
+                               codeCompleteBox.style.height = (options.ccWords * ($("cc_word_0").offsetHeight)) + 'px';
+                       } else {
+                               codeCompleteBox.style.height = (options.ccWords * ($("cc_word_0").offsetHeight)) + 4 + 'px';
+                               codeCompleteBox.style.width = codeCompleteBox.offsetWidth + 20 + 'px';
+                       }
+
+                       var leftpos = (Position.cumulativeOffset($$('.t3e_iframe_wrap')[index])[0] + Position.cumulativeOffset(cursorNode)[0] + cursorNode.offsetWidth) + 'px';
+                       var toppos = (Position.cumulativeOffset(cursorNode)[1] + cursorNode.offsetHeight - Element.cumulativeScrollOffset(cursorNode)[1]) + 'px';
+                       codeCompleteBox.setStyle({left: leftpos,top:  toppos});
+
+                       // set flag to 1 - needed for continue typing word. 
+                       cc = 1;
+
+                       // highlight first word in list
+                       highlightCurrWord(0);
+                       for (var i=0;i<plugins.length;i++) {
+                               if (plugins[i].obj && plugins[i].obj.afterCCRefresh)
+                                       plugins[i].obj.afterCCRefresh(proposals[currWord],compResult);
+                       }
+               } else {
+                       endAutoCompletion();
+               }
+       }
+
+
+
+
+       /**
+        * hides codecomplete box and resets completionResult
+        * afterwards the interceptor method endCodeCompletion gets called
+        * @type void      
+        */    
+       this.endAutoCompletion = function() {
+               endAutoCompletion();
+       }  
+
+       function endAutoCompletion(){
+               cc = 0;
+               codeCompleteBox.hide();
+//             force full refresh  
+               compResult = null;
+               for (var i=0;i<plugins.length;i++) {
+                       if (plugins[i].obj && plugins[i].obj.endCodeCompletion)
+                               plugins[i].obj.endCodeCompletion();
+               }
+       }
+
+
+//     move cursor in autcomplete box up
+       function codeCompleteBoxMoveUpCursor() {
+               // if previous position was first or position not initialized - then move cursor to last word, else decrease position
+               if (currWord == 0 || currWord == -1) {
+                       var id = proposals.length - 1;
+               } else {
+                       var id = currWord - 1;
+               }
+               // hightlight new cursor position
+               highlightCurrWord(id);
+               // update id of first and last showing proposals and scroll box
+               if (currWord < cc_up || currWord == (proposals.length - 1)) {
+                       cc_up = currWord;
+                       cc_down = currWord + (options.ccWords - 1);
+                       if (cc_up === (proposals.length - 1)) {
+                               cc_down = proposals.length - 1;
+                               cc_up = cc_down - (options.ccWords - 1);
+                       }
+                       codeCompleteBox.scrollTop = cc_up * 16;
+               }
+       }
+
+//     move cursor in codecomplete box down
+       function codeCompleteBoxMoveDownCursor() {
+               // if previous position was last word in list - then move cursor to first word if not than      position ++
+               if (currWord == proposals.length - 1) {
+                       var id = 0;
+               } else {
+                       var id = currWord + 1;
+               }
+               // highlight new cursor position
+               highlightCurrWord(id);
+
+               // update id of first and last showing proposals and scroll box
+               if (currWord > cc_down || currWord == 0) {
+                       cc_down = currWord;
+                       cc_up = currWord - (options.ccWords - 1);
+                       if (cc_down == 0) {
+                               cc_up = 0;
+                               cc_down = options.ccWords - 1;
+                       }
+                       codeCompleteBox.scrollTop = cc_up * 16;
+               }
+       }
+
+       function saveMousePos(event){
+               mousePos.x = event.clientX;
+               mousePos.y = event.clientY;
+       } 
+       /**
+        * highlights entry in codecomplete box by id
+        * @param {int} id
+        * @type void
+        */
+       this.onMouseOver = function(id,event){
+               highlightCurrWord(id,event);
+               for(var i=0;i<plugins.length;i++){
+                       if(plugins[i].obj && plugins[i].obj.afterMouseOver) plugins[i].obj.afterMouseOver(proposals[currWord],compResult);
+               }
+       }
+       function highlightCurrWord(id,event) {
+//             if it is a mouseover event
+               if(event){
+                       // if mousecoordinates haven't changed -> mouseover was triggered by scrolling of the result list -> don't highlight another word (return) 
+                       if(mousePos.x == event.clientX && mousePos.y == event.clientY)
+                               return;
+                       mousePos.x = event.clientX;
+                       mousePos.y = event.clientY;
+               }
+               if (currWord != -1) {
+                       $('cc_word_' + currWord).className = '';
+               }
+               $('cc_word_' + id).className = 'active';
+               currWord = id;
+       }
+
+       /**
+        * Insert the currently selected item in the proposal list
+        * of the codecompletion box into the editor div at cursor position
+        * @type void
+        * @see #highlightCurrWord
+        */
+       this.insertCurrWordAtCursor = function(){
+               insertCurrWordAtCursor();
+       }
+       // insert selected word into text from codecompletebox
+       function insertCurrWordAtCursor() {
+               var word = proposals[currWord].word;
+               mirror.editor.highlightAtCursor();
+               var cursorNode = getCursorNode();
+               if (cursorNode.currentText 
+                          && cursorNode.currentText != '.' 
+                          && cursorNode.currentText.strip() != '' ) {
+                  cursorNode.innerHTML = '';
+                   cursorNode.currentText = '';
+               }
+               mirror.replaceSelection(word);
+               // set cursor behind the selection
+               var select = mirror.editor.win.select;
+               var start = select.cursorPos(mirror.editor.container, true),
+               end = select.cursorPos(mirror.editor.container, false);
+               if (!start || !end) return;
+               select.setCursorPos(mirror.editor.container, end, end);
+       }
+
+
+//     TODO remove if unneeded
+       /**
+        * determines what kind of completion is possible and return a array of proposals
+        * if we have no suggestions, the list will be empty
+        */ 
+       /*
+function getCompletionResult(startNode, cursor) {
+var compResult;
+buildTsObjTree(startNode, cursor);
+
+// is there an operator left of the current curser Position (= in the currentLine)
+var op = getOperator(currentLine); 
+if (op != -1) {
+  // is it a reference/copy operator?
+  if (op.indexOf("<") != -1) {
+       // show path completion
+       compResult = getPathCompletion(currentTsTreeNode);
+  } else {
+       // show what ?????     
+       // biggest mystery!!
+       // think about!
+  } 
+// no operator in the line
+} else {
+
+  // whitespace after last characters? -> show operators
+  if(currentLine.substr(-1,1) == " ") {
+       compResult = getOperatorCompletion();
+  // no whitespace? we're in a path!
+  } else {
+       compResult = getPathCompletion(currentTsTreeNode);
+  }
+}
+
+return compResult;
+}*/
+
+       /**
+        * retrieves the get-variable with the specified name
+        */
+       function getGetVar(name){
+               var get_string = document.location.search;
+               var return_value = '';
+               var value;
+               do { //This loop is made to catch all instances of any get variable.
+                       var name_index = get_string.indexOf(name + '=');
+                       if (name_index != -1) {
+                               get_string = get_string.substr(name_index + name.length + 1, get_string.length - name_index);
+                               end_of_value = get_string.indexOf('&');
+                               if (end_of_value != -1) {
+                                       value = get_string.substr(0, end_of_value);
+                               } else {
+                                       value = get_string;
+                               }
+
+                               if (return_value == '' || value == '') {
+                                       return_value += value;
+                               } else {
+                                       return_value += ', ' + value;
+                               }
+                       }
+               } while(name_index != -1);
+
+//             Restores all the blank spaces.
+               var space = return_value.indexOf('+');
+               while(space != -1) {
+                       return_value = return_value.substr(0, space) + ' ' + 
+                       return_value.substr(space + 1, return_value.length);
+                       space = return_value.indexOf('+');
+               }
+
+               return(return_value);        
+       }
 }
\ No newline at end of file
index 0c77024..b6bde5f 100644 (file)
-/***************************************************************\r
-* Copyright notice\r
-*\r
-* (c) 2008-2009 Stephan Petzl <spetzl@gmx.at> and Christian Kartnig <office@hahnepeter.de>\r
-* All rights reserved\r
-*\r
-* This script is part of the TYPO3 project. The TYPO3 project is\r
-* free software; you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation; either version 2 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* The GNU General Public License can be found at\r
-* http://www.gnu.org/copyleft/gpl.html.\r
-* A copy is found in the textfile GPL.txt and important notices to the license\r
-* from the author is found in LICENSE.txt distributed with these scripts.\r
-*\r
-*\r
-* This script is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* This copyright notice MUST APPEAR in all copies of the script!\r
-***************************************************************/\r
-/**\r
- * @fileoverview contains the TsParser class and the TreeNode helper class\r
- */\r
-\r
-/**\r
- * Construct a new TsParser object.\r
- * @class This class takes care of the parsing and builds the codeTree\r
- *\r
- * @constructor\r
- * @param tsRef typoscript reference tree\r
- * @param extTsObjTree codeTree for all typoscript templates\r
- *                      excluding the current one.\r
- * @return A new TsParser instance\r
- */\r
-var TsParser = function(tsRef,extTsObjTree){\r
-\r
-       /**\r
-        * @class data structure for the nodes of the code tree\r
-        * mainly used for retrieving the externals templates childnodes\r
-        * @constructor\r
-        * @param {String} name\r
-        */\r
-       function TreeNode(nodeName){\r
-               this.name = nodeName;\r
-               //this.tsObjTree = tsObjTree;\r
-               this.childNodes = new Array();\r
-               //has to be set, so the node can retrieve the childnodes of the external templates \r
-               this.extPath = "";\r
-               // the TS-objecttype ID (TSREF) \r
-               this.value = "";\r
-               //this.extTsObjTree = null;\r
-               // current template or external template\r
-               this.isExternal = false;\r
-\r
-               /**\r
-                * returns local properties and the properties of the external templates\r
-                * @returns {Array} ChildNodes\r
-                */           \r
-               this.getChildNodes = function(){  \r
-                       var node = this.getExtNode();\r
-                       if(node){\r
-                               for(key in node.c){\r
-                                       var tn = new TreeNode(key,this.tsObjTree);\r
-                                       tn.global = true;\r
-                                       tn.value = (node.c[key].v)? node.c[key].v : "";\r
-                                       tn.isExternal = true;\r
-                                       this.childNodes[key] = tn;\r
-                               }\r
-                       }\r
-                       return this.childNodes;\r
-               }\r
-\r
-               this.getValue = function(){\r
-                       if(this.value) {\r
-                               return this.value;\r
-                       } else {\r
-                               var node = this.getExtNode();\r
-                               if(node && node.v) {\r
-                                       return node.v;\r
-                               } else {\r
-                                       var type = this.getNodeTypeFromTsref();\r
-                                       if(type)\r
-                                               return type;\r
-                                       else\r
-                                               return '';\r
-                               }\r
-                       }\r
-               }\r
-\r
-               /**\r
-                * This method will try to resolve the properties recursively from right\r
-                * to left. If the node's value property is not set, it will look for the\r
-                * value of its parent node, and if there is a matching childProperty \r
-                * (according to the TSREF) it will return the childProperties value. \r
-                * If there is no value in the parent node it will go one step further \r
-                * and look into the parent node of the parent node,...      \r
-                **/              \r
-               this.getNodeTypeFromTsref = function(){\r
-                       var path = this.extPath.split('.');\r
-                       var lastSeg = path.pop();      \r
-                       // attention: there will be recursive calls if necessary\r
-                       var parentValue = this.parent.getValue();\r
-                       if(parentValue){\r
-                               if(tsRef.typeHasProperty(parentValue,lastSeg)){\r
-                                       var type = tsRef.getType(parentValue);\r
-                                       var propertyTypeId = type.properties[lastSeg].value;\r
-                                       return propertyTypeId; \r
-                               }\r
-                       }\r
-                       return '';\r
-               }\r
-\r
-               /**\r
-                * Will look in the external ts-tree (static templates, templates on other pages) \r
-                * if there is a value or childproperties assigned to the current node.     \r
-                * The method uses the extPath of the current node to navigate to the corresponding\r
-                * node in the external tree\r
-                **/          \r
-               this.getExtNode = function(){\r
-                       var extTree = extTsObjTree;\r
-                       var path = this.extPath.split('.');\r
-                       var pathSeg;\r
-                       if (path == "") return extTree;\r
-                       var i;\r
-                       for(i=0;i<path.length;i++){\r
-                               pathSeg = path[i];\r
-                               if(extTree.c == null || extTree.c[pathSeg] == null) {\r
-                                       return null;\r
-                               }\r
-                               extTree = extTree.c[pathSeg];\r
-                       }\r
-                       return extTree;\r
-               }\r
-\r
-       }\r
-\r
-       // the top level treenode\r
-       var tsTree = new TreeNode("_L_");\r
-       var currentLine = "";\r
-\r
-\r
-       /** \r
-        * build Tree of TsObjects from beginning of editor to actual cursorPos\r
-        * and store it in tsTree.\r
-        * also store string from cursor position to the beginning of the line in currentLine\r
-        * and return the reference to the last path before the cursor position in currentTsTreeNode\r
-        * @param startNode DOM Node containing the first word in the editor\r
-        * @param cursorNode DOM Node containing the word at cursor position       \r
-        * @return currentTsTreeNode   \r
-        */\r
-       this.buildTsObjTree = function(startNode, cursorNode){\r
-               return buildTsObjTree(startNode, cursorNode);\r
-       }\r
-       function buildTsObjTree(startNode, cursorNode) {\r
-               var currentNode = startNode;\r
-               var line = "";\r
-               tsTree = new TreeNode("");\r
-               tsTree.value = "TLO";  \r
-               function Stack() {\r
-               }\r
-\r
-               Stack.prototype = new Array();\r
-\r
-               Stack.prototype.lastElementEquals = function(str) {\r
-                       if (this.length > 0 && this[this.length-1]==str) {\r
-                               return true;\r
-                       }else { \r
-                               return false;\r
-                       }\r
-               }\r
-\r
-               Stack.prototype.popIfLastElementEquals = function(str) {\r
-                       if(this.length > 0 && this[this.length-1]==str) {\r
-                               this.pop();\r
-                               return true;\r
-                       }else {\r
-                               return false;\r
-                       }\r
-               }\r
-\r
-               var stack = new Stack();\r
-               var prefixes = new Array();\r
-               var ignoreLine = false;\r
-               //var cursorReached = false;\r
-               var insideCondition = false;    \r
-\r
-               while(true) {\r
-                       if(currentNode.hasChildNodes() && currentNode.firstChild.nodeType==3 && currentNode.currentText.length>0) {\r
-                               node = currentNode.currentText;\r
-                               if (node[0] == '#')stack.push('#');\r
-                               if (node    == '(')stack.push('(');\r
-                               if (node[0] == '/' && node[1]=='*')stack.push('/*');\r
-                               if (node    == '{') {\r
-                                       stack.push('{');\r
-                                       prefixes.push(line);\r
-                                       ignoreLine = true;\r
-                               }\r
-                               // TODO: conditions  \r
-                               // if condition starts -> ignore everything until end of condition          \r
-                               if (node.search(/^\s*\[.*\]/) != -1  \r
-                                               && line.search(/\S/) == -1\r
-                                               && node.search(/^\s*\[(global|end|GLOBAL|END)\]/) == -1  \r
-                                               && !stack.lastElementEquals('#')\r
-                                               && !stack.lastElementEquals('/*')\r
-                                               && !stack.lastElementEquals('{')\r
-                                               && !stack.lastElementEquals('(')\r
-                               ) {\r
-                                       insideCondition = true;\r
-                                       ignoreLine = true;\r
-                               }\r
-\r
-                               // if end of condition reached \r
-                               if (line.search(/\S/) == -1\r
-                                               && !stack.lastElementEquals('#')\r
-                                               && !stack.lastElementEquals('/*')\r
-                                               && !stack.lastElementEquals('(')\r
-                                               && (\r
-                                                               (node.search(/^\s*\[(global|end|GLOBAL|END)\]/) != -1\r
-                                                                               && !stack.lastElementEquals('{'))  \r
-                                                                               || (node.search(/^\s*\[(global|GLOBAL)\]/) != -1)\r
-                                               )\r
-                               ) {\r
-                                       insideCondition = false;\r
-                                       ignoreLine = true;\r
-                               }\r
-\r
-\r
-\r
-                               if (node == ')') {\r
-                                       stack.popIfLastElementEquals('(');\r
-                               }\r
-                               if (node[0] == '*' && node[1]=='/') {\r
-                                       stack.popIfLastElementEquals('/*');\r
-                                       ignoreLine = true;\r
-                               }\r
-                               if (node    == '}') {\r
-                                       stack.popIfLastElementEquals('{');\r
-                                       if (prefixes.length>0) prefixes.pop();\r
-                                       ignoreLine = true;\r
-                               }                   \r
-                               if (!stack.lastElementEquals('#')) {\r
-                                       line += node;\r
-                               }\r
-\r
-                       } else {\r
-                               //end of line? divide line into path and text and try to build a node\r
-                               if (currentNode.tagName == "BR") {\r
-                                       // ignore comments, ...\r
-                                       if(!stack.lastElementEquals('/*') && !stack.lastElementEquals('(') && !ignoreLine && !insideCondition) {           \r
-                                               line = line.replace(/\s/g,"");\r
-                                               // check if there is any operator in this line\r
-                                               var op = getOperator(line);\r
-                                               if (op != -1) {\r
-                                                       // figure out the position of the operator\r
-                                                       var pos = line.indexOf(op);\r
-                                                       // the target objectpath should be left to the operator  \r
-                                                       var path = line.substring(0,pos);\r
-                                                       // if we are in between curly brackets: add prefixes to object path\r
-                                                       if (prefixes.length>0) {\r
-                                                               path = prefixes.join('.') + '.' + path;\r
-                                                       }\r
-                                                       // the type or value should be right to the operator\r
-                                                       var str = line.substring(pos+op.length, line.length);\r
-                                                       path = path.replace(/\s/g,"");\r
-                                                       str = str.replace(/\s/g,"");\r
-                                                       switch(op) {  // set a value or create a new object                \r
-                                                       case '=':\r
-                                                               setTreeNodeValue(path, str);\r
-                                                               break;\r
-                                                       case '=<': // reference to another object in the tree\r
-                                                                // resolve relative path               \r
-                                                               if ( prefixes.length > 0 \r
-                                                                               && str.substr(0, 1) == '.' ) {\r
-                                                                       str = prefixes.join('.') + str;\r
-                                                               }\r
-                                                               setReference(path, str);\r
-                                                               break;\r
-                                                       case '<': // copy from another object in the tree\r
-                                                               if ( prefixes.length > 0 \r
-                                                                               && str.substr(0, 1) == '.' ) {\r
-                                                                       str = prefixes.join('.') + str;\r
-                                                               }\r
-                                                               setCopy(path, str);\r
-                                                               break;\r
-                                                       case '>': // delete object value and properties\r
-                                                               deleteTreeNodeValue(path);  \r
-                                                               break;\r
-                                                       case ':=': // function operator\r
-                                                               // TODO: function-operator\r
-                                                               break;                                                            \r
-                                                       } \r
-                                               }\r
-                                       }\r
-                                       stack.popIfLastElementEquals('#');\r
-                                       ignoreLine = false;\r
-                                       line = "";\r
-                               }\r
-                       }\r
-                       // todo: fix problem: occurs if you type something, delete it with backspace and press ctrl+space\r
-                       // hack: cursor.start does not always return the node on the same level- so we have to check both\r
-                       // if (currentNode == cursor.start.node.parentNode || currentNode == cursor.start.node.previousSibling){\r
-                       // another problem: also the filter is calculated wrong, due to the buggy cursor, so this hack is useless\r
-                       if (currentNode == cursorNode) {\r
-                               break;\r
-                       } else {\r
-                               currentNode = currentNode.nextSibling;\r
-                       }\r
-               } \r
-               // when node at cursorPos is reached:\r
-               // save currentLine, currentTsTreeNode and filter if necessary\r
-               // if there is a reference or copy operator ('<' or '=<') \r
-               // return the treeNode of the path right to the operator, \r
-               // else try to build a path from the whole line\r
-\r
-               if(!stack.lastElementEquals('/*') && !stack.lastElementEquals('(') && !ignoreLine) {  \r
-                       currentLine = line;\r
-                       var i = line.indexOf('<');\r
-                       if (i != -1) {\r
-                               var path = line.substring(i+1, line.length);\r
-                               path = path.replace(/\s/g,"");\r
-                               if ( prefixes.length > 0 && path.substr(0,1) == '.') {\r
-                                       path = prefixes.join('.') + path;\r
-                               }\r
-                       } else {\r
-                               var path = line;\r
-                               if (prefixes.length>0) {\r
-                                       path = prefixes.join('.') + '.' + path;\r
-                                       path = path.replace(/\s/g,"");\r
-                               }\r
-                       }\r
-                       var lastDot = path.lastIndexOf(".");\r
-                       path = path.substring(0, lastDot);\r
-               }\r
-               return getTreeNode(path);\r
-       }  \r
-\r
-\r
-       /**\r
-        * check if there is an operator in the line and return it\r
-        * if there is none, return -1\r
-        */\r
-       function getOperator(line) {\r
-               var operators = new Array(":=", "=<", "<", ">", "=");\r
-               for (var i=0; i<operators.length; i++) {\r
-                       var op = operators[i];\r
-                       if (line.indexOf(op) != -1) {\r
-                               // check if there is some HTML in this line (simple check, however it's the only difference between a reference operator and HTML)\r
-                               // we do this check only in case of the two operators "=<" and "<" since the delete operator would trigger our "HTML-finder"\r
-                               if((op == "=<" || op == "<") && line.indexOf(">") != -1){\r
-                                       // if there is a ">" in the line suppose there's some HTML\r
-                                       return "=";\r
-                               }\r
-                               return op;\r
-                       }\r
-               }\r
-               return -1; \r
-       }\r
-\r
-\r
-       /**\r
-        * iterates through the object tree, and creates treenodes\r
-        * along the path, if necessary\r
-        */    \r
-       function getTreeNode(path){\r
-               var aPath = path.replace(/\s/g,"").split(".");\r
-               if (aPath == "") {\r
-                       return tsTree;\r
-               }\r
-               var subTree = tsTree.childNodes;\r
-               var pathSeg;\r
-               var parent = tsTree;\r
-               var currentNodePath = '';\r
-               // step through the path from left to right\r
-               for(i=0;i<aPath.length;i++){\r
-                       pathSeg = aPath[i];\r
-                       // if there isn't already a treenode\r
-                       if(subTree[pathSeg] == null || subTree[pathSeg].childNodes == null){ // if this subpath is not defined in the code\r
-                               // create a new treenode\r
-                               subTree[pathSeg] = new TreeNode(pathSeg);\r
-                               subTree[pathSeg].parent = parent;\r
-                               //subTree[pathSeg].extTsObjTree = extTsObjTree;\r
-                               // the extPath has to be set, so the TreeNode can retrieve the respecting node in the external templates\r
-                               var extPath = parent.extPath;\r
-                               if(extPath) {\r
-                                       extPath += '.';\r
-                               }\r
-                               extPath += pathSeg;\r
-                               subTree[pathSeg].extPath = extPath;\r
-                       } \r
-                       if(i==aPath.length-1){\r
-                               return subTree[pathSeg];\r
-                       }\r
-                       parent = subTree[pathSeg];\r
-                       subTree = subTree[pathSeg].childNodes;\r
-               }\r
-       }\r
-\r
-\r
-       /**\r
-        * navigates to the respecting treenode, \r
-        * create nodes in the path, if necessary, and sets the value\r
-        */        \r
-       function setTreeNodeValue(path, value) {\r
-               var treeNode = getTreeNode(path);\r
-               // if we are inside a GIFBUILDER Object\r
-               if(treeNode.parent != null && treeNode.parent.value == "GIFBUILDER" && value == "TEXT") {\r
-                       value = "IMGTEXT";\r
-               }\r
-               // just override if it is a real objecttype\r
-               if (tsRef.isType(value)) {\r
-                       treeNode.value = value; \r
-               }\r
-       }\r
-\r
-\r
-       /**\r
-        * navigates to the respecting treenode,\r
-        * creates nodes if necessary, empties the value and childNodes-Array\r
-        */\r
-       function deleteTreeNodeValue(path) {\r
-               var treeNode = getTreeNode(path);\r
-               // currently the node is not deleted really, its just not displayed cause value == null\r
-               // deleting it would be a cleaner solution\r
-               treeNode.value = null;\r
-               treeNode.childNodes = null;\r
-               treeNode = null;    \r
-       }         \r
-\r
-\r
-       /**\r
-        * copies a reference of the treeNode specified by path2 \r
-        * to the location specified by path1\r
-        */     \r
-       function setReference(path1, path2) {\r
-               path1arr = path1.split('.');\r
-               lastNodeName = path1arr[path1arr.length-1];\r
-               var treeNode1 = getTreeNode(path1);\r
-               var treeNode2 = getTreeNode(path2);\r
-               if(treeNode1.parent != null) {\r
-                       treeNode1.parent.childNodes[lastNodeName] = treeNode2;\r
-               } else {\r
-                       tsTree.childNodes[lastNodeName] = treeNode2;\r
-               }\r
-       }\r
-\r
-       /**\r
-        * copies a treeNode specified by path2 \r
-        * to the location specified by path1\r
-        */ \r
-       function setCopy(path1,path2){\r
-               this.clone = function(myObj) {\r
-                       if (myObj == null || typeof(myObj) != 'object') {\r
-                               return myObj;\r
-                       }\r
-\r
-                       var myNewObj = new Object();\r
-\r
-                       for(var i in myObj){\r
-                               // disable recursive cloning for parent object -> copy by reference\r
-                               if(i != "parent"){\r
-                                       if (typeof myObj[i] == 'object') {\r
-                                               myNewObj[i] = clone(myObj[i]);\r
-                                       } else {\r
-                                               myNewObj[i] = myObj[i];\r
-                                       }\r
-                               } else {\r
-                                       myNewObj.parent = myObj.parent;\r
-                               }\r
-                       }\r
-                       return myNewObj;\r
-               } \r
-               var path1arr = path1.split('.');\r
-               var lastNodeName = path1arr[path1arr.length-1];\r
-               var treeNode1 = getTreeNode(path1);\r
-               var treeNode2 = getTreeNode(path2);\r
-\r
-               if(treeNode1.parent != null) {\r
-                       treeNode1.parent.childNodes[lastNodeName] = this.clone(treeNode2);\r
-                       //treeNode1.parent.childNodes[lastNodeName].extTsObjTree = extTsObjTree;\r
-               } else {\r
-                       tsTree.childNodes[lastNodeName] = this.clone(treeNode2);\r
-                       //tsTree[lastNodeName].extTsObjTree = extTsObjTree;\r
-               }\r
-\r
-       }\r
-}\r
+/***************************************************************
+* Copyright notice
+*
+* (c) 2008-2009 Stephan Petzl <spetzl@gmx.at> and Christian Kartnig <office@hahnepeter.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!
+***************************************************************/
+/**
+ * @fileoverview contains the TsParser class and the TreeNode helper class
+ */
+
+/**
+ * Construct a new TsParser object.
+ * @class This class takes care of the parsing and builds the codeTree
+ *
+ * @constructor
+ * @param tsRef typoscript reference tree
+ * @param extTsObjTree codeTree for all typoscript templates
+ *                      excluding the current one.
+ * @return A new TsParser instance
+ */
+var TsParser = function(tsRef,extTsObjTree){
+
+       /**
+        * @class data structure for the nodes of the code tree
+        * mainly used for retrieving the externals templates childnodes
+        * @constructor
+        * @param {String} name
+        */
+       function TreeNode(nodeName){
+               this.name = nodeName;
+               //this.tsObjTree = tsObjTree;
+               this.childNodes = new Array();
+               //has to be set, so the node can retrieve the childnodes of the external templates 
+               this.extPath = "";
+               // the TS-objecttype ID (TSREF) 
+               this.value = "";
+               //this.extTsObjTree = null;
+               // current template or external template
+               this.isExternal = false;
+
+               /**
+                * returns local properties and the properties of the external templates
+                * @returns {Array} ChildNodes
+                */           
+               this.getChildNodes = function(){  
+                       var node = this.getExtNode();
+                       if(node){
+                               for(key in node.c){
+                                       var tn = new TreeNode(key,this.tsObjTree);
+                                       tn.global = true;
+                                       tn.value = (node.c[key].v)? node.c[key].v : "";
+                                       tn.isExternal = true;
+                                       this.childNodes[key] = tn;
+                               }
+                       }
+                       return this.childNodes;
+               }
+
+               this.getValue = function(){
+                       if(this.value) {
+                               return this.value;
+                       } else {
+                               var node = this.getExtNode();
+                               if(node && node.v) {
+                                       return node.v;
+                               } else {
+                                       var type = this.getNodeTypeFromTsref();
+                                       if(type)
+                                               return type;
+                                       else
+                                               return '';
+                               }
+                       }
+               }
+
+               /**
+                * This method will try to resolve the properties recursively from right
+                * to left. If the node's value property is not set, it will look for the
+                * value of its parent node, and if there is a matching childProperty 
+                * (according to the TSREF) it will return the childProperties value. 
+                * If there is no value in the parent node it will go one step further 
+                * and look into the parent node of the parent node,...      
+                **/              
+               this.getNodeTypeFromTsref = function(){
+                       var path = this.extPath.split('.');
+                       var lastSeg = path.pop();      
+                       // attention: there will be recursive calls if necessary
+                       var parentValue = this.parent.getValue();
+                       if(parentValue){
+                               if(tsRef.typeHasProperty(parentValue,lastSeg)){
+                                       var type = tsRef.getType(parentValue);
+                                       var propertyTypeId = type.properties[lastSeg].value;
+                                       return propertyTypeId; 
+                               }
+                       }
+                       return '';
+               }
+
+               /**
+                * Will look in the external ts-tree (static templates, templates on other pages) 
+                * if there is a value or childproperties assigned to the current node.     
+                * The method uses the extPath of the current node to navigate to the corresponding
+                * node in the external tree
+                **/          
+               this.getExtNode = function(){
+                       var extTree = extTsObjTree;
+                       var path = this.extPath.split('.');
+                       var pathSeg;
+                       if (path == "") return extTree;
+                       var i;
+                       for(i=0;i<path.length;i++){
+                               pathSeg = path[i];
+                               if(extTree.c == null || extTree.c[pathSeg] == null) {
+                                       return null;
+                               }
+                               extTree = extTree.c[pathSeg];
+                       }
+                       return extTree;
+               }
+
+       }
+
+       // the top level treenode
+       var tsTree = new TreeNode("_L_");
+       var currentLine = "";
+
+
+       /** 
+        * build Tree of TsObjects from beginning of editor to actual cursorPos
+        * and store it in tsTree.
+        * also store string from cursor position to the beginning of the line in currentLine
+        * and return the reference to the last path before the cursor position in currentTsTreeNode
+        * @param startNode DOM Node containing the first word in the editor
+        * @param cursorNode DOM Node containing the word at cursor position       
+        * @return currentTsTreeNode   
+        */
+       this.buildTsObjTree = function(startNode, cursorNode){
+               return buildTsObjTree(startNode, cursorNode);
+       }
+       function buildTsObjTree(startNode, cursorNode) {
+               var currentNode = startNode;
+               var line = "";
+               tsTree = new TreeNode("");
+               tsTree.value = "TLO";  
+               function Stack() {
+               }
+
+               Stack.prototype = new Array();
+
+               Stack.prototype.lastElementEquals = function(str) {
+                       if (this.length > 0 && this[this.length-1]==str) {
+                               return true;
+                       }else { 
+                               return false;
+                       }
+               }
+
+               Stack.prototype.popIfLastElementEquals = function(str) {
+                       if(this.length > 0 && this[this.length-1]==str) {
+                               this.pop();
+                               return true;
+                       }else {
+                               return false;
+                       }
+               }
+
+               var stack = new Stack();
+               var prefixes = new Array();
+               var ignoreLine = false;
+               //var cursorReached = false;
+               var insideCondition = false;    
+
+               while(true) {
+                       if(currentNode.hasChildNodes() && currentNode.firstChild.nodeType==3 && currentNode.currentText.length>0) {
+                               node = currentNode.currentText;
+                               if (node[0] == '#')stack.push('#');
+                               if (node    == '(')stack.push('(');
+                               if (node[0] == '/' && node[1]=='*')stack.push('/*');
+                               if (node    == '{') {
+                                       stack.push('{');
+                                       prefixes.push(line);
+                                       ignoreLine = true;
+                               }
+                               // TODO: conditions  
+                               // if condition starts -> ignore everything until end of condition          
+                               if (node.search(/^\s*\[.*\]/) != -1  
+                                               && line.search(/\S/) == -1
+                                               && node.search(/^\s*\[(global|end|GLOBAL|END)\]/) == -1  
+                                               && !stack.lastElementEquals('#')
+                                               && !stack.lastElementEquals('/*')
+                                               && !stack.lastElementEquals('{')
+                                               && !stack.lastElementEquals('(')
+                               ) {
+                                       insideCondition = true;
+                                       ignoreLine = true;
+                               }
+
+                               // if end of condition reached 
+                               if (line.search(/\S/) == -1
+                                               && !stack.lastElementEquals('#')
+                                               && !stack.lastElementEquals('/*')
+                                               && !stack.lastElementEquals('(')
+                                               && (
+                                                               (node.search(/^\s*\[(global|end|GLOBAL|END)\]/) != -1
+                                                                               && !stack.lastElementEquals('{'))  
+                                                                               || (node.search(/^\s*\[(global|GLOBAL)\]/) != -1)
+                                               )
+                               ) {
+                                       insideCondition = false;
+                                       ignoreLine = true;
+                               }
+
+
+
+                               if (node == ')') {
+                                       stack.popIfLastElementEquals('(');
+                               }
+                               if (node[0] == '*' && node[1]=='/') {
+                                       stack.popIfLastElementEquals('/*');
+                                       ignoreLine = true;
+                               }
+                               if (node    == '}') {
+                                       stack.popIfLastElementEquals('{');
+                                       if (prefixes.length>0) prefixes.pop();
+                                       ignoreLine = true;
+                               }                   
+                               if (!stack.lastElementEquals('#')) {
+                                       line += node;
+                               }
+
+                       } else {
+                               //end of line? divide line into path and text and try to build a node
+                               if (currentNode.tagName == "BR") {
+                                       // ignore comments, ...
+                                       if(!stack.lastElementEquals('/*') && !stack.lastElementEquals('(') && !ignoreLine && !insideCondition) {           
+                                               line = line.replace(/\s/g,"");
+                                               // check if there is any operator in this line
+                                               var op = getOperator(line);
+                                               if (op != -1) {
+                                                       // figure out the position of the operator
+                                                       var pos = line.indexOf(op);
+                                                       // the target objectpath should be left to the operator  
+                                                       var path = line.substring(0,pos);
+                                                       // if we are in between curly brackets: add prefixes to object path
+                                                       if (prefixes.length>0) {
+                                                               path = prefixes.join('.') + '.' + path;
+                                                       }
+                                                       // the type or value should be right to the operator
+                                                       var str = line.substring(pos+op.length, line.length);
+                                                       path = path.replace(/\s/g,"");
+                                                       str = str.replace(/\s/g,"");
+                                                       switch(op) {  // set a value or create a new object                
+                                                       case '=':
+                                                               setTreeNodeValue(path, str);
+                                                               break;
+                                                       case '=<': // reference to another object in the tree
+                                                                // resolve relative path               
+                                                               if ( prefixes.length > 0 
+                                                                               && str.substr(0, 1) == '.' ) {
+                                                                       str = prefixes.join('.') + str;
+                                                               }
+                                                               setReference(path, str);
+                                                               break;
+                                                       case '<': // copy from another object in the tree
+                                                               if ( prefixes.length > 0 
+                                                                               && str.substr(0, 1) == '.' ) {
+                                                                       str = prefixes.join('.') + str;
+                                                               }
+                                                               setCopy(path, str);
+                                                               break;
+                                                       case '>': // delete object value and properties
+                                                               deleteTreeNodeValue(path);  
+                                                               break;
+                                                       case ':=': // function operator
+                                                               // TODO: function-operator
+                                                               break;                                                            
+                                                       } 
+                                               }
+                                       }
+                                       stack.popIfLastElementEquals('#');
+                                       ignoreLine = false;
+                                       line = "";
+                               }
+                       }
+                       // todo: fix problem: occurs if you type something, delete it with backspace and press ctrl+space
+                       // hack: cursor.start does not always return the node on the same level- so we have to check both
+                       // if (currentNode == cursor.start.node.parentNode || currentNode == cursor.start.node.previousSibling){
+                       // another problem: also the filter is calculated wrong, due to the buggy cursor, so this hack is useless
+                       if (currentNode == cursorNode) {
+                               break;
+                       } else {
+                               currentNode = currentNode.nextSibling;
+                       }
+               } 
+               // when node at cursorPos is reached:
+               // save currentLine, currentTsTreeNode and filter if necessary
+               // if there is a reference or copy operator ('<' or '=<') 
+               // return the treeNode of the path right to the operator, 
+               // else try to build a path from the whole line
+
+               if(!stack.lastElementEquals('/*') && !stack.lastElementEquals('(') && !ignoreLine) {  
+                       currentLine = line;
+                       var i = line.indexOf('<');
+                       if (i != -1) {
+                               var path = line.substring(i+1, line.length);
+                               path = path.replace(/\s/g,"");
+                               if ( prefixes.length > 0 && path.substr(0,1) == '.') {
+                                       path = prefixes.join('.') + path;
+                               }
+                       } else {
+                               var path = line;
+                               if (prefixes.length>0) {
+                                       path = prefixes.join('.') + '.' + path;
+                                       path = path.replace(/\s/g,"");
+                               }
+                       }
+                       var lastDot = path.lastIndexOf(".");
+                       path = path.substring(0, lastDot);
+               }
+               return getTreeNode(path);
+       }  
+
+
+       /**
+        * check if there is an operator in the line and return it
+        * if there is none, return -1
+        */
+       function getOperator(line) {
+               var operators = new Array(":=", "=<", "<", ">", "=");
+               for (var i=0; i<operators.length; i++) {
+                       var op = operators[i];
+                       if (line.indexOf(op) != -1) {
+                               // check if there is some HTML in this line (simple check, however it's the only difference between a reference operator and HTML)
+                               // we do this check only in case of the two operators "=<" and "<" since the delete operator would trigger our "HTML-finder"
+                               if((op == "=<" || op == "<") && line.indexOf(">") != -1){
+                                       // if there is a ">" in the line suppose there's some HTML
+                                       return "=";
+                               }
+                               return op;
+                       }
+               }
+               return -1; 
+       }
+
+
+       /**
+        * iterates through the object tree, and creates treenodes
+        * along the path, if necessary
+        */    
+       function getTreeNode(path){
+               var aPath = path.replace(/\s/g,"").split(".");
+               if (aPath == "") {
+                       return tsTree;
+               }
+               var subTree = tsTree.childNodes;
+               var pathSeg;
+               var parent = tsTree;
+               var currentNodePath = '';
+               // step through the path from left to right
+               for(i=0;i<aPath.length;i++){
+                       pathSeg = aPath[i];
+                       // if there isn't already a treenode
+                       if(subTree[pathSeg] == null || subTree[pathSeg].childNodes == null){ // if this subpath is not defined in the code
+                               // create a new treenode
+                               subTree[pathSeg] = new TreeNode(pathSeg);
+                               subTree[pathSeg].parent = parent;
+                               //subTree[pathSeg].extTsObjTree = extTsObjTree;
+                               // the extPath has to be set, so the TreeNode can retrieve the respecting node in the external templates
+                               var extPath = parent.extPath;
+                               if(extPath) {
+                                       extPath += '.';
+                               }
+                               extPath += pathSeg;
+                               subTree[pathSeg].extPath = extPath;
+                       } 
+                       if(i==aPath.length-1){
+                               return subTree[pathSeg];
+                       }
+                       parent = subTree[pathSeg];
+                       subTree = subTree[pathSeg].childNodes;
+               }
+       }
+
+
+       /**
+        * navigates to the respecting treenode, 
+        * create nodes in the path, if necessary, and sets the value
+        */        
+       function setTreeNodeValue(path, value) {
+               var treeNode = getTreeNode(path);
+               // if we are inside a GIFBUILDER Object
+               if(treeNode.parent != null && treeNode.parent.value == "GIFBUILDER" && value == "TEXT") {
+                       value = "IMGTEXT";
+               }
+               // just override if it is a real objecttype
+               if (tsRef.isType(value)) {
+                       treeNode.value = value; 
+               }
+       }
+
+
+       /**
+        * navigates to the respecting treenode,
+        * creates nodes if necessary, empties the value and childNodes-Array
+        */
+       function deleteTreeNodeValue(path) {
+               var treeNode = getTreeNode(path);
+               // currently the node is not deleted really, its just not displayed cause value == null
+               // deleting it would be a cleaner solution
+               treeNode.value = null;
+               treeNode.childNodes = null;
+               treeNode = null;    
+       }         
+
+
+       /**
+        * copies a reference of the treeNode specified by path2 
+        * to the location specified by path1
+        */     
+       function setReference(path1, path2) {
+               path1arr = path1.split('.');
+               lastNodeName = path1arr[path1arr.length-1];
+               var treeNode1 = getTreeNode(path1);
+               var treeNode2 = getTreeNode(path2);
+               if(treeNode1.parent != null) {
+                       treeNode1.parent.childNodes[lastNodeName] = treeNode2;
+               } else {
+                       tsTree.childNodes[lastNodeName] = treeNode2;
+               }
+       }
+
+       /**
+        * copies a treeNode specified by path2 
+        * to the location specified by path1
+        */ 
+       function setCopy(path1,path2){
+               this.clone = function(myObj) {
+                       if (myObj == null || typeof(myObj) != 'object') {
+                               return myObj;
+                       }
+
+                       var myNewObj = new Object();
+
+                       for(var i in myObj){
+                               // disable recursive cloning for parent object -> copy by reference
+                               if(i != "parent"){
+                                       if (typeof myObj[i] == 'object') {
+                                               myNewObj[i] = clone(myObj[i]);
+                                       } else {
+                                               myNewObj[i] = myObj[i];
+                                       }
+                               } else {
+                                       myNewObj.parent = myObj.parent;
+                               }
+                       }
+                       return myNewObj;
+               } 
+               var path1arr = path1.split('.');
+               var lastNodeName = path1arr[path1arr.length-1];
+               var treeNode1 = getTreeNode(path1);
+               var treeNode2 = getTreeNode(path2);
+
+               if(treeNode1.parent != null) {
+                       treeNode1.parent.childNodes[lastNodeName] = this.clone(treeNode2);
+                       //treeNode1.parent.childNodes[lastNodeName].extTsObjTree = extTsObjTree;
+               } else {
+                       tsTree.childNodes[lastNodeName] = this.clone(treeNode2);
+                       //tsTree[lastNodeName].extTsObjTree = extTsObjTree;
+               }
+
+       }
+}
index 2e4e800..8121b33 100644 (file)
-/***************************************************************\r
-*  Copyright notice\r
-*\r
-*  (c) 2008-2009 Stephan Petzl <spetzl@gmx.at> and Christian Kartnig <office@hahnepeter.de> \r
-*  All rights reserved\r
-*\r
-*  This script is part of the TYPO3 project. The TYPO3 project is\r
-*  free software; you can redistribute it and/or modify\r
-*  it under the terms of the GNU General Public License as published by\r
-*  the Free Software Foundation; either version 2 of the License, or\r
-*  (at your option) any later version.\r
-*\r
-*  The GNU General Public License can be found at\r
-*  http://www.gnu.org/copyleft/gpl.html.\r
-*  A copy is found in the textfile GPL.txt and important notices to the license\r
-*  from the author is found in LICENSE.txt distributed with these scripts.\r
-*\r
-*\r
-*  This script is distributed in the hope that it will be useful,\r
-*  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-*  GNU General Public License for more details.\r
-*\r
-*  This copyright notice MUST APPEAR in all copies of the script!\r
-***************************************************************/\r
-/**\r
- * @fileoverview contains the TsRef class \r
- * and the TsRefProperty and TsRefType helper classes\r
- */ \r
-\r
-/**\r
- * @class Represents a TsRefProperty in the tree\r
- *  \r
- * @constructor\r
- */\r
-var TsRefProperty = function(parentType,name,value) {\r
-       this.parentType = parentType;\r
-       this.name = name;\r
-       this.value = value;\r
-       var descriptionCache = null;\r
-       this.getDescription = function(callBack) {\r
-               if(descriptionCache == null){\r
-                       var urlParameters = '&ajaxID=tx_t3editor_TSrefLoader::getDescription' +\r
-                               '&typeId=' + this.parentType +\r
-                               '&parameterName=' + this.name;\r
-\r
-                       new Ajax.Request(\r
-                               URL_typo3 + 'ajax.php',\r
-                               {\r
-                                       method: 'get',\r
-                                       parameters: urlParameters,\r
-                                       onSuccess: function(transport) {\r
-                                         descriptionCache = transport.responseText;\r
-                                         callBack(transport.responseText);\r
-                                       }\r
-                               }\r
-                       );\r
-               } else {\r
-                       callBack(descriptionCache);\r
-               }\r
-       }\r
-}\r
-\r
-/**\r
- * @class Represents a TsRefType in the tree\r
- *  \r
- * @constructor\r
- */\r
-var TsRefType = function(typeId) {\r
-       this.typeId = typeId;                   \r
-       this.properties = new Array();\r
-\r
-       // todo: types can have descriptions too!\r
-       this.getDescription = function() {\r
-       }\r
-}\r
-\r
-/**\r
- * Construct a new TsRef object.\r
- * @class This class receives the TsRef from the server and represents it as a tree\r
- * also supplies methods for access to treeNodes \r
- *  \r
- * @constructor\r
- * @return A new TsRef instance\r
- */\r
-var TsRef = function() {\r
-       var typeTree = new Array();     \r
-\r
-       var doc;\r
-\r
-       this.loadTsrefAsync = function() {\r
-               var urlParameters = '&ajaxID=tx_t3editor_TSrefLoader::getTypes';\r
-               new Ajax.Request(\r
-                       URL_typo3 + 'ajax.php',\r
-                       {\r
-                               method: 'get',\r
-                               parameters: urlParameters,\r
-                               onSuccess: function(transport) {\r
-                                       doc = eval('('+ transport.responseText +')');\r
-                                       buildTree();\r
-                               }\r
-                       }\r
-               );\r
-       }\r
-\r
-\r
-\r
-       function buildTree() { \r
-         \r
-               typeTree = new Array();\r
-               for (var typeId in doc) {\r
-                 \r
-                       var arr = doc[typeId];\r
-                       typeTree[typeId] = new TsRefType(typeId);\r
-                 \r
-\r
-                       if (arr['extends'] != null) {\r
-                               typeTree[typeId]['extends'] = arr['extends'];\r
-                       }\r
-                       for (propName in arr.properties) {\r
-                               var propType = arr.properties[propName].type;\r
-                               typeTree[typeId].properties[propName] = new TsRefProperty(typeId,propName,propType);\r
-                       }\r
-               }\r
-               for (var typeId in typeTree) {\r
-                       if (typeTree[typeId]['extends'] != null) {\r
-                               //console.log(typeId+" | "+typeTree[typeId].extends+" |");\r
-                               addPropertiesToType(typeTree[typeId], typeTree[typeId]['extends'], 100);\r
-                       }\r
-               }\r
-       }\r
-\r
-\r
-       function addPropertiesToType(addToType,addFromTypeNames,maxRecDepth){\r
-               if(maxRecDepth<0){\r
-                       throw "Maximum recursion depth exceeded while trying to resolve the extends in the TSREF!";\r
-                       return;\r
-               }\r
-               var exts = addFromTypeNames.split(',');\r
-               var i;\r
-               for(i=0;i<exts.length;i++){\r
-                       //"Type 'array' which is used to extend 'undefined', was not found in the TSREF!"\r
-                       if(typeTree[exts[i]]==null){\r
-                               //console.log("Error: Type '"+exts[i]+"' which is used to extend '"+addToType.typeId+"', was not found in the TSREF!");\r
-                       }else{\r
-                               if(typeTree[exts[i]]['extends'] != null){   \r
-                                       addPropertiesToType(typeTree[exts[i]],typeTree[exts[i]]['extends'],maxRecDepth-1);\r
-                               }\r
-                               var properties = typeTree[exts[i]].properties;\r
-                               for(propName in properties){\r
-                                       // only add this property if it was not already added by a supertype (subtypes override supertypes)\r
-                                       if(addToType.properties[propName] == null){\r
-                                               addToType.properties[propName] = properties[propName];\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-\r
-       }\r
-\r
-       this.getPropertiesFromTypeId = function(tId) {\r
-               if (typeTree[tId] != null) {\r
-                       // clone is needed to assure that nothing of the tsref is overwritten by user setup\r
-                       typeTree[tId].properties.clone = function() {\r
-                               var result = new Array();\r
-                               for (key in this) {\r
-                                       result[key] = new TsRefProperty(this[key].parentType,this[key].name,this[key].value);\r
-                               }\r
-                               return result;\r
-                       }        \r
-                       return typeTree[tId].properties;\r
-               } else {\r
-                       return new Array();\r
-               } \r
-       }\r
-\r
-       this.typeHasProperty = function(typeId,propertyName) {\r
-               if (typeTree[typeId] != null && typeTree[typeId].properties[propertyName] != null) {\r
-                       return true;\r
-               } else {\r
-                       return false;\r
-               }\r
-       }\r
-\r
-       this.getType = function(typeId){\r
-               return typeTree[typeId];\r
-       }\r
-       this.isType = function(typeId){\r
-               return (typeTree[typeId] != null);\r
-       }\r
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008-2009 Stephan Petzl <spetzl@gmx.at> and Christian Kartnig <office@hahnepeter.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!
+***************************************************************/
+/**
+ * @fileoverview contains the TsRef class 
+ * and the TsRefProperty and TsRefType helper classes
+ */ 
+
+/**
+ * @class Represents a TsRefProperty in the tree
+ *  
+ * @constructor
+ */
+var TsRefProperty = function(parentType,name,value) {
+       this.parentType = parentType;
+       this.name = name;
+       this.value = value;
+       var descriptionCache = null;
+       this.getDescription = function(callBack) {
+               if(descriptionCache == null){
+                       var urlParameters = '&ajaxID=tx_t3editor_TSrefLoader::getDescription' +
+                               '&typeId=' + this.parentType +
+                               '&parameterName=' + this.name;
+
+                       new Ajax.Request(
+                               URL_typo3 + 'ajax.php',
+                               {
+                                       method: 'get',
+                                       parameters: urlParameters,
+                                       onSuccess: function(transport) {
+                                         descriptionCache = transport.responseText;
+                                         callBack(transport.responseText);
+                                       }
+                               }
+                       );
+               } else {
+                       callBack(descriptionCache);
+               }
+       }
+}
+
+/**
+ * @class Represents a TsRefType in the tree
+ *  
+ * @constructor
+ */
+var TsRefType = function(typeId) {
+       this.typeId = typeId;                   
+       this.properties = new Array();
+
+       // todo: types can have descriptions too!
+       this.getDescription = function() {
+       }
+}
+
+/**
+ * Construct a new TsRef object.
+ * @class This class receives the TsRef from the server and represents it as a tree
+ * also supplies methods for access to treeNodes 
+ *  
+ * @constructor
+ * @return A new TsRef instance
+ */
+var TsRef = function() {
+       var typeTree = new Array();     
+
+       var doc;
+
+       this.loadTsrefAsync = function() {
+               var urlParameters = '&ajaxID=tx_t3editor_TSrefLoader::getTypes';
+               new Ajax.Request(
+                       URL_typo3 + 'ajax.php',
+                       {
+                               method: 'get',
+                               parameters: urlParameters,
+                               onSuccess: function(transport) {
+                                       doc = eval('('+ transport.responseText +')');
+                                       buildTree();
+                               }
+                       }
+               );
+       }
+
+
+
+       function buildTree() { 
+         
+               typeTree = new Array();
+               for (var typeId in doc) {
+                 
+                       var arr = doc[typeId];
+                       typeTree[typeId] = new TsRefType(typeId);
+                 
+
+                       if (arr['extends'] != null) {
+                               typeTree[typeId]['extends'] = arr['extends'];
+                       }
+                       for (propName in arr.properties) {
+                               var propType = arr.properties[propName].type;
+                               typeTree[typeId].properties[propName] = new TsRefProperty(typeId,propName,propType);
+                       }
+               }
+               for (var typeId in typeTree) {
+                       if (typeTree[typeId]['extends'] != null) {
+                               //console.log(typeId+" | "+typeTree[typeId].extends+" |");
+                               addPropertiesToType(typeTree[typeId], typeTree[typeId]['extends'], 100);
+                       }
+               }
+       }
+
+
+       function addPropertiesToType(addToType,addFromTypeNames,maxRecDepth){
+               if(maxRecDepth<0){
+                       throw "Maximum recursion depth exceeded while trying to resolve the extends in the TSREF!";
+                       return;
+               }
+               var exts = addFromTypeNames.split(',');
+               var i;
+               for(i=0;i<exts.length;i++){
+                       //"Type 'array' which is used to extend 'undefined', was not found in the TSREF!"
+                       if(typeTree[exts[i]]==null){
+                               //console.log("Error: Type '"+exts[i]+"' which is used to extend '"+addToType.typeId+"', was not found in the TSREF!");
+                       }else{
+                               if(typeTree[exts[i]]['extends'] != null){   
+                                       addPropertiesToType(typeTree[exts[i]],typeTree[exts[i]]['extends'],maxRecDepth-1);
+                               }
+                               var properties = typeTree[exts[i]].properties;
+                               for(propName in properties){
+                                       // only add this property if it was not already added by a supertype (subtypes override supertypes)
+                                       if(addToType.properties[propName] == null){
+                                               addToType.properties[propName] = properties[propName];
+                                       }
+                               }
+                       }
+               }
+
+       }
+
+       this.getPropertiesFromTypeId = function(tId) {
+               if (typeTree[tId] != null) {
+                       // clone is needed to assure that nothing of the tsref is overwritten by user setup
+                       typeTree[tId].properties.clone = function() {
+                               var result = new Array();
+                               for (key in this) {
+                                       result[key] = new TsRefProperty(this[key].parentType,this[key].name,this[key].value);
+                               }
+                               return result;
+                       }        
+                       return typeTree[tId].properties;
+               } else {
+                       return new Array();
+               } 
+       }
+
+       this.typeHasProperty = function(typeId,propertyName) {
+               if (typeTree[typeId] != null && typeTree[typeId].properties[propertyName] != null) {
+                       return true;
+               } else {
+                       return false;
+               }
+       }
+
+       this.getType = function(typeId){
+               return typeTree[typeId];
+       }
+       this.isType = function(typeId){
+               return (typeTree[typeId] != null);
+       }
 }
\ No newline at end of file
index 5a46865..9be35a9 100644 (file)
@@ -314,7 +314,7 @@ This value has no default value and only if you specify a value for this token w
                        <description><![CDATA[If this value is set, then all relative links in TypoScript are prepended with this string. Used to convert relative paths to absolute paths.
 
 Note: This values is automatically set to the dirname of the index.php script in case simulateStaticDocuments is set to "PATH_INFO".
-If you're working on a server where you have both internal and external access, you might to yourself a favour and set the absRefPrefix to the url and path of you site, eg. http://www.typo3.com/. If you do not, you risk to render pages to cache from the internal network and thereby prefix image-references and links with a non-accesible path from outside.]]></description>
+If you're working on a server where you have both internal and external access, you might to yourself a favour and set the absRefPrefix to the url and path of you site, eg. http://www.typo3.com/. If you do not, you risk to render pages to cache from the internal network and thereby prefix image-references and links with a non-accessible path from outside.]]></description>
                        <default><![CDATA[
 ]]></default>
                </property>