diff --git a/inc/toolbar.php b/inc/toolbar.php
index af1dc8d05163d0eab6d671f00d7f08553ebbbbf9..3188c9ac9c1e284e6824b233750c2c7f942618b8 100644
--- a/inc/toolbar.php
+++ b/inc/toolbar.php
@@ -172,6 +172,9 @@ function toolbar_JSdefines($varname){
                 'icon'   => 'sig.png',
                 'key'    => 'y',
                ),
+
+
+
         ));
     } // end event TOOLBAR_DEFINE default action
     $evt->advise_after();
diff --git a/lib/exe/js.php b/lib/exe/js.php
index 26323e9b002a93f9fce0e91b00749901fd92b57a..7c5ad021cc3b674884f9b8ae94d6c7e959982b1a 100644
--- a/lib/exe/js.php
+++ b/lib/exe/js.php
@@ -51,6 +51,7 @@ function js_out(){
              );
     if($edit){
         if($write){
+            $files[] = DOKU_INC.'lib/scripts/textselection.js';
             $files[] = DOKU_INC.'lib/scripts/toolbar.js';
             $files[] = DOKU_INC.'lib/scripts/edit.js';
         }
diff --git a/lib/scripts/edit.js b/lib/scripts/edit.js
index 34305c53dc96397d059b77b13e30dfd024f89e30..517daa086e2a4014439173da1eb4b5a2ba89ecb2 100644
--- a/lib/scripts/edit.js
+++ b/lib/scripts/edit.js
@@ -125,81 +125,6 @@ function showPicker(pickerid,btn){
     }
 }
 
-/**
- * Create a toolbar
- *
- * @param  string tbid ID of the element where to insert the toolbar
- * @param  string edid ID of the editor textarea
- * @param  array  tb   Associative array defining the buttons
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function initToolbar(tbid,edid,tb){
-    var toolbar = $(tbid);
-    if(!toolbar) return;
-
-    //empty the toolbar area:
-    toolbar.innerHTML='';
-
-    var cnt = tb.length;
-    for(var i=0; i<cnt; i++){
-        // create new button
-        var btn = createToolButton(tb[i]['icon'],
-                               tb[i]['title'],
-                               tb[i]['key']);
-
-        var actionFunc = 'addBtnAction'+tb[i]['type'].charAt(0).toUpperCase()+tb[i]['type'].substring(1);
-        var exists = eval("typeof("+actionFunc+") == 'function'");
-        if(exists)
-        {
-            if(eval(actionFunc+"(btn, tb[i], edid, i)"))
-                toolbar.appendChild(btn);
-        }else{
-            alert('unknown type: '+tb[i]['type']);
-        }
-    } // end for
-}
-
-/**
- * Add button action for format buttons
- *
- * @param  DOMElement btn   Button element to add the action to
- * @param  array      props Associative array of button properties
- * @param  string     edid  ID of the editor textarea
- * @return boolean    If button should be appended
- * @author Gabriel Birke <birke@d-scribe.de>
- */
-function addBtnActionFormat(btn, props, edid)
-{
-    var sample = props['title'];
-    if(props['sample']){ sample = props['sample']; }
-    eval("btn.onclick = function(){insertTags('"+
-        jsEscape(edid)+"','"+
-        jsEscape(props['open'])+"','"+
-        jsEscape(props['close'])+"','"+
-        jsEscape(sample)+
-    "');return false;}");
-
-    return true;
-}
-
-/**
- * Add button action for insert buttons
- *
- * @param  DOMElement btn   Button element to add the action to
- * @param  array      props Associative array of button properties
- * @param  string     edid  ID of the editor textarea
- * @return boolean    If button should be appended
- * @author Gabriel Birke <birke@d-scribe.de>
- */
-function addBtnActionInsert(btn, props, edid)
-{
-    eval("btn.onclick = function(){insertAtCarret('"+
-        jsEscape(edid)+"','"+
-        jsEscape(props['insert'])+
-    "');return false;}");
-    return true;
-}
-
 /**
  * Add button action for signature button
  *
diff --git a/lib/scripts/textselection.js b/lib/scripts/textselection.js
new file mode 100644
index 0000000000000000000000000000000000000000..537e8d3481bb3211f0b4bbd1a4d4897351a2bc2a
--- /dev/null
+++ b/lib/scripts/textselection.js
@@ -0,0 +1,175 @@
+/**
+ * Text selection related functions.
+ */
+
+/**
+ * selection prototype
+ *
+ * Object that capsulates the selection in a textarea. Returned by getSelection.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function selection_class(){
+    this.start     = 0;
+    this.end       = 0;
+    this.obj       = null;
+    this.rangeCopy = null;
+
+    this.getLength = function(){
+        return this.end - this.start;
+    };
+
+    this.getText = function(){
+        if(!this.obj) return '';
+        return this.obj.value.substring(this.start,this.end);
+    }
+}
+
+/**
+ * Get current selection/cursor position in a given textArea
+ *
+ * @link http://groups.drupal.org/node/1210
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @returns object - a selection object
+ */
+function getSelection(textArea) {
+    var sel = new selection_class();
+
+    sel.obj   = textArea;
+    sel.start = textArea.value.length;
+    sel.end   = textArea.value.length;
+
+    textArea.focus();
+    if(document.getSelection) {          // Mozilla et al.
+        sel.start = textArea.selectionStart;
+        sel.end = textArea.selectionEnd;
+    } else if(document.selection) {      // MSIE
+        // The current selection
+        var range = document.selection.createRange();
+        sel.rangeCopy = range.duplicate();
+        // Select all text
+        sel.rangeCopy.moveToElementText(textArea);
+        // Now move 'dummy' end point to end point of original range
+        sel.rangeCopy.setEndPoint( 'EndToEnd', range );
+        // Now we can calculate start and end points
+        sel.start = sel.rangeCopy.text.length - range.text.length;
+        sel.end = sel.start + range.text.length;
+    }
+    return sel;
+}
+
+/**
+ * Set the selection
+ *
+ * You need to get a selection object via getSelection() first, then modify the
+ * start and end properties and pass it back to this function.
+ *
+ * @link http://groups.drupal.org/node/1210
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param object selection - a selection object as returned by getSelection()
+ */
+function setSelection(selection){
+    if(document.getSelection){ // FF
+        // what a pleasure in FF ;)
+        selection.obj.setSelectionRange(selection.start,selection.end);
+    } else if(document.selection) { // IE
+        // count number of newlines in str to work around stupid IE selection bug
+        var countNL = function(str) {
+            var m = str.split("\n");
+            if (!m || !m.length) return 0;
+            return m.length-1;
+        };
+        var fix = countNL(selection.obj.value.substring(0,selection.start));
+
+        selection.rangeCopy.collapse(true);
+        selection.rangeCopy.moveStart('character',selection.start - fix);
+        selection.rangeCopy.moveEnd('character',selection.end - selection.start);
+        selection.rangeCopy.select();
+    }
+}
+
+/**
+ * Inserts the given text at the current cursor position or replaces the current
+ * selection
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @param string text          - the new text to be pasted
+ * @param objct  selecttion    - selection object returned by getSelection
+ * @param int    opts.startofs - number of charcters at the start to skip from new selection
+ * @param int    opts.endofs   - number of charcters at the end to skip from new selection
+ * @param bool   opts.ofs      - set tru if new text should not be selected
+ */
+function pasteText(selection,text,opts){
+    if(!opts) opts = {};
+    // replace the content
+    selection.obj.value =
+        selection.obj.value.substring(0, selection.start) + text +
+        selection.obj.value.substring(selection.end, selection.obj.value.length);
+
+    // set new selection
+    selection.end = selection.start + text.length;
+
+    // modify the new selection if wanted
+    if(opts.startofs) selection.start += opts.startofs;
+    if(opts.endofs)   selection.end   -= opts.endofs;
+
+    // no selection wanted? set cursor to end position
+    if(opts.nosel) selection.start = selection.end;
+
+    setSelection(selection);
+}
+
+
+/**
+ * Format selection
+ *
+ * Apply tagOpen/tagClose to selection in textarea, use sampleText instead
+ * of selection if there is none.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function insertTags(textAreaID, tagOpen, tagClose, sampleText){
+    var txtarea = $(textAreaID);
+
+    var selection = getSelection(txtarea);
+    var text = selection.getText();
+    var opts;
+
+    // don't include trailing space in selection
+    if(text.charAt(text.length - 1) == ' '){
+        selection.end--;
+        text = selection.getText();
+    }
+
+    if(!text){
+        // nothing selected, use the sample text and select it
+        text = sampleText;
+        opts = {
+            startofs: tagOpen.length,
+            endofs: tagClose.length
+        };
+    }else{
+        // place cursor at the end
+        opts = {
+            nosel: true
+        };
+    }
+
+    // surround with tags
+    text = tagOpen + text + tagClose;
+
+    // do it
+    pasteText(selection,text,opts);
+}
+
+/**
+ * Wraps around pasteText() for backward compatibility
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function insertAtCarret(textAreaID, text){
+    var txtarea = $(textAreaID);
+    var selection = getSelection(txtarea);
+    pasteText(selection,text,{nosel: true});
+}
+
diff --git a/lib/scripts/toolbar.js b/lib/scripts/toolbar.js
index f31e12887c0d274a9bc89453134f5fd5f4d68e74..18d2daedee33191f1a78622c4679a6db7f94e1aa 100644
--- a/lib/scripts/toolbar.js
+++ b/lib/scripts/toolbar.js
@@ -1,161 +1,99 @@
 /**
- * selection prototype
+ * Create a toolbar
  *
- * Object that capsulates the selection in a textarea. Returned by getSelection.
+ * @param  string tbid ID of the element where to insert the toolbar
+ * @param  string edid ID of the editor textarea
+ * @param  array  tb   Associative array defining the buttons
+ * @author Andreas Gohr <andi@splitbrain.org>
  */
-function selection_class(){
-    this.start     = 0;
-    this.end       = 0;
-    this.obj       = null;
-    this.rangeCopy = null;
-
-    this.getLength = function(){
-        return this.end - this.start;
-    };
-
-    this.getText = function(){
-        if(!this.obj) return '';
-        return this.obj.value.substring(this.start,this.end);
-    }
-}
+function initToolbar(tbid,edid,tb){
+    var toolbar = $(tbid);
+    if(!toolbar) return;
+
+    //empty the toolbar area:
+    toolbar.innerHTML='';
+
+    var cnt = tb.length;
+    for(var i=0; i<cnt; i++){
+        var actionFunc;
+
+        // create new button
+        var btn = createToolButton(tb[i]['icon'],
+                                   tb[i]['title'],
+                                   tb[i]['key']);
+
+
+        // type is a tb function -> assign it as onclick
+        actionFunc = 'tb_'+tb[i]['type'];
+        if( isFunction(window[actionFunc]) ){
+            addEvent(btn,'click', function(func,btn, props, edid){
+                return function(){
+                    window[func](btn, props, edid);
+                    return false;
+                }
+            }(actionFunc,btn,tb[i],edid) );
+            //above fixes the scope problem as descried at http://www.mennovanslooten.nl/blog/post/62
+            toolbar.appendChild(btn);
+            continue;
+        }
+
+        // type is a init function -> execute it
+        actionFunc = 'addBtnAction'+tb[i]['type'].charAt(0).toUpperCase()+tb[i]['type'].substring(1);
+        if( isFunction(window[actionFunc]) ){
+            if(window[actionFunc](btn, tb[i], edid, i)){
+                toolbar.appendChild(btn);
+            }
+            continue;
+        }
+
+        console.log('unknown toolbar type: '+tb[i]['type']+'  '+actionFunc); //FIXME make alert
+    } // end for
 
-/**
- * Get current selection/cursor position in a given textArea
- *
- * @link http://groups.drupal.org/node/1210
- * @returns object - a selection object
- */
-function getSelection(textArea) {
-    var sel = new selection_class();
-
-    sel.obj   = textArea;
-    sel.start = textArea.value.length;
-    sel.end   = textArea.value.length;
-
-    textArea.focus();
-    if(document.getSelection) {          // Mozilla et al.
-        sel.start = textArea.selectionStart;
-        sel.end = textArea.selectionEnd;
-    } else if(document.selection) {      // MSIE
-        // The current selection
-        var range = document.selection.createRange();
-        sel.rangeCopy = range.duplicate();
-        // Select all text
-        sel.rangeCopy.moveToElementText(textArea);
-        // Now move 'dummy' end point to end point of original range
-        sel.rangeCopy.setEndPoint( 'EndToEnd', range );
-        // Now we can calculate start and end points
-        sel.start = sel.rangeCopy.text.length - range.text.length;
-        sel.end = sel.start + range.text.length;
-    }
-    return sel;
 }
 
 /**
- * Set the selection
+ * Button action for format buttons
  *
- * You need to get a selection object via getSelection() first, then modify the
- * start and end properties and pass it back to this function.
- *
- * @link http://groups.drupal.org/node/1210
- * @param object selection - a selection object as returned by getSelection()
+ * @param  DOMElement btn   Button element to add the action to
+ * @param  array      props Associative array of button properties
+ * @param  string     edid  ID of the editor textarea
+ * @author Gabriel Birke <birke@d-scribe.de>
+ * @author Andreas Gohr <andi@splitbrain.org>
  */
-function setSelection(selection){
-    if(document.getSelection){ // FF
-        // what a pleasure in FF ;)
-        selection.obj.setSelectionRange(selection.start,selection.end);
-    } else if(document.selection) { // IE
-        // count number of newlines in str to work around stupid IE selection bug
-        var countNL = function(str) {
-            var m = str.split("\n");
-            if (!m || !m.length) return 0;
-            return m.length-1;
-        };
-        var fix = countNL(selection.obj.value.substring(0,selection.start));
-
-        selection.rangeCopy.collapse(true);
-        selection.rangeCopy.moveStart('character',selection.start - fix);
-        selection.rangeCopy.moveEnd('character',selection.end - selection.start);
-        selection.rangeCopy.select();
+function tb_format(btn, props, edid) {
+    var sample = props['title'];
+    if(props['sample']){
+        sample = props['sample'];
     }
+    insertTags(edid,
+               fixtxt(props['open']),
+               fixtxt(props['close']),
+               fixtxt(sample));
+    return false;
 }
 
 /**
- * Inserts the given text at the current cursor position or replaces the current
- * selection
+ * Button action for insert buttons
  *
+ * @param  DOMElement btn   Button element to add the action to
+ * @param  array      props Associative array of button properties
+ * @param  string     edid  ID of the editor textarea
+ * @author Gabriel Birke <birke@d-scribe.de>
  * @author Andreas Gohr <andi@splitbrain.org>
- * @param string text          - the new text to be pasted
- * @param objct  selecttion    - selection object returned by getSelection
- * @param int    opts.startofs - number of charcters at the start to skip from new selection
- * @param int    opts.endofs   - number of charcters at the end to skip from new selection
- * @param bool   opts.ofs      - set tru if new text should not be selected
  */
-function pasteText(selection,text,opts){
-    if(!opts) opts = {};
-    // replace the content
-    selection.obj.value =
-        selection.obj.value.substring(0, selection.start) + text +
-        selection.obj.value.substring(selection.end, selection.obj.value.length);
-
-    // set new selection
-    selection.end = selection.start + text.length;
-
-    // modify the new selection if wanted
-    if(opts.startofs) selection.start += opts.startofs;
-    if(opts.endofs)   selection.end   -= opts.endofs;
-
-    // no selection wanted? set cursor to end position
-    if(opts.nosel) selection.start = selection.end;
-
-    setSelection(selection);
+function tb_insert(btn, props, edid) {
+    insertAtCarret(edid,fixtxt(props['insert']));
 }
 
 
-/**
- * Format selection
- *
- * Apply tagOpen/tagClose to selection in textarea, use sampleText instead
- * of selection if there is none.
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function insertTags(textAreaID, tagOpen, tagClose, sampleText){
-    var txtarea = document.getElementById(textAreaID);
-
-    var selection = getSelection(txtarea);
-    var text = selection.getText();
 
-    // don't include trailing space in selection
-    if(text.charAt(text.length - 1) == ' '){
-        selection.end--;
-        text = selection.getText();
-    }
-
-    // nothing selected, use the sample text
-    if(!text) text = sampleText;
-
-    // surround with tags
-    text = tagOpen + text + tagClose;
 
-    // prepare options
-    var opts = {
-        startofs: tagOpen.length,
-        endofs: tagClose.length
-    };
 
-    // do it
-    pasteText(selection,text,opts);
-}
 
 /**
- * Wraps around pasteText() for backward compatibility
- *
- * @author Andreas Gohr <andi@splitbrain.org>
+ * Replaces \n with linebreaks
  */
-function insertAtCarret(textAreaID, text){
-    var txtarea = document.getElementById(textAreaID);
-    var selection = getSelection(txtarea);
-    pasteText(selection,text,{nosel: true});
+function fixtxt(str){
+    return str.replace(/\\n/g,"\n");
 }