From 20d062ca5220daf6606e2b1bcdd73d84eebafa45 Mon Sep 17 00:00:00 2001
From: Andreas Gohr <andi@splitbrain.org>
Date: Sat, 8 Oct 2005 19:54:04 +0200
Subject: [PATCH] first go on unobstrusive javascript, new toolbar

darcs-hash:20051008175404-7ad00-cd640de7660825b19d5e863cc8caf5467d59b055.gz
---
 inc/JSON.php                      | 615 ++++++++++++++++++++++++++++++
 inc/html.php                      |  55 +--
 inc/lang/en/lang.php              |   3 +
 inc/template.php                  |  44 ++-
 inc/toolbar.php                   | 202 ++++++++++
 lib/images/toolbar/bold.png       | Bin 738 -> 479 bytes
 lib/images/toolbar/chars.png      | Bin 0 -> 636 bytes
 lib/images/toolbar/code.png       | Bin 710 -> 0 bytes
 lib/images/toolbar/empty.png      | Bin 516 -> 0 bytes
 lib/images/toolbar/extlink.png    | Bin 885 -> 0 bytes
 lib/images/toolbar/fonth1.png     | Bin 592 -> 0 bytes
 lib/images/toolbar/fonth2.png     | Bin 708 -> 0 bytes
 lib/images/toolbar/fonth3.png     | Bin 681 -> 0 bytes
 lib/images/toolbar/fonth4.png     | Bin 687 -> 0 bytes
 lib/images/toolbar/fonth5.png     | Bin 674 -> 0 bytes
 lib/images/toolbar/h1.png         | Bin 0 -> 429 bytes
 lib/images/toolbar/h2.png         | Bin 0 -> 500 bytes
 lib/images/toolbar/h3.png         | Bin 0 -> 501 bytes
 lib/images/toolbar/h4.png         | Bin 0 -> 461 bytes
 lib/images/toolbar/h5.png         | Bin 0 -> 478 bytes
 lib/images/toolbar/hr.png         | Bin 0 -> 372 bytes
 lib/images/toolbar/image.png      | Bin 1010 -> 680 bytes
 lib/images/toolbar/italic.png     | Bin 676 -> 363 bytes
 lib/images/toolbar/link.png       | Bin 842 -> 574 bytes
 lib/images/toolbar/linkextern.png | Bin 0 -> 1138 bytes
 lib/images/toolbar/list.png       | Bin 582 -> 0 bytes
 lib/images/toolbar/list_ul.png    | Bin 560 -> 0 bytes
 lib/images/toolbar/mono.png       | Bin 0 -> 426 bytes
 lib/images/toolbar/ol.png         | Bin 0 -> 435 bytes
 lib/images/toolbar/rule.png       | Bin 565 -> 0 bytes
 lib/images/toolbar/sig.png        | Bin 699 -> 606 bytes
 lib/images/toolbar/smiley.png     | Bin 0 -> 860 bytes
 lib/images/toolbar/spellcheck.png | Bin 1076 -> 738 bytes
 lib/images/toolbar/strike.png     | Bin 739 -> 450 bytes
 lib/images/toolbar/ul.png         | Bin 0 -> 409 bytes
 lib/images/toolbar/underline.png  | Bin 743 -> 405 bytes
 lib/scripts/edit.js               | 308 +++++++++++++++
 lib/scripts/script.js             | 281 ++++++--------
 lib/scripts/spellcheck.js         | 125 +++---
 lib/tpl/default/design.css        |  24 ++
 40 files changed, 1369 insertions(+), 288 deletions(-)
 create mode 100644 inc/JSON.php
 create mode 100644 inc/toolbar.php
 create mode 100644 lib/images/toolbar/chars.png
 delete mode 100644 lib/images/toolbar/code.png
 delete mode 100644 lib/images/toolbar/empty.png
 delete mode 100644 lib/images/toolbar/extlink.png
 delete mode 100644 lib/images/toolbar/fonth1.png
 delete mode 100644 lib/images/toolbar/fonth2.png
 delete mode 100644 lib/images/toolbar/fonth3.png
 delete mode 100644 lib/images/toolbar/fonth4.png
 delete mode 100644 lib/images/toolbar/fonth5.png
 create mode 100644 lib/images/toolbar/h1.png
 create mode 100644 lib/images/toolbar/h2.png
 create mode 100644 lib/images/toolbar/h3.png
 create mode 100644 lib/images/toolbar/h4.png
 create mode 100644 lib/images/toolbar/h5.png
 create mode 100644 lib/images/toolbar/hr.png
 create mode 100644 lib/images/toolbar/linkextern.png
 delete mode 100644 lib/images/toolbar/list.png
 delete mode 100644 lib/images/toolbar/list_ul.png
 create mode 100644 lib/images/toolbar/mono.png
 create mode 100644 lib/images/toolbar/ol.png
 delete mode 100644 lib/images/toolbar/rule.png
 create mode 100644 lib/images/toolbar/smiley.png
 create mode 100644 lib/images/toolbar/ul.png
 create mode 100644 lib/scripts/edit.js

diff --git a/inc/JSON.php b/inc/JSON.php
new file mode 100644
index 000000000..6345743fc
--- /dev/null
+++ b/inc/JSON.php
@@ -0,0 +1,615 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/** 
+ * Converts to and from JSON format.
+ * 
+ * JSON (JavaScript Object Notation) is a lightweight data-interchange
+ * format. It is easy for humans to read and write. It is easy for machines
+ * to parse and generate. It is based on a subset of the JavaScript
+ * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
+ * This feature can also be found in  Python. JSON is a text format that is
+ * completely language independent but uses conventions that are familiar
+ * to programmers of the C-family of languages, including C, C++, C#, Java,
+ * JavaScript, Perl, TCL, and many others. These properties make JSON an
+ * ideal data-interchange language.
+ * 
+ * This package provides a simple encoder and decoder for JSON notation. It
+ * is intended for use with client-side Javascript applications that make
+ * use of HTTPRequest to perform server communication functions - data can
+ * be encoded into JSON notation for use in a client-side javascript, or
+ * decoded from incoming Javascript requests. JSON format is native to
+ * Javascript, and can be directly eval()'ed with no further parsing
+ * overhead
+ *
+ * All strings should be in ASCII or UTF-8 format!
+ *
+ * PHP versions 4 and 5
+ *
+ * LICENSE: Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met: Redistributions of source code must retain the
+ * above copyright notice, this list of conditions and the following
+ * disclaimer. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * 
+ * @category   
+ * @package    
+ * @author      Michal Migurski <mike-json@teczno.com>
+ * @author      Matt Knapp <mdknapp[at]gmail[dot]com>
+ * @author      Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
+ * @copyright   2005 Michal Migurski
+ * @license     http://www.freebsd.org/copyright/freebsd-license.html
+ * @link        http://pear.php.net/pepr/pepr-proposal-show.php?id=198
+ */
+
+/**
+ * Marker constant for JSON::decode(), used to flag stack state
+ */
+define('JSON_SLICE',   1);
+
+/**
+ * Marker constant for JSON::decode(), used to flag stack state
+ */
+define('JSON_IN_STR',  2);
+
+/**
+ * Marker constant for JSON::decode(), used to flag stack state
+ */
+define('JSON_IN_ARR',  4);
+
+/**
+ * Marker constant for JSON::decode(), used to flag stack state
+ */
+define('JSON_IN_OBJ',  8);
+
+/**
+ * Marker constant for JSON::decode(), used to flag stack state
+ */
+define('JSON_IN_CMT', 16);
+
+/**
+ * Behavior switch for JSON::decode()
+ */
+define('JSON_LOOSE_TYPE', 10);
+
+/**
+ * Behavior switch for JSON::decode()
+ */
+define('JSON_STRICT_TYPE', 11);
+
+/** 
+ * Converts to and from JSON format.
+ *
+ * @category   
+ * @package    
+ * @author     Michal Migurski <mike-json@teczno.com>
+ * @author     Matt Knapp <mdknapp[at]gmail[dot]com>
+ * @author     Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
+ * @copyright  2005 Michal Migurski
+ * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
+ * @version    
+ * @link       
+ * @see        
+ * @since      
+ * @deprecated 
+ */
+class JSON
+{
+   /**
+    * constructs a new JSON instance
+    *
+    * @param    int     $use    object behavior: when encoding or decoding,
+    *                           be loose or strict about object/array usage
+    *
+    *                           possible values:
+    *                              JSON_STRICT_TYPE - strict typing, default
+    *                                                 "{...}" syntax creates objects in decode.
+    *                               JSON_LOOSE_TYPE - loose typing
+    *                                                 "{...}" syntax creates associative arrays in decode.
+    */
+    function JSON($use=JSON_STRICT_TYPE)
+    {
+        $this->use = $use;
+    }
+
+   /**
+    * encodes an arbitrary variable into JSON format
+    *
+    * @param    mixed   $var    any number, boolean, string, array, or object to be encoded.
+    *                           see argument 1 to JSON() above for array-parsing behavior.
+    *                           if var is a strng, note that encode() always expects it
+    *                           to be in ASCII or UTF-8 format!
+    *
+    * @return   string  JSON string representation of input var
+    * @access   public
+    */
+    function encode($var)
+    {
+        switch (gettype($var)) {
+            case 'boolean':
+                return $var ? 'true' : 'false';
+            
+            case 'NULL':
+                return 'null';
+            
+            case 'integer':
+                return sprintf('%d', $var);
+                
+            case 'double':
+            case 'float':
+                return sprintf('%f', $var);
+                
+            case 'string':
+                // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
+                $ascii = '';
+                $strlen_var = strlen($var);
+
+               /*
+                * Iterate over every character in the string,
+                * escaping with a slash or encoding to UTF-8 where necessary
+                */
+                for ($c = 0; $c < $strlen_var; ++$c) {
+                    
+                    $ord_var_c = ord($var{$c});
+                    
+                    switch ($ord_var_c) {
+                        case 0x08:  $ascii .= '\b';  break;
+                        case 0x09:  $ascii .= '\t';  break;
+                        case 0x0A:  $ascii .= '\n';  break;
+                        case 0x0C:  $ascii .= '\f';  break;
+                        case 0x0D:  $ascii .= '\r';  break;
+
+                        case 0x22:
+                        case 0x2F:
+                        case 0x5C:
+                            // double quote, slash, slosh
+                            $ascii .= '\\'.$var{$c};
+                            break;
+                            
+                        case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
+                            // characters U-00000000 - U-0000007F (same as ASCII)
+                            $ascii .= $var{$c};
+                            break;
+                        
+                        case (($ord_var_c & 0xE0) == 0xC0):
+                            // characters U-00000080 - U-000007FF, mask 110XXXXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c, ord($var{$c+1}));
+                            $c+=1;
+                            $utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+    
+                        case (($ord_var_c & 0xF0) == 0xE0):
+                            // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c+1}),
+                                         ord($var{$c+2}));
+                            $c+=2;
+                            $utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+    
+                        case (($ord_var_c & 0xF8) == 0xF0):
+                            // characters U-00010000 - U-001FFFFF, mask 11110XXX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c+1}),
+                                         ord($var{$c+2}),
+                                         ord($var{$c+3}));
+                            $c+=3;
+                            $utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+    
+                        case (($ord_var_c & 0xFC) == 0xF8):
+                            // characters U-00200000 - U-03FFFFFF, mask 111110XX
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c+1}),
+                                         ord($var{$c+2}),
+                                         ord($var{$c+3}),
+                                         ord($var{$c+4}));
+                            $c+=4;
+                            $utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+    
+                        case (($ord_var_c & 0xFE) == 0xFC):
+                            // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                            $char = pack('C*', $ord_var_c,
+                                         ord($var{$c+1}),
+                                         ord($var{$c+2}),
+                                         ord($var{$c+3}),
+                                         ord($var{$c+4}),
+                                         ord($var{$c+5}));
+                            $c+=5;
+                            $utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
+                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                            break;
+                    }
+                }
+                
+                return '"'.$ascii.'"';
+                
+            case 'array':
+               /*
+                * As per JSON spec if any array key is not an integer
+                * we must treat the the whole array as an object. We
+                * also try to catch a sparsely populated associative
+                * array with numeric keys here because some JS engines
+                * will create an array with empty indexes up to
+                * max_index which can cause memory issues and because
+                * the keys, which may be relevant, will be remapped
+                * otherwise.
+                * 
+                * As per the ECMA and JSON specification an object may
+                * have any string as a property. Unfortunately due to
+                * a hole in the ECMA specification if the key is a
+                * ECMA reserved word or starts with a digit the
+                * parameter is only accessible using ECMAScript's
+                * bracket notation.
+                */
+                
+                // treat as a JSON object  
+                if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
+                    return sprintf('{%s}', join(',', array_map(array($this, 'name_value'),
+                                                               array_keys($var),
+                                                               array_values($var))));
+                }
+
+                // treat it like a regular array
+                return sprintf('[%s]', join(',', array_map(array($this, 'encode'), $var)));
+                
+            case 'object':
+                $vars = get_object_vars($var);
+                return sprintf('{%s}', join(',', array_map(array($this, 'name_value'),
+                                                           array_keys($vars),
+                                                           array_values($vars))));                    
+
+            default:
+                return '';
+        }
+    }
+    
+   /**
+    * encodes an arbitrary variable into JSON format, alias for encode()
+    */
+    function enc($var)
+    {
+        return $this->encode($var);
+    }
+    
+   /** function name_value
+    * array-walking function for use in generating JSON-formatted name-value pairs
+    *
+    * @param    string  $name   name of key to use
+    * @param    mixed   $value  reference to an array element to be encoded
+    *
+    * @return   string  JSON-formatted name-value pair, like '"name":value'
+    * @access   private
+    */
+    function name_value($name, $value)
+    {
+        return (sprintf("%s:%s", $this->encode(strval($name)), $this->encode($value)));
+    }        
+
+   /**
+    * reduce a string by removing leading and trailing comments and whitespace
+    *
+    * @param    $str    string      string value to strip of comments and whitespace
+    *
+    * @return   string  string value stripped of comments and whitespace
+    * @access   private
+    */
+    function reduce_string($str)
+    {
+        $str = preg_replace(array(
+        
+                // eliminate single line comments in '// ...' form
+                '#^\s*//(.+)$#m',
+    
+                // eliminate multi-line comments in '/* ... */' form, at start of string
+                '#^\s*/\*(.+)\*/#Us',
+    
+                // eliminate multi-line comments in '/* ... */' form, at end of string
+                '#/\*(.+)\*/\s*$#Us'
+    
+            ), '', $str);
+        
+        // eliminate extraneous space
+        return trim($str);
+    }
+
+   /**
+    * decodes a JSON string into appropriate variable
+    *
+    * @param    string  $str    JSON-formatted string
+    *
+    * @return   mixed   number, boolean, string, array, or object
+    *                   corresponding to given JSON input string.
+    *                   See argument 1 to JSON() above for object-output behavior.
+    *                   Note that decode() always returns strings
+    *                   in ASCII or UTF-8 format!
+    * @access   public
+    */
+    function decode($str)
+    {
+        $str = $this->reduce_string($str);
+    
+        switch (strtolower($str)) {
+            case 'true':
+                return true;
+
+            case 'false':
+                return false;
+            
+            case 'null':
+                return null;
+            
+            default:
+                if (is_numeric($str)) {
+                    // Lookie-loo, it's a number
+
+                    // This would work on its own, but I'm trying to be
+                    // good about returning integers where appropriate:
+                    // return (float)$str;
+
+                    // Return float or int, as appropriate
+                    return ((float)$str == (integer)$str)
+                        ? (integer)$str
+                        : (float)$str;
+                    
+                } elseif (preg_match('/^("|\').+("|\')$/s', $str, $m) && $m[1] == $m[2]) {
+                    // STRINGS RETURNED IN UTF-8 FORMAT
+                    $delim = substr($str, 0, 1);
+                    $chrs = substr($str, 1, -1);
+                    $utf8 = '';
+                    $strlen_chrs = strlen($chrs);
+                    
+                    for ($c = 0; $c < $strlen_chrs; ++$c) {
+                    
+                        $substr_chrs_c_2 = substr($chrs, $c, 2);
+                        $ord_chrs_c = ord($chrs{$c});
+                        
+                        switch ($substr_chrs_c_2) {
+                            case '\b':  $utf8 .= chr(0x08);  $c+=1;  break;
+                            case '\t':  $utf8 .= chr(0x09);  $c+=1;  break;
+                            case '\n':  $utf8 .= chr(0x0A);  $c+=1;  break;
+                            case '\f':  $utf8 .= chr(0x0C);  $c+=1;  break;
+                            case '\r':  $utf8 .= chr(0x0D);  $c+=1;  break;
+
+                            case '\\"':
+                            case '\\\'':
+                            case '\\\\':
+                            case '\\/':
+                                if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
+                                   ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
+                                    $utf8 .= $chrs{++$c};
+                                }
+                                break;
+                                
+                            default:
+                                if (preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6))) {
+                                    // single, escaped unicode character
+                                    $utf16 = chr(hexdec(substr($chrs, ($c+2), 2)))
+                                           . chr(hexdec(substr($chrs, ($c+4), 2)));
+                                    $utf8 .= mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
+                                    $c+=5;
+        
+                                } elseif(($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F)) {
+                                    $utf8 .= $chrs{$c};
+        
+                                } elseif(($ord_chrs_c & 0xE0) == 0xC0) {
+                                    // characters U-00000080 - U-000007FF, mask 110XXXXX
+                                    //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                    $utf8 .= substr($chrs, $c, 2); $c += 1;
+    
+                                } elseif(($ord_chrs_c & 0xF0) == 0xE0) {
+                                    // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+                                    // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                    $utf8 .= substr($chrs, $c, 3); $c += 2;
+    
+                                } elseif(($ord_chrs_c & 0xF8) == 0xF0) {
+                                    // characters U-00010000 - U-001FFFFF, mask 11110XXX
+                                    // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                    $utf8 .= substr($chrs, $c, 4); $c += 3;
+    
+                                } elseif(($ord_chrs_c & 0xFC) == 0xF8) {
+                                    // characters U-00200000 - U-03FFFFFF, mask 111110XX
+                                    // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                    $utf8 .= substr($chrs, $c, 5); $c += 4;
+    
+                                } elseif(($ord_chrs_c & 0xFE) == 0xFC) {
+                                    // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+                                    // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                                    $utf8 .= substr($chrs, $c, 6); $c += 5;
+
+                                }
+                                break;
+
+                        }
+
+                    }
+                    
+                    return $utf8;
+                
+                } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
+                    // array, or object notation
+
+                    if ($str{0} == '[') {
+                        $stk = array(JSON_IN_ARR);
+                        $arr = array();
+                    } else {
+                        if ($this->use == JSON_LOOSE_TYPE) {
+                            $stk = array(JSON_IN_OBJ);
+                            $obj = array();
+                        } else {
+                            $stk = array(JSON_IN_OBJ);
+                            $obj = new stdClass();
+                        }
+                    }
+                    
+                    array_push($stk, array('what'  => JSON_SLICE,
+                                           'where' => 0,
+                                           'delim' => false));
+
+                    $chrs = substr($str, 1, -1);
+                    $chrs = $this->reduce_string($chrs);
+                    
+                    if ($chrs == '') {
+                        if (reset($stk) == JSON_IN_ARR) {
+                            return $arr;
+
+                        } else {
+                            return $obj;
+
+                        }
+                    }
+
+                    //print("\nparsing {$chrs}\n");
+                    
+                    $strlen_chrs = strlen($chrs);
+                    
+                    for ($c = 0; $c <= $strlen_chrs; ++$c) {
+                    
+                        $top = end($stk);
+                        $substr_chrs_c_2 = substr($chrs, $c, 2);
+                    
+                        if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == JSON_SLICE))) {
+                            // found a comma that is not inside a string, array, etc.,
+                            // OR we've reached the end of the character list
+                            $slice = substr($chrs, $top['where'], ($c - $top['where']));
+                            array_push($stk, array('what' => JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
+                            //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                            if (reset($stk) == JSON_IN_ARR) {
+                                // we are in an array, so just push an element onto the stack
+                                array_push($arr, $this->decode($slice));
+
+                            } elseif (reset($stk) == JSON_IN_OBJ) {
+                                // we are in an object, so figure
+                                // out the property name and set an
+                                // element in an associative array,
+                                // for now
+                                if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
+                                    // "name":value pair
+                                    $key = $this->decode($parts[1]);
+                                    $val = $this->decode($parts[2]);
+
+                                    if ($this->use == JSON_LOOSE_TYPE) {
+                                        $obj[$key] = $val;
+                                    } else {
+                                        $obj->$key = $val;
+                                    }
+                                } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
+                                    // name:value pair, where name is unquoted
+                                    $key = $parts[1];
+                                    $val = $this->decode($parts[2]);
+
+                                    if ($this->use == JSON_LOOSE_TYPE) {
+                                        $obj[$key] = $val;
+                                    } else {
+                                        $obj->$key = $val;
+                                    }
+                                }
+
+                            }
+
+                        } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) &&
+                                 in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) {
+                            // found a quote, and we are not inside a string
+                            array_push($stk, array('what' => JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
+                            //print("Found start of string at {$c}\n");
+
+                        } elseif (($chrs{$c} == $top['delim']) &&
+                                 ($top['what'] == JSON_IN_STR) &&
+                                 (($chrs{$c - 1} != "\\") ||
+                                 ($chrs{$c - 1} == "\\" && $chrs{$c - 2} == "\\"))) {
+                            // found a quote, we're in a string, and it's not escaped
+                            array_pop($stk);
+                            //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
+
+                        } elseif (($chrs{$c} == '[') &&
+                                 in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) {
+                            // found a left-bracket, and we are in an array, object, or slice
+                            array_push($stk, array('what' => JSON_IN_ARR, 'where' => $c, 'delim' => false));
+                            //print("Found start of array at {$c}\n");
+
+                        } elseif (($chrs{$c} == ']') && ($top['what'] == JSON_IN_ARR)) {
+                            // found a right-bracket, and we're in an array
+                            array_pop($stk);
+                            //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                        } elseif (($chrs{$c} == '{') &&
+                                 in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) {
+                            // found a left-brace, and we are in an array, object, or slice
+                            array_push($stk, array('what' => JSON_IN_OBJ, 'where' => $c, 'delim' => false));
+                            //print("Found start of object at {$c}\n");
+
+                        } elseif (($chrs{$c} == '}') && ($top['what'] == JSON_IN_OBJ)) {
+                            // found a right-brace, and we're in an object
+                            array_pop($stk);
+                            //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                        } elseif (($substr_chrs_c_2 == '/*') &&
+                                 in_array($top['what'], array(JSON_SLICE, JSON_IN_ARR, JSON_IN_OBJ))) {
+                            // found a comment start, and we are in an array, object, or slice
+                            array_push($stk, array('what' => JSON_IN_CMT, 'where' => $c, 'delim' => false));
+                            $c++;
+                            //print("Found start of comment at {$c}\n");
+
+                        } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == JSON_IN_CMT)) {
+                            // found a comment end, and we're in one now
+                            array_pop($stk);
+                            $c++;
+                            
+                            for ($i = $top['where']; $i <= $c; ++$i)
+                                $chrs = substr_replace($chrs, ' ', $i, 1);
+                            
+                            //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+                        }
+                    
+                    }
+                    
+                    if (reset($stk) == JSON_IN_ARR) {
+                        return $arr;
+
+                    } elseif (reset($stk) == JSON_IN_OBJ) {
+                        return $obj;
+
+                    }
+                
+                }
+        }
+    }
+    
+   /**
+    * decodes a JSON string into appropriate variable; alias for decode()
+    */
+    function dec($var)
+    {
+        return $this->decode($var);
+    }
+    
+}
+    
+?>
\ No newline at end of file
diff --git a/inc/html.php b/inc/html.php
index d4fafdaf3..d03815f00 100644
--- a/inc/html.php
+++ b/inc/html.php
@@ -894,37 +894,12 @@ function html_edit($text=null,$include='edit'){ //FIXME: include needed?
   <table style="width:99%">
     <tr>
       <td class="toolbar" colspan="2">
+        <div id="toolbar"></div>
+
         <?php if($wr){?>
         <script language="javascript" type="text/javascript" charset="utf-8">
           <?php /* sets changed to true when previewed */?>
           textChanged = <?php ($pr) ? print 'true' : print 'false' ?>;
-          
-          formatButton('bold.png','<?php echo $lang['qb_bold']?>','**','**','<?php echo $lang['qb_bold']?>','b');
-          formatButton('italic.png','<?php echo $lang['qb_italic']?>',"\/\/","\/\/",'<?php echo $lang['qb_italic']?>','i');
-          formatButton('underline.png','<?php echo $lang['qb_underl']?>','__','__','<?php echo $lang['qb_underl']?>','u');
-          formatButton('code.png','<?php echo $lang['qb_code']?>','\'\'','\'\'','<?php echo $lang['qb_code']?>','c');
-          formatButton('strike.png','<?php echo $lang['qb_strike']?>','&lt;del&gt;','&lt;\/del&gt;','<?php echo $lang['qb_strike']?>','d');
-
-          formatButton('fonth1.png','<?php echo $lang['qb_h1']?>','====== ',' ======\n','<?php echo $lang['qb_h1']?>','1');
-          formatButton('fonth2.png','<?php echo $lang['qb_h2']?>','===== ',' =====\n','<?php echo $lang['qb_h2']?>','2');
-          formatButton('fonth3.png','<?php echo $lang['qb_h3']?>','==== ',' ====\n','<?php echo $lang['qb_h3']?>','3');
-          formatButton('fonth4.png','<?php echo $lang['qb_h4']?>','=== ',' ===\n','<?php echo $lang['qb_h4']?>','4');
-          formatButton('fonth5.png','<?php echo $lang['qb_h5']?>','== ',' ==\n','<?php echo $lang['qb_h5']?>','5');
-
-          formatButton('link.png','<?php echo $lang['qb_link']?>','[[',']]','<?php echo $lang['qb_link']?>','l');
-          formatButton('extlink.png','<?php echo $lang['qb_extlink']?>','[[',']]','http://www.example.com|<?php echo $lang['qb_extlink']?>');
-
-          formatButton('list.png','<?php echo $lang['qb_ol']?>','  - ','\n','<?php echo $lang['qb_ol']?>');
-          formatButton('list_ul.png','<?php echo $lang['qb_ul']?>','  * ','\n','<?php echo $lang['qb_ul']?>');
-
-          insertButton('rule.png','<?php echo $lang['qb_hr']?>','----\n');
-          mediaButton('image.png','<?php echo $lang['qb_media']?>','m','<?php echo $INFO['namespace']?>');
-
-          <?php
-          if($conf['useacl'] && $_SERVER['REMOTE_USER']){
-            echo "insertButton('sig.png','".$lang['qb_sig']."','".html_signature()."','y');";
-          }
-          ?>
         </script>
         <span id="spell_action"></span>
         <?php } ?>
@@ -955,14 +930,18 @@ function html_edit($text=null,$include='edit'){ //FIXME: include needed?
       <?php }?>
       </td>
       <td align="right">
+        <div id="sizectl"></div>
+
         <script language="javascript" type="text/javascript" charset="utf-8">
-          showSizeCtl();
+          //showSizeCtl();
           <?php if($wr){ ?>
             init_locktimer(<?php echo $conf['locktime']-60?>,'<?php echo $lang['willexpire']?>');
 
+            //initToolbar('toolbar','wikitext',toolbar);
+
             //initialize spellchecker
             <?php if($conf['spellchecker']){ ?>
-              ajax_spell.init('<?php echo $lang['spell_start']?>','<?php echo $lang['spell_stop']?>','<?php echo $lang['spell_wait']?>','<?php echo $lang['spell_noerr']?>','<?php echo $lang['spell_nosug']?>','<?php echo $lang['spell_change']?>');
+//              ajax_spell.init('<?php echo $lang['spell_start']?>','<?php echo $lang['spell_stop']?>','<?php echo $lang['spell_wait']?>','<?php echo $lang['spell_noerr']?>','<?php echo $lang['spell_nosug']?>','<?php echo $lang['spell_change']?>');
             <?php } ?>
 
             document.editform.wikitext.focus();
@@ -1003,24 +982,6 @@ function html_minoredit(){
   print '</label>';
 }
 
-/**
- * prepares the signature string as configured in the config
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
-function html_signature(){
-  global $conf;
-  global $INFO;
-
-  $sig = $conf['signature'];
-  $sig = strftime($sig);
-  $sig = str_replace('@USER@',$_SERVER['REMOTE_USER'],$sig);
-  $sig = str_replace('@NAME@',$INFO['userinfo']['name'],$sig);
-  $sig = str_replace('@MAIL@',$INFO['userinfo']['mail'],$sig);
-  $sig = str_replace('@DATE@',date($conf['dformat']),$sig);
-  return addslashes($sig);
-}
-
 /**
  * prints some debug info
  *
diff --git a/inc/lang/en/lang.php b/inc/lang/en/lang.php
index 9cfae794e..c3de831cd 100644
--- a/inc/lang/en/lang.php
+++ b/inc/lang/en/lang.php
@@ -123,6 +123,9 @@ $lang['qb_ol']      = 'Ordered List Item';
 $lang['qb_ul']      = 'Unordered List Item';
 $lang['qb_media']   = 'Add Images and other files';
 $lang['qb_sig']     = 'Insert Signature';
+$lang['qb_smileys'] = 'Smileys';
+$lang['qb_chars']   = 'Special Chars';
+
 
 $lang['del_confirm']= 'Delete this entry?';
 
diff --git a/inc/template.php b/inc/template.php
index e04998444..8c84515c2 100644
--- a/inc/template.php
+++ b/inc/template.php
@@ -207,6 +207,7 @@ function tpl_metaheaders(){
   ptln("  var alertText   = '".str_replace('\\\\n','\\n',addslashes($lang['qb_alert']))."'",$it);
   ptln("  var notSavedYet = '".str_replace('\\\\n','\\n',addslashes($lang['notsavedyet']))."'",$it);
   ptln("  var DOKU_BASE   = '".DOKU_BASE."'",$it);
+
   ptln('</script>',$it);
  
   // load the default JavaScript files
@@ -217,11 +218,6 @@ function tpl_metaheaders(){
   ptln('<script language="javascript" type="text/javascript" charset="utf-8" src="'.
        DOKU_BASE.'lib/scripts/ajax.js"></script>',$it);
 
-  // load spellchecker script if wanted
-  if($conf['spellchecker'] && ($ACT=='edit' || $ACT=='preview')){
-    ptln('<script language="javascript" type="text/javascript" charset="utf-8" src="'.
-       DOKU_BASE.'lib/scripts/spellcheck.js"></script>',$it);
-  }
   
   // dom tool tip library, for insitu footnotes
   ptln('<script language="javascript" type="text/javascript" charset="utf-8" src="'.
@@ -229,6 +225,44 @@ function tpl_metaheaders(){
   ptln('<script language="javascript" type="text/javascript" charset="utf-8" src="'.
        DOKU_BASE.'lib/scripts/domTT.js"></script>',$it);
 
+  // add size control
+  ptln('<script language="javascript" type="text/javascript" charset="utf-8">',$it);
+  ptln("addEvent(window,'onload',function(){initSizeCtl('sizectl','wikitext')});",$it+2);
+  ptln('</script>',$it);
+
+
+  // editing functions
+  if(($ACT=='edit' || $ACT=='preview') && $INFO['writable']){
+    // load toolbar functions
+    ptln('<script language="javascript" type="text/javascript" charset="utf-8" src="'.
+         DOKU_BASE.'lib/scripts/edit.js"></script>',$it);
+
+    // load spellchecker functions if wanted
+    if($conf['spellchecker']){
+      ptln('<script language="javascript" type="text/javascript" charset="utf-8" src="'.
+           DOKU_BASE.'lib/scripts/spellcheck.js"></script>',$it+2);
+    }
+
+    ptln('<script language="javascript" type="text/javascript" charset="utf-8">',$it);
+
+    // add toolbar
+    require_once(DOKU_INC.'inc/toolbar.php');
+    toolbar_JSdefines('toolbar');
+    ptln("addEvent(window,'onload',function(){initToolbar('toolbar','wikitext',toolbar);});",$it+2);
+
+    // add spellchecker
+    if($conf['spellchecker']){
+      //init here
+      ptln("addEvent(window,'onload',function(){ ajax_spell.init('".$lang['spell_start']."','".
+                                                                    $lang['spell_stop']."','".
+                                                                    $lang['spell_wait']."','".
+                                                                    $lang['spell_noerr']."','".
+                                                                    $lang['spell_nosug']."','".
+                                                                    $lang['spell_change']."'); });");
+    }
+    ptln('</script>',$it);
+  }
+
   // plugin stylesheets and Scripts
   plugin_printCSSJS();
 }
diff --git a/inc/toolbar.php b/inc/toolbar.php
new file mode 100644
index 000000000..5c4ff030f
--- /dev/null
+++ b/inc/toolbar.php
@@ -0,0 +1,202 @@
+<?php
+/**
+ * Editing toolbar functions
+ * 
+ * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author     Andreas Gohr <andi@splitbrain.org>
+ */
+
+  if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/');
+
+require_once(DOKU_INC.'inc/JSON.php');
+
+
+/**
+ * Prepares and prints an JavaScript array with all toolbar buttons
+ *
+ * @todo add toolbar plugins
+ * @param  string $varname Name of the JS variable to fill
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function toolbar_JSdefines($varname){
+    global $ID;
+    global $conf;
+    global $lang;    
+
+    // build button array  
+    $menu = array(
+       array(
+            'type'   => 'format',
+            'title'  => $lang['qb_bold'],
+            'icon'   => 'bold.png',
+            'key'    => 'b',
+            'open'   => '**',
+            'close'  => '**',
+            ),
+       array(
+            'type'   => 'format',
+            'title'  => $lang['qb_italic'],
+            'icon'   => 'italic.png',
+            'key'    => 'i',
+            'open'   => '//',
+            'close'  => '//',
+            ),
+       array(
+            'type'   => 'format',
+            'title'  => $lang['qb_underl'],
+            'icon'   => 'underline.png',
+            'key'    => 'u',
+            'open'   => '__',
+            'close'  => '__',
+            ),
+       array(
+            'type'   => 'format',
+            'title'  => $lang['qb_code'],
+            'icon'   => 'mono.png',
+            'key'    => 'c',
+            'open'   => "''",
+            'close'  => "''",
+            ),
+       array(
+            'type'   => 'format',
+            'title'  => $lang['qb_strike'],
+            'icon'   => 'strike.png',
+            'key'    => 'd',
+            'open'  => '<del>',
+            'close'   => '<del>',
+            ),
+       array(
+            'type'   => 'format',
+            'title'  => $lang['qb_h1'],
+            'icon'   => 'h1.png',
+            'key'    => '1',
+            'open'   => '====== ',
+            'close'  => '======\n',
+            ),
+       array(
+            'type'   => 'format',
+            'title'  => $lang['qb_h2'],
+            'icon'   => 'h2.png',
+            'key'    => '2',
+            'open'   => '===== ',
+            'close'  => '=====\n',
+            ),
+       array(
+            'type'   => 'format',
+            'title'  => $lang['qb_h3'],
+            'icon'   => 'h3.png',
+            'key'    => '3',
+            'open'   => '==== ',
+            'close'  => '====\n',
+            ),
+       array(
+            'type'   => 'format',
+            'title'  => $lang['qb_h4'],
+            'icon'   => 'h4.png',
+            'key'    => '4',
+            'open'   => '=== ',
+            'close'  => '===\n',
+            ),
+       array(
+            'type'   => 'format',
+            'title'  => $lang['qb_h5'],
+            'icon'   => 'h5.png',
+            'key'    => '5',
+            'open'   => '== ',
+            'close'  => '==\n',
+            ),
+       array(
+            'type'   => 'format',
+            'title'  => $lang['qb_link'],
+            'icon'   => 'link.png',
+            'key'    => 'l',
+            'open'   => '[[',
+            'close'  => ']]',
+            ),
+       array(
+            'type'   => 'format',
+            'title'  => $lang['qb_extlink'],
+            'icon'   => 'linkextern.png',
+            'open'   => '[[',
+            'close'  => ']]',
+            'sample' => 'http://example.com|'.$lang['qb_extlink'],
+            ),
+       array(
+            'type'   => 'format',
+            'title'  => $lang['qb_ol'],
+            'icon'   => 'ol.png',
+            'open'   => '  - ',
+            'close'  => '\n',
+            ),
+       array(
+            'type'   => 'format',
+            'title'  => $lang['qb_ul'],
+            'icon'   => 'ul.png',
+            'open'   => '  * ',
+            'close'  => '\n',
+            ),
+       array(
+            'type'   => 'insert',
+            'title'  => $lang['qb_hr'],
+            'icon'   => 'hr.png',
+            'insert' => '----\n',
+            ),
+       array(
+            'type'   => 'popup',
+            'title'  => $lang['qb_media'],
+            'icon'   => 'image.png',
+            'url'    => DOKU_BASE.'lib/exe/media.php?ns='.getNS($ID),
+            'name'   => 'mediaselect',
+            'options'=> 'width=600,height=320,left=70,top=50,scrollbars=yes,resizable=yes',
+            ),
+      array(
+            'type'   => 'picker',
+            'title'  => $lang['qb_smileys'],
+            'icon'   => 'smiley.png',
+            'list'   => getSmileys(),
+            'icobase'=> 'smileys',
+           ),
+      array(
+            'type'   => 'picker',
+            'title'  => $lang['qb_chars'],
+            'icon'   => 'chars.png',
+            'list'   => explode(' ','À à Á á Â â Ã ã Ä ä Ǎ ǎ Ă ă Å å Ā ā Ą ą Æ æ Ć ć Ç ç Č č Ĉ ĉ Ċ ċ Ð đ ð Ď ď È è É é Ê ê Ë ë Ě ě Ē ē Ė ė Ę ę Ģ ģ Ĝ ĝ Ğ ğ Ġ ġ Ĥ ĥ Ì ì Í í Î î Ï ï Ǐ ǐ Ī ī İ ı Į į Ĵ ĵ Ķ ķ Ĺ ĺ Ļ ļ Ľ ľ Ł ł Ŀ ŀ Ń ń Ñ ñ Ņ ņ Ň ň Ò ò Ó ó Ô ô Õ õ Ö ö Ǒ ǒ Ō ō Ő ő Ø ø Ŕ ŕ Ŗ ŗ Ř ř Ś ś Ş ş Š š Ŝ ŝ Ţ ţ Ť ť Ù ù Ú ú Û û Ü ü Ǔ ǔ Ŭ ŭ Ū ū Ů ů ǖ ǘ ǚ ǜ Ų ų Ű ű Ŵ ŵ Ý ý Ÿ ÿ Ŷ ŷ Ź ź Ž ž Ż ż Þ þ ß Ħ ħ ¿ ¡ ¢ £ ¤ ¥ € ¦ § ª ¬ ¯ ° ± ÷ ‰ ¼ ½ ¾ ¹ ² ³ µ ¶ † ‡ · • º ∀ ∂ ∃ Ə ə ∅ ∇ ∈ ∉ ∋ ∏ ∑ ‾ − ∗ √ ∝ ∞ ∠ ∧ ∨ ∩ ∪ ∫ ∴ ∼ ≅ ≈ ≠ ≡ ≤ ≥ ⊂ ⊃ ⊄ ⊆ ⊇ ⊕ ⊗ ⊥ ⋅ ◊ ℘ ℑ ℜ ℵ ♠ ♣ ♥ ♦'),
+           ),
+    );
+    
+    // if logged in add sig button
+    if($conf['useacl'] && $_SERVER['REMOTE_USER']){
+        $menu[] = array(
+            'type'   => 'insert',
+            'title'  => $lang['qb_sig'],
+            'icon'   => 'sig.png',
+            'key'    => 'y',
+            'insert' => toolbar_signature(),
+            );
+    }
+
+    // use JSON to build the JavaScript array
+    $json = new JSON();
+    print "var $varname = ".$json->encode($menu).";\n";
+}
+
+/**
+ * prepares the signature string as configured in the config
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function toolbar_signature(){
+  global $conf;
+  global $INFO;
+
+  $sig = $conf['signature'];
+  $sig = strftime($sig);
+  $sig = str_replace('@USER@',$_SERVER['REMOTE_USER'],$sig);
+  $sig = str_replace('@NAME@',$INFO['userinfo']['name'],$sig);
+  $sig = str_replace('@MAIL@',$INFO['userinfo']['mail'],$sig);
+  $sig = str_replace('@DATE@',date($conf['dformat']),$sig);
+  return $sig;
+}
+
+
+//Setup VIM: ex: et ts=4 enc=utf-8 :
diff --git a/lib/images/toolbar/bold.png b/lib/images/toolbar/bold.png
index d12c5710e94ae165bbf2b8e07010a965e5018ce9..6ec336262a9e6487182ff12d66f8c1419348472a 100644
GIT binary patch
literal 479
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL
zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+AuIM7J9lkhE&{2`t$$4J+mr<Lc<IR
z4HgDQmyL`Jj7OTztX#3egCXc={r`WaKR!P{-+q68z5kD|uctFkDEsmA^K&+Z-34c7
znaWT2%D^Jf#cgF}CB|Ty_v6=BZRUWFt(w8hOwP?R)&6k2UtYSQO{M1lzgqiU+zd<|
ztg#F$CNgGl9Nu65|3Q*NFTX=0?-Je%SD9G^!k81<8XD%$pU-gNCucyj*n-vU911+l
z4PA+C8b5yhy2kvI(c!kJUG1-u2Tx8;?tJlzk%>cDtl=N4G(*w1XJ=<im%qK0`s3l@
zc2*xBAHG+wUOg8T5n-7CGP;e?q1S+U!cngKd#jHhICn0OVT%G|q^$!(qA9}@-W29_
zF*`p!yuCgDK>_2bkIEo>#d6pTjE$Q!b_A!Uq;OeST1w8dt!DF*=AH;LPq`>=!`7|7
z3|1HAGq^RLIBtt=U|Yec5z7#3AoyYu`w2E+peQe$$*ItwagG}rrfdxV{ypIjKR>@8
P7()!6u6{1-oD!M<qk_08

literal 738
zcmV<80v-K{P)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x0+&fdK~#9!t(8wp<6scRe`%Y|o@zzbDlB*qStzbYJyoa&4}ODwhCR8T
z#nbL_7qOwe3Z6vpsvztlDk_Ll!DgF6n>0z&*~2EGP1|k#GcY9Yo5?)$%=^v^Ko-~m
z<c;(j@CkSaC<?H1cX#(ClgZF4ilR*X9zK2Fr&_JDw6ydS_zE->KupubG|kBPe>%>l
z+wC$lGXszV9ufeFL}IMtP{-M(QmK&O6rd$~=??q3QmHUMKhNCU9NBD^+1XhtmC9I_
zfC?lMamsNJUDt_AsZ^Q-0DwLQagb`Y%JK2>0Kn1F5s#0LF9!%g%H=X5LU>N0hzPo_
zk35e7fKic@N~OqfZEcOk#l>j7ySqE`+$LghdV0$B^>t)eC=@6Z3eo!N>WY(-lc69J
zG3bpx1lZWv=-Uff#6kKB7LZn}MYGwA3|!YGm&?&;H2z)asVQ!5Zm?~eg@pxt-v?lN
zdYaqYTQp7UD?&}v0M>!ap(#2zIEb7B<nwt{RVAHHv%0z(?bqvd_V@P(Sj0sv%aW(3
zC#ltHVi<;OZf;K8+_tv1#Bm&PT~|EMlTN1-e#-}q6tQhv48st^Fy!LmLXyek!~n@;
zQtt2XBj>*F_W=yFigLLe<rrXldz)snNvqYuvMg-drdTXS-+kX_Z*OnpEdr2syDg?^
zN~6(`<>lqR2oDbr#j-51ZCl#ywm6O>x~})xtgNg^x7(FadKoAI0FL84t1S<+i_M93
z;4%f^y6%g5|FD!8hA~iR-_Os_@jMSzRiD-S<Id~#I%j8R0KWl0NEIJ}A8$C5e*s0{
zGmue&;hY9O1XCy#RQOA!12lme@J9)pslfXHEXnJn3wVGHcuK4<DX)w^y85C11y^%y
UZTh`Q)c^nh07*qoM6N<$f}Ctz{Qv*}

diff --git a/lib/images/toolbar/chars.png b/lib/images/toolbar/chars.png
new file mode 100644
index 0000000000000000000000000000000000000000..83cdadd755809565ff66f5b2fef3172eb39903e1
GIT binary patch
literal 636
zcmV-?0)zdDP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt006JZ
zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!4oO5oRCwBA
z{Qv(y10?_;fS4F41ONfVf-Vp>?TG>(2XnowFpI<YU;jV+13Hj}iBaJ0tDgtHe*V|E
zp<M0(vU-33Vnp^r)YK;i#!4Lf|NUcNICbZH;OczY10eB$&PNW0YMkr;|NYN!`r22=
zt#yhQV0r)o2yQ^c)W-s*3Y_=3IhY0ZUi#v=x)7on2E1GDJ2)8f?tlCF&xf;DzAEl+
zQT_lD2M8c|82tOgkigH)B5?23?+fUfL11f*;(;4ae_RmaVHWuF>t6y)93X(;21p9A
z`h#3^>(P%5xB~3{z3&_T0=*|B%H|If0|+3v0e^u010sgMfBxbO@jt(T^8X+h1^@yG
zZouo0zaKCFUBJc5Vt~s4UOr|6Muz_kAK(6h#{@tC!43HG;qSr^-~KVkiLyH2GC)F-
z&EehGzYL$=|6T|a0|+3v0o&>o4;;Jvd4V7olYm3%?F4kqrWw~0gn3v5PM`U_;OuNI
zcpw7=5Zr+9Nssn_djDtQ;R|0EXlilyTjkyqfXSJpUKdc;<LN(k>f?fs?|)BptGT@&
zCI=8ea0BE;*&P1-`S1Vn-LHkO-~WCfp}+xGBn?blAK(9Z@ag@pg@6D3^Out5gnJVp
zfZ$2_FE9X2jCdRV0;2+yw2(tuRG8HO#1$41-2WfQK$2nr2p~pEb0a_iQJfnA0t^5c
WE7*mHLr^0C0000<MNUMnLSTZM*&mMp

literal 0
HcmV?d00001

diff --git a/lib/images/toolbar/code.png b/lib/images/toolbar/code.png
deleted file mode 100644
index fb5c0c3d8be18b48add78d3af2456f2642799b7b..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 710
zcmV;%0y+JOP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru)d>p~HYOFyw_gAN0#ivu
zK~zY`wUxh5>TndrKdmJZ<D|yLRasa`l(?}9G3n&MN*wqz41>|dME?L57bp8CIGQlP
zfW(GH7b7K=S_%c*`vwAeNPQ;HdXh8rNA9`jeD7^}d3lj?xhy~|ER{;qYPH1oeF?)*
zD3{Cf^z<Z-<IM5>{e4E)b!Y7N`!jl;C!XiYU@(xuU?8sRifNisEEeVU^;LY|7X^^F
zw>NCtMp2X>GYA6K*Vkz_n`~`up#rF?8cT6SQP4CEfL^bM@B2)yAU1(1#^W(z7)}J@
zD*m^?6u;(R3iUey(=;RRKR!N27XK^~8Bx34#xM*F!@#mETCLW?I|l~`Y;JC%>pHrw
zlS-u`UCcSSxVRvf%W-scgl*fLo}SWdHotUsetu53+vV`^kZd-~+1c5GfC5Or-^Xzr
zGMNm+;gI9wV+w@=J3Bj(5quUh41>$dOOnYXrfIUgyv*I*9jR1m-a)Naqgt(ESr)pk
zv%kMjrBWg4oK8+o$Ye6)^LZ@G;^yXNb}s*%qTStH_V)IuR4Uxx-*bC=8yS)7x?Ejd
zk<Dfo7Ih&a&+~9yH<oc#RTWLs<|Fzl-#B(bjeF4|1>!9J>kcA66{FE8Hi2%pJ3pqS
zQi+F$2e!AjSy@>j2!d~y>#L4!+ooQxlTN2uT3VVse|~<JVzC(8KRKOF%k}lOG#U-D
zZCe!I_r-A>I-L%^UXPED4@89jg{En&uCB7NvBBEf8cG<3G9Hf^4u_0JBZ45{Cs0+D
sL?S^lnIw@&piH}!34YXl#6&880D6~fYKarV-2eap07*qoM6N<$f}NB<ApigX

diff --git a/lib/images/toolbar/empty.png b/lib/images/toolbar/empty.png
deleted file mode 100644
index e606cfd078ecb71c629138a6451577f748183fe3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 516
zcmV+f0{i`mP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv0000hbVXQnLvm$d
zbZKvHAXI5>WdKueATl%{Piu4_GB7YSATcyLFfuwbI3O!9F)%R9jQObm000McNliru
z)Cw331sh~;SA_ro010qNS#tmY9>D+r9>D>_X;f1H000DMK}|sb0I`n?{9y$E00CS{
zL_t(|+O?I>N{2uY$7k2I@=}6Cm#z{7Jy6fkt!L>}$9f^5@GgXxOoJe>beq|q+O}#x
z$@vX@{DU&zo!OZk0Du$Z2GLC1B4@}RA_O_lvg|4hL$FPlPs^VBd($+K=Q+f2{D805
z$QympRaHS*mgdK`kVq6oq<4-yOL~%0vN$J{Qhk6&$iA|}<-jtZ)~-06I|9ab8G$j$
zDd1Mw5P|!n=Xs-&opPqNHW){^xl>X6ieQZ`iojj@QuBR(Bs96nZQBmv+D5`|il}!+
z8`|~LtiW6)Y%{k}XH(?nbV<c*i%hy3#N7+5eK0G)>3ruAj0%7*bzQRw6h$!-xJ%R2
zw0sZ*rfF=bC;ozZq%Tt%T1k?S-zTJj%?O24<R18D@*{GITp%GOjfV3fatxa(M7^=*
zVERJdkr(7ubk687Iq1axcOd;3oj0Gz2i@(J3X8Qir0g3Y(`uz=xnHLM0000<MNUMn
GLSTZw@Ys(4

diff --git a/lib/images/toolbar/extlink.png b/lib/images/toolbar/extlink.png
deleted file mode 100644
index 705527e8cfee0c68882be97d8d6319d982a31531..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 885
zcmV-*1B(2KP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY9>M?s9>M``&~-il000McNliru)d>p~H8LbUFyR0I0|H4z
zK~zY`tyMis^I#M``NApzi!CZta8Pu}4{)&P;^5}uBymv-LVt!1g6OXhac~fvqz=Vd
z!B(_^bP%l&A`)BErun?@(6^=0*w>Huz#Sf*n{)1G9%!0I*=&{o{1?k)GNdR9*|tqV
z5D>E2EIm9tP_0%A+1uM&$4t}gSiN5FSfkOPMx#NNWszlBWSS<as!FmfldkJz+cq%(
z==Jp#hGBqVm|vUk`$!}bxVyVUDwP5Y04&S?n6Of*AeYObTrPuQ81Os~0H{{0ux%Ty
z6YwRnr>7^Jo}NNc6qHIOsH%#3y$+t|adUG6hGE)ta9tNc5VQoo8tur)2o4SopsFgm
zvADR1R4Nq`XoLMu27P^f*xTFtK(fBR9`fr(s6?*oqF5}#_x+Az_lH3c;Q06$JkP`P
zJOIGd)D#vL7DE0X1Q>>aX_}aun}e?F_!l^i>xitat-<$w@I2o;gWKC%=(>*W?QNvf
z>5x+{m&5-4J}k?ED2gym6H7}=I6FJT%E}4^K|psUA~R@Tq|<54&(C*8ZF6%IM@L5h
zfYH%W?C$Pjb#)c8EMsC~0*OQ-MA)+j-MG5C!t(Mm?(gqA<oSFanx+8&1_lPOwY3$V
zn7{iJIYsXgi^Wi>Q~&_UWD@y&9@Ep)p+0mIa~$`%KvZ)iNy5g)21HTB$;nBGygTdn
ze*u<dqXnX{v$KQq^K;D3&PI}dW}hzFdkhW^VrFJ0Qv9m|AExN~`nu;1TwY#&O8@|<
z*=&-cC=`puzVxWX<8jh;ogBv@*LBJBJo0^?f*>FwA^>!8aY34<5f1>4<6wAr7==Os
z<#PE$gzwLiBq1J;M@Ikh@)9mlCX+#_RKn!sB*w?bF*Y{Vle||s48uU7P=F*!;5e>z
z|M>VwvMm3%H(8P-Iy^k2VzEeuVGv{6Hq~l1JU>69TCKwKJhaOAGw?hQQ52C(CNVTL
z1SSXqa$OhAW)qI%!1sOp1}w`$5Cru1_d^f_Fzslmg<nM<u_MeM7Am~@X(K2b00000
LNkvXXu0mjfc|(wA

diff --git a/lib/images/toolbar/fonth1.png b/lib/images/toolbar/fonth1.png
deleted file mode 100644
index ded5113ccce0313d9b0740af5656e306091be69c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 592
zcmV-W0<ZmvP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3labT3lag+-G2N4000McNliru)dmO<EGjyG`+EQY0o_SN
zK~zY`)s?@h8bK7se=|EQHbF$tDhojnK~g0TV3k+UE*6%#FJgI{q!Nn+xzCbHNMai-
z1SR{YP!<+<C(WJ3opm)qQ{=$eo%wdocV^Eya|WOVJOcVo`Vn{qNB{vmuGi~_dcBSi
z0waGjHt#e|*=#m+yWKCq2OtuFj-rS#46#K@i4dZo*RU+hXf~SwuYqsU5Z!}Z2!T?{
zP_!^{x)-_8XHog%G_JRhpNoXL*Uk-AiiS<@c^;ikr(ooH9_@BJ$3~+Oy<U$-qd}|H
zDmg4UIQQ|?$i}3UjK||bxmGz)_97!e5R@=8e|maC2*GqZrD}r(2lj#_N$B_crNvbV
zJ;k)v)qh}&lu|4fi`;NH9CAD!D-(Jt$;yte84m`7Ld<QVYx%kuqH9T>&*z2yGn>s2
zLNJ+3&N|U?9P90Nt9QGd2DIzCItT(ChM|t4NV~490lnYv_2F=+?4)U$>NHKw{N33q
z@_oNlb~YBraphsNlPv8jxV253J!t=;2NfJ7NrIFzSI2R19OsWPo80$(Gkjwld|Itm
zWLZY7RzoS3lbsS?Xv?{TVaRg11o#1bHFz8Ne8)TaJMbQOYwlzTyZ~N4-$IJpBm*Mg
eC-95^UVZ}~Xtz2i457~e0000<MNUMnLSTZjG5i$(

diff --git a/lib/images/toolbar/fonth2.png b/lib/images/toolbar/fonth2.png
deleted file mode 100644
index fcf23f5ab64edef1601c4350f654a40838daf308..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 708
zcmV;#0z3VQP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3labT3lag+-G2N4000McNliru)dmO<Eftjl=LY})0#Qjs
zK~zY`)s;_68$lSxe=`}DTuKfGBS->82#6F9?Zq!pya|FNo*EEu?a5D~m-dijOTIwx
z8a(F|XsgGfVl;OD1Py`J-M1HKNj9<nOb>nG-JN}Q_L+H}*?9+G9ykDGM)@9i4rl-c
z9Gsq>zRTruD5bFRCvAI=qKJ!&3(Dp4C*Um*C_sWB!1sO9p|wUSHI~1^;y7k*ZVuoD
z@L5};S&%EGFveJld8|*fBDeVvCb^9I`V{hMPMBHE++q`Mq{&OA5=%=<V;_}DB?^T?
zg4Jp@R##Wa=kpYcMYgxMIXgQ`Tf~?}>6fFkOk?eKn`*U6xm>2%Y;t&bi0itvTCK+|
zN|Sk>H-XvbPNzdQn?-BQ=H?~~3k#f_oJ_T7s)8^KSy@?`=xqB~a-|f_W)pz*^>wt?
zh{)p#>|bDvq0wk0gq2E#`}_Ne1+CZX?CtHbyu8f*{{B=205TX1q}%Pv<>jRS;y8|6
zUtf#sy5f1BIF2KL^!t6exw(-b2xND6R{&XCTa)wia|y#x?(Xg+3`1L!UjOwXZ)|LE
zbacex;vzdcJG5FYj4^C&ZB11n!{Jb_uCAol>m>?2&lBJGB?y8<!R_s>3<iU#Rn&1D
ziK0lND4J9-s={^MiA|KohQr~bn=QS_dX#(?Wg=~n{#P|<Y=AHf(OM^&$z;f6GQWkT
z$z9jA&6jq7568#H#BoeEo5dKDkc|@lq%0@l`#zmc2jDBvws-;fIKwmf3-AVbWzS>{
qJOhdkr;y=k5d#764fxJ~A3p%&y$&9Y%dss00000<MNUMnLSTX=Q9t?s

diff --git a/lib/images/toolbar/fonth3.png b/lib/images/toolbar/fonth3.png
deleted file mode 100644
index 04246acf2499ae770038dd00087bdbbbd819155f..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 681
zcmV;a0#^NrP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3labT3lag+-G2N4000McNliru)dmO<EiY3JKD7V<0yarR
zK~zY`)s?Yt+CUV>e|NS}mXaul;H5|;3QOohE3vU=WA(_2P`mI?WXY7J6+^_(Dq>(k
zh#}%XC<{_s##BhjRKS1`kwtu6auyhpHVGa2q-UQ$pTB$ez2|oTd%zi>Hsl|H1Rwzf
zaMtVfK5TDqBZNTPQ^xv!cX!9l%?-(9@(b`Da0H+n$6+`e5;Q3#LWm{*6Xtmykw^sK
z4e(8BqD_zsAuvr-Q|zI2+7!9=do%sZqOLC?U#En*smL|9qDGKB9*=WyaIo}IJRT<&
zi}_fkQX!Q}5s5^wEQ@S5ORLoiO2m>x!Iz6s2C--~N~u&L91hcNw<(v)6bc2duC5-I
zC`dLK3|27xoXh1H3<kKai(wd)%ViD^57$bxb_cHOa&&aGGI?>{{{Fs?ClU$H&(D!k
zqLg}g2f7MO)8yjf!Y8wBoB4dcl+b#;&h70jwOWm8wMwyAq}gn)1_h|;bjo-<MhJmr
zS%g9%uCK3s%`MBqbzMfI(MknPr&FTQDB*CJe!q`Wicly7a12~NE6MqMo=hgg&dv^v
zMgxF!I{maNdJI!aadL8k<2dZ@?qb_Er>CcDlPmx=o6VR^CeQk@f|ycD=kgf1l#7vV
zqD=&MA^%kmT3Wz$U8I!08-{^l7=MKY$@~4j9=_EJeCl?)c%H}B))uB|`eciQkF;gq
zhQlG9P6yxz@Kxh6;PVF0<nKTpc&DpK0<VDA_otA_%gh5D;3x2l|K5HBaT3Ina!I0M
P00000NkvXXu0mjfLewm|

diff --git a/lib/images/toolbar/fonth4.png b/lib/images/toolbar/fonth4.png
deleted file mode 100644
index 1e7ac84c677fb7139730177a82dc5c86a710b847..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 687
zcmV;g0#N;lP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3labT3lag+-G2N4000McNliru)dmO<E)FzGeJB6`0z64X
zK~zY`)s?$y8$lF?znL9YZh{0tt15zE5CW4b>E*&iwJH}j<OPymFQ6B2lRSWeaH}$n
zT0ts75_ck47pt(m!bp~N+es16qP?Ibwo>H4*&Y6!{m+>*|Cs@BfHOev$Ugut00|&~
zv&+lN_sL`uAq2+$W^CT;^_sz8Kt7-U1iS;r0?^~}7}s?Po0JkEM8JQCd7ei)od$Rb
ze3gc17vw?+lv0Mm!PIG2<i;ON`H#)IK7~B45^7hO8!S?dFnKPQV}E}?@KY|ABb&`e
z$WKpCNu^R`GMTs%5hzjk<0erYR<GA-Hk$#-Ze2lm!p+T%@8LQ9exFLELbY0re2WXB
zr_-tK^?JJB?{Do=*LAh)y1G~_>Z7A0J()~2pl#dMv)N3~=W~63e{bf$32gGF3Y1dR
z>vcb)<Ktsis}({B&d<+jwOTY94LY69uMD-O)9Lto7ptO86-X&LJUsL<6IcjAx7%et
zpHnK8e3IpI$-%(^S65f2iyyzq<#L%qq2LERIXOWoMXgpNnM_7{K>&I-n{j)4ix2|G
zaj<Qh;c(~&a2$ulV!>oGiD*BONMPGGcXxMwGL~fllz`7Ftb);K6ltP3%&c&^Tm~?$
zbyTL0?b^6wBD~4+U!6gL0E@)}DW&h0Wno#?A7Nqg(P(6buS|fC7Z(?Jp2yza9!e>n
zY?E-yvFw}cy0qJEfbYN;gJ*%-4)5e|z+2$8k*Nfp0nZ<9A;r_o1IEA);F|y5egYC{
V<+F}6<-Py_002ovPDHLkV1k8SGTi_G

diff --git a/lib/images/toolbar/fonth5.png b/lib/images/toolbar/fonth5.png
deleted file mode 100644
index 5a1edb14cacedb8aa19c1849bfb39a9317245cff..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 674
zcmV;T0$u%yP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3labT3lag+-G2N4000McNliru)dmO<E-2<l_|*Ua0xwBK
zK~zY`)s??*8Zi{dKQ<OhBGB<e3bz!gip18bfcOiVfgxj*sZ+M{mmo1@X&I4Pv4uS=
zW2Z!IS*r*TL*Wi0M1sP(3qBnOqD?}FKIz@rU*CQG-q+7Iz#(t}=pFe-;58rt1aNVC
zdt0$A3n2u?p3*k&#bQCf-zS&LeE~iIt^l;_x;TzQ*rb#QAy)iPnCE$<(`kS=z&B}#
zc0n$LKq+M?4lz3Iiro0pl>Z3o`V#U@N~m2$Zm=~q!sOX(mZPJim7lWNESXHk$I|IE
zsZ@$&GD#wlz_KhFjYe1^RwN1!2BQpP07@z9^|~)hp-|YEfeO}i@PpB4w1x%yQcB9@
zGD<1-_xCqOZ%j|8Q{C-$b+6akx=S6$(XQ*R;l*N6-`w2jhldA!e}8ZAcWW7#bd^#x
zn@vBe)6-KPA0PdGrBWfE&vS5az~$v7&1RGH^K;tm_FD8}nE{i@1R(^rZ4-?~>GgWP
z=C*A!pU)YO$7>ZdnM|;4n|M6VXf#4=O*9$>I0mkswa6zYCzQ)&VzC&lRttbqsr0le
z+J;${MYURGFc^?XBse=eqgJbJTx0?0*=)w$-QBY`Rv6P-o3%U!u4FK>T^tkPEabmB
zgH|S(&*w-feUC&UL?V&D!ouXk;m|bSnh8F2IvqUEV{dN{rIb$=B;0Z=`{p<f*Voqo
zKY*_W&j6oycqe}c-UE44MG}Yuua>uv;$`LmF7Olh#eZ+V0Zp3FiZuh((EtDd07*qo
IM6N<$f;0sw8~^|S

diff --git a/lib/images/toolbar/h1.png b/lib/images/toolbar/h1.png
new file mode 100644
index 0000000000000000000000000000000000000000..ffee5c159fb8180920a04249b72fc64b31450cd5
GIT binary patch
literal 429
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL
zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+AuIM+IzY<hE&{2`t$$4J+mr<Lc<IR
z4HgDQmyL{2;s}${p~Huz8>g6c{Qds^{?+VjYa(C1eJlI#_xJY~;`i4X{`vFs^Q(`K
zkH0Q0DY0qD`F?wQzW5;?1`Y+b0EMQ4h=?1TA3S(qYGB84`}Xbi8#ipIU`xu*&W>KW
zV#S(?lP6cVtzlDWco4^M>&%De=jBD7Gv+2U>||hB7qhd7=Y$=fkTV+t;}NFh1{3DF
zI<KES3*#v@^VqDji7kaW5$M_nYz(H&A0Ef<F8g}uNJHH=maIvwA01~ozM8=3z+k8-
z-H>Ost2e+q;0gnafbgc5Fa9};GiSQ-t2Zztv9vB}Zgy4<SZEe<I4hxH?Ud=$`Pnx)
zFFd!8>&W$nS$7*7&$3_nF46J3p-P^aML>CJC8I)vhF>Rg;IJ_)e|EiIM$|b97~Tw?
Lu6{1-oD!M<Q?aSI

literal 0
HcmV?d00001

diff --git a/lib/images/toolbar/h2.png b/lib/images/toolbar/h2.png
new file mode 100644
index 0000000000000000000000000000000000000000..a2cc7f253ad4cdc5187d58d9b7654432ad839991
GIT binary patch
literal 500
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL
zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+AuIMwt2cZhE&{2`t$$4J+mr<Lc<IR
z4HgDQmyL{2;s}${p~Huz8>g6c{Qds^{?+VjYa(C1eJlI#_xJY~;`i4X{`vFsv(|(-
z)+ODIGx$%;`~2bIVOfQ*42(xOxLp<~o^P1d&uH3yz^A;RAma1S&*|C<mt|HI@(R3X
z$lCVn-{0Ne=G)hwxxcsiyM#hRL_$~NEXjr@jdRRd2|qqOWM)=ZUoJX9w&?e_x5tHq
zgu)!0uQ6Ob%{0}9jYDAvqrzDS_0zj{?i6*NdzN8IDp2dXn4O!1mhowXv0VAXx#AmF
z2fu(r0doVB!k>!k>tgpB7|P1ZdM|L?WUz0-gaG@H*bn{k_I8a&7??UZZ!%0c`y#HP
z)6q1Zxy_T~!q$FCNy&q3%q#-JlP({Sn!xDs=JoaU3TML{&dzgqbMDX~rceL#BGxbh
z<xRFoH_qyBG+~%4%O^B>`gDGF$sh0U?@xB<)l{%=KEx?<!=XS_qWVDw3x|T6*JmaN
nhQK*Oj7%L#%s`7l1P{aYP4DO3O|`xTj5Y>OS3j3^P6<r_lfuV^

literal 0
HcmV?d00001

diff --git a/lib/images/toolbar/h3.png b/lib/images/toolbar/h3.png
new file mode 100644
index 0000000000000000000000000000000000000000..accdaf652d31f49e58c9d1422801c358d5531f63
GIT binary patch
literal 501
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL
zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+AuIMwtKobhE&{2`t$$4J+mr<Lc<IR
z4HgDQmyL{2;s}${p~Huz8>g6c{Qds^{?+VjYa(C1eJlI#_xJY~;`i4X{`vFsv(|(-
z)+ODIGx$%;`~2bIVOfQ*42(xOxLp<~o^P1d&uH3yz^A;RAcFZyLg}9$g_^RmbMHEQ
zGhC3St+4j*qodrK6Qmj#nyMLB%zSu$zP-jdW~~&4oeZb^cGdnavjrM0vYRWIS-?TZ
zfX&1B!pTi}d3i?z(wj|AH)RMgbb5Mttoixv?QGEtSN9s!0_|n^#KciuS!r8bS{lpz
zxOv02ZQrCsMW?14>|3y4fet_a`Mk2SZ|P^woRL#71Y4V7eP`#1IEGssn<Aq<JT$)E
z-Cf?__-c~FJ=Uax1<Wi0ceoAGm6<0<oM3QsbK_UoJ)^n#vDSsv@(UU3Wn36o1T4fF
z7T)FHid><%dVS2!O+j&Sb}}c}+?6kcO*lKhVODCRSv||E+niU}``j8Bl9rh01N9u$
k6jW%?FariSh&aIDq4|&dT7$?VV7xJSy85}Sb4q9e0DGLpS^xk5

literal 0
HcmV?d00001

diff --git a/lib/images/toolbar/h4.png b/lib/images/toolbar/h4.png
new file mode 100644
index 0000000000000000000000000000000000000000..8e57676885b7c73609f18d7007cdf5b7c65115b4
GIT binary patch
literal 461
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL
zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+AuIM#(TOrhE&{2`t$$4J+mr<Lc<IR
z4HgDQmyL{2;s}${p~Huz8>g6s<b3r~-~fXEe}9*22pIqQ_4W0uMrQU`j+3mctTx%#
z|MS^d``c^=zkmbJ0tc3d8#Zi6ci6*rj6E?t{JQD4Z{N-*)a2&o+KGxzy<1dNR8Y#m
z*z%}#fBpYO7W^5;%oofo<WJ0F5P9q@#>}B0mU6cK-=B$JzkSndvyxuoDCW}KuxeG7
z{RCTfjW8BrX2u4FCTWH%XBe*hsCa#C?Op@J<mBYj{PK1um`tM?O)H&vuP{a)IC${l
zkH^RRtH6qdSQ1khinRhRiz--irWgnKDtpLYI25X2*}&jr$Z#{$fZ0K>`p1Wd>I&Z_
zJa{rbyHAi1h-dxC$iyMjk(Za(>u~nCgH*#gzV=_1GE#iUTUuJAChn;cm52*ZtZ86K
sT4JKlz#?!|Q&6En!weXZAmRXnm)rw><LK6#!1!SBboFyt=akR{0JN*6!T<mO

literal 0
HcmV?d00001

diff --git a/lib/images/toolbar/h5.png b/lib/images/toolbar/h5.png
new file mode 100644
index 0000000000000000000000000000000000000000..8fe10e99f0b159fa3cd6756c95ff7a6f3aee018a
GIT binary patch
literal 478
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL
zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+AuIM7I?ZihE&{2`t$$4J+mr<Lc<IR
z4HgDQmyL{2;s}${p~Huz8>g6c{Qds^{?+VjYa(C1eJlI#_xJY~;`i4X{`vFsv(}Vr
zY)Nby)#tj!^~)Go1a7cuhp$`19u($qmPg^N!p61H+t;;dZLzBRQ(-$RO`w)%37<kk
zM1mh<=D*L+`MW+RNG-^zQ>Yf5aF21zPeUJG2Zn>Z44G_Jk=M?iT`O@?EK-1%$zj{K
z?fLhm8ed6OR#t}B{rj_1K!s1hp@6wzmgA3)>tc6TB_>%}Sxs|bPH}wG&M)u9$;p|?
z%=>|1m3CTUq9tR>dKL}^5$1$*uHTq0gs}l-a~H^XJkD8gcCW)(BM1G{4Of6Jw~<Ob
z=f<XBIDt{&tV0Zs$pJ2@IE8Ro_Kl289fDJ)$jZn_IWFWeP5C-iJ3Q>v>C^4ZHy>oM
zRPsJ?S}^%%<19zU3Yiu8>?ar+7?PHl=mQNrswt?@pkW3KSrBo6Az(MtmYCxcnt&0+
N;OXk;vd$@?2>|D1uGIhl

literal 0
HcmV?d00001

diff --git a/lib/images/toolbar/hr.png b/lib/images/toolbar/hr.png
new file mode 100644
index 0000000000000000000000000000000000000000..6d68d66aafc2ec82c3c615cf54b61f62976f97e0
GIT binary patch
literal 372
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL
zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+AuIMvU$2VhE&{2`t$$4J+mr<Lc<IR
z4HgE*BTUI5At49me)|4CzAb)#o#CG!ADbWE-kzWE=j-cmgMXi%a?jXT`dUocL)U@9
zFz6L)14Gm91zWa!u~&>vd=y}sAkM%da8!?hLtzJZQgZVD#~Z)uU${2e;g-~0h6aX3
zH&_`MS;`!L9}BNeZHb(_LG#D&@Ail1*Z-HOV}5ymzhuLg__q1=5)$id{%y;TTsO(s
zfuWI?Aye#e^Y6BY_xJzjssG<-!t_zzO@a5)i31<npUO`-%VZYfHGwxr(ShM$scrp#
z>D9jb8+X++^Zxk!T>gea34?%xNIRngL*Se#j7%L#%nV2b55tw0JIkJTmDB@+jlt8^
K&t;ucLK6VoERu2n

literal 0
HcmV?d00001

diff --git a/lib/images/toolbar/image.png b/lib/images/toolbar/image.png
index ed35e5a6292b493b84a6f9f66ac31b0edb0a2d66..d1416fae90fefa907aa45b6eda2bdf9995753957 100644
GIT binary patch
literal 680
zcmV;Z0$2TsP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt006JZ
zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!I!Q!9RCwBA
z{Qv(y10?_;fLQjln&UL#-@pH0{1=G-{Qbx97l=XhpFbcPA_fqE!!fo200v>0h5AJ=
z=+^&F=*B^W0;}a%SuO5+Pz2PQd6Y(1b5Jn})u^2gqT(3-oG*aD2K@W`hvCDMmki(E
ze<I3eUVc6XaVZI~7(f7l4fqcf1Zm#wa*_e;00ssK4Z}cwom3$M52qZ+c!v26vlv9h
z#J~mv1P~M0MrbJP{WcAVr!xFxya}|Of#DAn{|0*H_&a@uf8Q?wz4Hrf^M7a<00a;d
z#LW<A8w%V9YF^E-?`t~4?|&bF3V@pb01W}+OFvy1w!gAu`1Iv2*k)j`fV~J1KoA!|
z4fq2L3lm;_pn|^)hkp1o{ARcXF$9QjevxL_@F9(%=-wQ-3qX1R0*D11U_e#i0Q>iw
z;p(SL3_j8#49~v)VED@H!|?920fXSb5QfLEtQo%ikN~P>X3zuc`3E)tAb{WofK1gF
zdBdP9EXg3np~9fY4^;49kKqyTEuasVF{nx}0n(6Y{<jYpLm;OC0YCt;`~@5EAM7u2
zc155jU{wA81*U;A43ZpjkhB0~gCL0g@!ut|7eD|YfLK5_{{wP3xOo_U^lk=A{DsFk
zA`Se7rVS7l5fEU2<p6*HVgV^&_|M3|FDSym$0r01P!Q0JDq;BgWIH&DI7G}Ct}LDl
zG#un_a57|IWQ0T@KmakWEY<ywoVM}Vj12$;5F@3z5g>q=7$^h)0R{kH8==1u$dil!
O0000<MNUMnLSTaa{2J5%

literal 1010
zcmV<O0}cF%P)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY9>M?s9>M``&~-il000McNliru)d>p~I3kQBUdR9d1Aj?G
zK~zY`t(8q^TvZgufA3``nvgD<%*w1vBSdB)bm78H!JSeSYy2uBww0kF6A_F;UAQuW
zg4QllB%nqmWZ6YT!KJ!#BV>@t(AbWdSQ00h%=dfme!CblOg=`d=^qaF!8z~z&-veb
z?qzFh%Vjbd2izA+r_(N<&pRQ6v(`E?nT#tIi>_X;@3Tgu(XnQ;*|Aou)v+K5To42<
z3_}-&p=&mqZf$MNrBW$ZDwUiN!g+wJR;yGh6+F*7wi#m>85tp$%P~4SN({jF{Z7Dl
zziiPBtqnqIgj7V4A{3G^l0=b0NQICZtqos&@B*Ia5sSqDsMTsD5{Whe&>;XwpMQ*A
zkQyT82qgr<(Gu{=<oo;n2T)33t;O$7-W_lhYWY0H$un$DpJ6wjqb1<C{5saTo;m!Z
zI_OpT_Qw|(pZ$=BUwZ;^?HtVrv{qQly%T6{ddgy~L*Dv<?5|mrbp*npq`+F&NqmqX
zc2FWAbx+Ohl|{1G&Y`U1uZzog5|oTE*7a0j-zHmY5mI%Ww~Hm_7ncEedE$BcA9{pn
z_BMfVc(P5bWP~;j-}nE$gZ}=0qNq(!+}ve;ahd7M6SM-&^vpZFdMU%=*Pj7!;nEBP
zCr_iL=ycGNpu2-mNQ#@g%q`sH?a3FhHqN#%OijPVHw!nId1H!rJjRn}$C>|r2c-nY
z^p<GfCi}im7)j<9ZgO?%C58qbq|%b)3ROIRkf)!$$ma`RQY!6m{flq8@>Bw?WJjXC
zfjvaf%^XFFkKVnEAAf+mJA##bnQB8&*x02RYEF$m&Zl!XC=?1zUHydj-aOwqMSDda
zNwBvHsi-z3>vtRE?(DK%jgTTD3Y(O6%4lUdb^1|${P`#TSYPMtGp}Q8??F3sRS2mm
zR|U83{K@Yd4Wx(=QHvmG61Exy%{oR2PMjE~xLyFj+QdH-bUU>+JU4kA>m1gCwe11Z
zro9@|{<d})V^6kY+<)j`VRqtJ*Y!d808+~P@)mfWN4Z?y-$6Q^W_5Lyv9U1*2M006
z9IEJEE3Q;3tgNh%OeX2;>udWrHa1);mAY?lax$58OG`^Go6WjPrQ$pxgsa!<Y;SK<
ztJTn2<DBFFA{L7=G&Dpakzjau7|&Yklu|@dgp?9v499`*`^4jM1_lO*$K!Z=)w(v0
gRsF#e>3N>_HzQPS`442mtN;K207*qoM6N<$g0J<|&j0`b

diff --git a/lib/images/toolbar/italic.png b/lib/images/toolbar/italic.png
index f4ecd0ddf2d8dad6ed2f6a9ad346510424b520d2..ab8943b458cfc69285fdbd7eb5b6d7ae49ffb6cd 100644
GIT binary patch
literal 363
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL
zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+5i>(^>lFzskoK&=l_3uW>p4-h8YqX
zEDVe;8yOiGk2LuksjDx4czu05>;C%x&;I}X{M=pP_n}#)*)kKZGO!3JFEr@r@2_Vt
zark$<U%vD8wYAX=di(+o6}%n2y`~IVcKlcV6drElWx8<%s5(xc!Bp+f@9+H&e}8{3
zU9ggoL&1rS<<H;W;_HEywOr=Dckf=pb7s?eo0=aR81$GKm^ji+m`v3gc>aHTdz-Ch
z9Setom<=0?!`{a03=Is2Ua=Mz7qc(;@$dY6d*hh>b#n#hgUm^6Sh+Hj+2EoDgCR2q
zv+()$^z-vr9~c3>CZT!O2k5oJI0g=dE?x!>1BRV??Vfe*+Q4vNVDNPHb6Mw<&;$Ts
C%7KCa

literal 676
zcmV;V0$crwP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x0$E8!K~#9!t(DJe8c`I+fA`MVR!CZj)@}?!94QnEK0zNtsLQysWK&$k
zje$S}w;^uYWhG1ZK7bFPR057>5iGMvt=5dFv7_Cn7#;s5`QR|az2~0qe&<}y0eA;o
z0HbHJZ@_!t1t0`)adUI?#pQA_3n9eD|C6s}Sr~>vFc{1NUxB{@7`0k0TCLX9d6lj6
z84icI-EM#nz%L0PrCb|$V(WZWRh<ZY1H6>8a@QTM*X!)>@8k7)snu#LRRRt`%6ZAF
zNY2jAa5|j;Twh<WBLLumf>k7?Qi)tHM>HD6>2yAgz>ehP<b<7_9b&N<9*>7=wYpU8
z0>Qe%=JR<9g#xiyjJ>@*d_Lc_26iMHDVQ9#EQ{0AQ#>9IM@L5pAvicVpjxdiRlAjf
zY&J`!QXw9Xv%9;C5CTopFbsokw`)tXv4T#gLpq(t@Aq?fcsO0xG!0<sQ=Nsnis1bG
zoZH)50K8r=^QhHoghHXE!B?ipFbp!84B>E?cDv2p-5sWBVwxuHb{kby(RJOnZVL)#
zHztm$REmDTPa=_6xS^`5`2GF|h2A(t0OfL-%gak5kqDZm*#-y%0=5d4z9K0lQc4s>
zA(>1frR4bdc)C7oilPt<2GMnWVQ-#50Ha>7N59|Ssx903&CQ8VKt%<(zrTM}@3%`y
zqtRGM(f6yXD+YrB4u@l_-aj9_*=$lQ76HnDH6Ee(fFI8|lYauAfscSojED1U;O%${
zspHx_7XJVf_znCK<6sWp)tF4-X&3?npbHGd+=~)Vy!`~zl>G<1EZw4CLifi20000<
KMNUMnLSTZ&Eiy9z

diff --git a/lib/images/toolbar/link.png b/lib/images/toolbar/link.png
index 99cb40051814913c61dd1a149dd4481b1d2f8013..453f0d3f1263b636d8733c3ce59fa5b63ae2a73c 100644
GIT binary patch
literal 574
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL
zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+AuIMUhs5r45_%4^ymM7duCMzg@zdt
z8Y~QqE*lx4#1W?C8@F#4zkcx|#nan6+{??0>)!72_ZQpw<qtIk@w2k9^l333{QUg<
zef!#9TmGJ!s(qPH&gO^c5`Kk-18fq~(wjX!J+H1_y?T0Ed%JPX-(OQ5BO@c<9cW}e
zUH|vjR~0j}uvx9Gt&ABB4{mNw-z{fbrNVV3m^tM?6NkbE#sf1xFl6}^7Zz5=2Lu#6
z0$P*jz&x|Gv{bZlmPmC~mBc*T>TlDhPcIL5aA+{|(7mAQ-VkNZ$Rcoq!OhK0x~{J7
zTkY>}qBZ~j)qb3=A0OxD;_`umi_3`NCeQl#{b@5yGB1@c&~|Eg6S3eHr-H2lGXoPx
z&Vl#$_rGWM{iCR)bm;V%GkfNBc6RRFym@lt?Ag*Xb_)89M;wYA_DC-gTf(lwF5r;B
z{O`}tVulw-#Iv%pt~$*A&zPH3`}33P;kD7*C2rijDf#5-Q^_Mok484W@{zNz%V7)R
zzQlZqTfm`b!4!@!!o~(qN*m4AvHyw{S<xveay0+m9#7Uw{*8Lk{7WM1fkun3_-T5<
zwei4)oi(4Io!!sCc*G+!h>b&`OIXN(AuxvliD+PC@ZP`g$rR3ITY(9H!PC{xWt~$(
F695j`>e>JR

literal 842
zcmV-Q1GW5#P)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY9>M?s9>M``&~-il000McNliru)d>p~HyOIOt0Mpa0@q1I
zK~zY`t(Ch<D^V1NzuB1-kwCzN1QY~`q%c+%Lc~0PAo>C+Y+{oKkbqB+Cs2fdjhz;v
zRu&o%3qkNMq%#(S7h<mC<TC3N;$TdU$IJQQXNtA>|F!m7dk=<TNGg>Q;J+}LOv=s8
zjaZf?wrvZkR7!4dZ>3x=cd$~aIILEy4r{fV!+O0g^?F@Q(-hM*rCO~@KA)FFA|dzp
z_hMO=Xn;IFKT|9g(KPMXY`5F^{eG^lt{5B~L<dkxeM_WLsj#xLf~IKz&Nm*9Gc`2@
zK&ezB5D2^)yd`~=mzS4hG8sO?<M9xW#{p<Io7lFE`mVU9X%q?tdLbMRJKelN{iK7#
z!^55i6B84^H+Xz}WMgBaOFR~fF)%RD+u);!%jH5T#p>!RcXxLkv2;3(Wm#PY^Yimg
z&R;tKaJgIntgWrFw6x^JY};mWagoi<%`Wlr@o^G~M2F5B^!FXSiEnRjlTN1rI5|1t
z=;(;$<z>##&%4BZJ|Ed^mXC$Lhtz5{F$_Zt!;ow?E4r?K=~?i4y|TBr=iF@5G{v$k
z0VJ2piD4MhaYP3P2P`Zs&}y~#7sBB%`}_OEVlk9b&fGp7^4QoI!^6X$3j2IMGMNm=
z$H$D0j&{8QN~zv600;(yY;A2ZJ3C80p9f%WZVs>4i{I~OdU~44$w_ow|8$k#Lj%M#
zO{&#u$F9%J%#hFLxwyDsXlUrm_e3d$Qi@zIM<f#IeGh`cAUiudL?V$Ny{KJB)XO9k
z3bDJpi^t>nvAAQ<Xf%2zheDxmSO4_%)M=1RCb_=8W@Kc9zP>)%?RHm1U#+-UEOL5!
zN;De9<#N5o3x$Ft5{duzPmV^TvcA49XJ=<pEEYwxEKADeG7k?Alu9L9trjA}Poe8N
zUayxxAV7bAKbmdZ(rh+)d3mAHXwYuA`3;m(xZQ3%9uID}8||%HdBv})@3E2EALpc;
U8nCk_qW}N^07*qoM6N<$f`+SrNdN!<

diff --git a/lib/images/toolbar/linkextern.png b/lib/images/toolbar/linkextern.png
new file mode 100644
index 0000000000000000000000000000000000000000..780c335334d8201a0bc7bd4b0e0409ea5f0d5f9c
GIT binary patch
literal 1138
zcmXApYfMuI6vq!OlnR#=f=aL5prLN+z!utUvIt!203|xh)C{(Wwm@M^WHLtvI$m|l
zwMsA$A1K<@O)`ltfcRjON0Ey>9JJ2O*dYTdLV5R6DQ)4lcU}B&&OhhF`JMbf{Lkss
zy*mT^HuwQRK+3MfeI5<`zt}8K4|`23JmQ@z{a6an*tgB+%(Q1l3zE_c_8-kDC{!F%
zf;9VRrjnnMr^r?AQ!28Lf8DQ)_3U`3BuWny4P{a^jWNZ2SZ%g{-7%GMtvX3{$w!Sb
z7W--1ExVGvz09}yL^)*sfWqJGeZPVFqhe)-(dWY?G`?g!$FW?YG8sn0kTUKe@mxuV
z%P@+S71GYv+m1At&xrUX;N|@R)L&lLH*z%m=e+rMXZy%$-|d79Ka3Q{M~j<Wxw%EF
z^I-&y>9{dyM|3QG{E}(lj-<v-xwBd#3y7Vb+b17ntE!u7?^T{(L$vC2+)_!jm~s-`
zq>IB#_2&_-+Bu}LG+!L+?0d}b&FYbd|I}cgHCrb5mEhG)jo7LKsus?C`dZOpwMP)&
z;1*<*b}1az?|tj5*G+9;;V)#Eq?lT{pvoY(G6i%V%ReXpZ-2gb%hvec$HEgpbue{G
zsMN2_^rqp41g+b(sf)jqR&E;NCF6E2$`!^_17w9Oj#*(<;`Xjww1F<^$)BGP;Q1Mw
za;`-*1B1Ob|Ci?Cr$|UgTvpNG!|rR3ejOk=UpyhwJboyLzEiZQHJy7R#JAJ&QBf3S
z;FG5`rsY{JBJ@i}bY<>8ec1deudaiU!w5&kYFlwus%mzhHW8vjxZOfWlND}xU@+A~
zt~7cPH?$$BkuJ+|P?KAUR?a~r_G+7l;R*saf4w|1O3cWzJ~zk^8qG%2(`oS$Z1IY!
z`rIj#Q-dLUXeYNWQ70iw?<*ZkOWOzzE=j1gqulb_cC#TYxg0<W9kjQLaxYj{th``m
zAOx^QV484)m&phMn1i?02ZOQO3{PP*tTHGNxu3!2PytL%v!S1O4sIuHWxT;qtCW6h
z;U#aQ-`mhSL4d7i3B+r7kd~GKHk%CuuU>&S(GRv&fWzqrfX(s&v)K%TgM+{^2RYwh
zn8LIz^Ur2RKij=AmZ58HhoBh*_Q*bg(yA-abmKaVj*fsJln2hmS?FkQhnu%<f@RqZ
z(zqnByd-@X>Mwt^KhEf!GTxsZlCnlxt|C+$HFo|Txv8I=@0H<dHJiob@mMmMjK$$_
z@Gwj#iMmCX*PBA*3^qSC60VOI4yay)oK;7W)6s3EYc5jXW(t_&bQz-2XprIIVR>{_
zP5BNaqy=+NY94mlmZtv-^901OCv?B2NEhe2eZkUjt@6%2|Lb?}MlvIUCBz>!BJ`_&
zA3W;R>-Bt*$iNp0_2jC-!jXkyikSSdPJd5467~9-nVEsiv*FHIk>m5a?z$M`KSmTq
zxoCsrkc+HwT1qt7iCVtfpvCC;@0RD@f0CpEFBTMCu6MBO-`nMR8jzB-H?d)d{N#U4
CI~+>@

literal 0
HcmV?d00001

diff --git a/lib/images/toolbar/list.png b/lib/images/toolbar/list.png
deleted file mode 100644
index ffae5cfbfcb1b1dc6c9154b39ffc577ddb5aee62..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 582
zcmV-M0=fN(P)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x0sBcrK~#9!t(DEH+E5gQzmvw^Drf~Mchad83VnsXN1wn!XB`Pf1;sy{
z-cd7>cJ8wXElP(%5fiPc5gJX^PI7YdV|uT8HyjcUD`)Su*V;J%x4<26e4_Okcmq5K
zgaGcQ)9J^2K2I=&5RZPB&;5SSY&N4<EPe$(0lx)sv@8qDvV8FW)<c-X;Xt8K0C)@h
zQ~(r3@d2i3((m^Z4+vsUEmc(|!I!{|8l-EQCWFBsR%N%_jkP1%qH47oVhN-GMF2<J
zwy`YB2lRS9%H{IKt;%Mz0PlexAqGjS)9J(*M48lTwI~AsP9~7L$o)#Ck|^jYO+s!2
zj+@Pf^?IGy23^-#EEX{avg&AonM}rSk)Ob}?Tc)A3YSi&!x~)c{V4814K7V`DuEJB
zFquqfx7!$oan^tZF);=~&~P|J(==MGmOnhrW)mR<xm?aSLsalaqmgV=nH@mWGz`NC
zv8vbWXSXU*gZX@puIrRaC4Wy=m-MTU3=`+TaU2}S@!KIk4p#nH;RA{9=fH6sw%hI1
z{*N%bpM%|QceVdzESJleP4)43jO)6jQmM188I09x#b`7F_zvv7E0ov3mnXcFzX2bB
zcR*fvmvaty<=sN6C;p}J7uWy`;Fs_YO93yuWY4%R4uA{%0bCKWthlmz8Gg(D0dVul
U((WQ-3;+NC07*qoM6N<$g0Ptd=Kufz

diff --git a/lib/images/toolbar/list_ul.png b/lib/images/toolbar/list_ul.png
deleted file mode 100644
index b86bcef7d805962e9f4ba46060f7f6ec7048dd32..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 560
zcmV-00?+-4P)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x0p&?VK~#9!t(DKJ+E5UOzlpJ}2v(5NO}A1gc9RF_R@ZUWXXvg=K^KaD
z9^kIpWxLM<_z+QO33MqGH?`&((O{}}lZ2SW>($(WLz2T}=6v%T&H%gy?ttSHtuMe^
z;29tS+|6dQPvvr%sENp<--G9Vzh^$5Q>|9N1D}C=0gkq9W7~G<{Ls4Ob2uERR4M@P
zfZqy$q9_*w2kVlrs;U9tOW?U0#T608<1wabqG=lSdL0pAG#Vw!5ie1@-9DiN@_?eo
zktdT0B7$j}G#U*=gjTC{RjHzuAkZ`|Bnb9~!(oCTPSWXgQWFSpbR37(YIT#KfhJLH
zip3(p2jG`_2~|WG3<jwL!Kvdh5(Mk@8pm;NYRfdgLZR?Df?Jb3C~}r0nG#%+B#|KM
zU|AN1VW8_ewOS1kq1WpnB9uy{u-oE-ce~y5B5$`_Hk%Cq{eC}miuU$36uDgPROIMS
zx~^jw2F+$O+zU>3?y3j~&l0$<i|e|XS~ErHbb>5N(o6-|?RJ^_Kd{AOaq_JIUoFeR
z^E~qT{8e{<Jos|CWICM!`~>#?2;~j%?Fnb{58xy49w>`HoJ+tfe+sF-__x|WU=92M
y{)!(g54`Y`<;Z3Szyr2`C$W~5jHeGQEZKj&6|;0sYGoS$0000<MNUMnLSTaFZT~|6

diff --git a/lib/images/toolbar/mono.png b/lib/images/toolbar/mono.png
new file mode 100644
index 0000000000000000000000000000000000000000..dd398411ec1cfdfe9e59af03098fa3994a3bf0b6
GIT binary patch
literal 426
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL
zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+AuIM+IYG+hE&{2`t$$4J+mr<Lc<IR
z4HgDQmyL{2;s}$HmX;Qu!%y*s8xPLUx96|>`%Cr1=jZ<B3Uyx}AMfYAzrWs`;Ss;W
zpSQQo*%e|7-rm~E%fQG|+{hpx&hU|K0bBKgXY7;Je7P7l?PoI0kKCB#${4`REWj;e
zS7X8Gq0b=6afw5~!GKxH%F0TQAvcX73y4^_nM}i(MZY!NP+)E_Yd+d&X3p@`VO=T%
zhr$N&hFRtf857b3{{8)J9-(;QS){@KCX;5K#>VI8=Qn?4U=iRhYG}xDD`PZjsA6=M
zQD`vWVX)%u*(llI3*-bW5?sQN!eKVMp@`{544Z(1PsTPChQCz;B8QG0JH}^F=;?Wq
zX~8po1?GszNbU(B^OToXGAcA^_;n(O3>(8Y$75S!lakbcfz9CQ>gTe~DWM4f4}Xda

literal 0
HcmV?d00001

diff --git a/lib/images/toolbar/ol.png b/lib/images/toolbar/ol.png
new file mode 100644
index 0000000000000000000000000000000000000000..91ce32b9d8108a07c9ae2d589f55a2ea213233a7
GIT binary patch
literal 435
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL
zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+AuIMx_Y`ehE&{2`t$$4J+mr<Lc<IP
zmv>F-THXD7)K9B4Ffd6cEIU*?J4T#=MS#1bW2<0_OPQmqtE<_BS)abYk8iWD|7Y;$
z-{08}udk0!`1Sn!{Dg0_OtU2%vly8=1Vz{i&i-#`yUA%Z=@C-{L(&ox0Y)Z{H?5WI
z_x}F>{aya>zSZ+Xr$5)cr+AbBXcc?Xq-KG~@4DxQ`cC!a_W_FRR@m`-UDr;w?{Agz
z4LAIM{P^+aMn+Rsk%SXJj`zzKd^<ba{2<UK4jHz$(s6(O^L{y$pP*pY?ln=QgMrbd
zP=Sd>;0Cwo>G^;Dvzt7Zzrbp1Xr!_e=*a_(Hv}~gb6l!<^rbp9D3(FMLC1j2V{_|D
z1r0HY-rioYEz@2(m=tBPEcH`h+bsgrlNhk+38#gE-~9hKDmR4hZV~~7$<am*fdq#A
XJgZ+lI3u_S80rk3u6{1-oD!M<qiU(m

literal 0
HcmV?d00001

diff --git a/lib/images/toolbar/rule.png b/lib/images/toolbar/rule.png
deleted file mode 100644
index 3a32bef348424c2b55213ba5843ca740e96b6cd4..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 565
zcmV-50?Pe~P)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY9>M?s9>M``&~-il000McNliru)d>p~I1EtoQwIP50m4Z{
zK~zY`wN<f>f<O>`yFj6_Qaf8aJ^@Yq5Lzle#sBb6C@i&56FY5;#vq8`g1d8tfgC62
zoe^I$1z~t^X7<g3-EK#&>k@!k!f_m0tyUz2Af*(+bzRzQHWY?oDbD9}5m6Ksak*TI
zh~t>zIHn{?C`l5EqKMY(HQBaJ`~9AT5X1n`>2!kc`(TW{9a2hkIvp$)3-o$DZ~)+(
z*Fw%1gRbiUfFKAUguwj?s7)Y8mSs>%-396*|1OZ@V;$t+bqeG>4;}nW)HJP>^cxuw
zfr#!zx?b5uX+!`polfC-Ub#)qOF4|Of*1fsqY;L~;olu-ng-AFFdmQb3N%f7E|9-a
zO2M+Mhs3HG6HzhBoIKyBr!KNA3xmPnp~9bMkdLiuQGXrLUk6*|m}kO;O`m=6?k@1U
z7p+pDPV$d;P<d6PX<D1W@pvq|$Z;GjmrL~feKea*NGbp2ma2+<-^Xk=gK3(DwXxl9
z$+qp<{>i3k(quBB`Fu{k?-LV3P#A_d91aMA0Jqz%bkDpBUDwfSwb1Q$(QdcFlv0#s
z8LrnW(lmvX67PU>4#P0eXf$9L23TG#-SJlS6^>+I74RI6Z;0w600000NkvXXu0mjf
DGMx3C

diff --git a/lib/images/toolbar/sig.png b/lib/images/toolbar/sig.png
index 3e8079f4931c3f1426655d99d66e7e4404272203..e4aa2943c06090d7e7ffddee2eee8a63056b2199 100644
GIT binary patch
literal 606
zcmV-k0-^nhP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt006JZ
zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz@JU2LRCwBA
z{Qv(y10?_;fS4F41ONfV0%KHERG>KJ+qZ8FpFVwJc>n%A!@GCy7~Z~p3ugcP$HMTJ
ziJjr&^E-?nbpQdxNQxJt=RXkzQU`%p9Efd~Cdym`2q3rtFc;vn**bqQgNvCq1LMEH
z3<qv}c=PkecYA;UBFY6Yn@yxyH1#Cd7(Raf!*J@(JBA}ypKJmMAb1$$<>i%Pv-v-l
z7`H{%yi6NS2{Dl7GdDjmi1D#8Jb(F~;p6MKUjPCKrwe}VWt4dKL(%=xXN%rvT<OB9
z3c7I3drseBIDPfr-rqld`T_(HRs(>Vz5laFZ28Y?$-u;K$?)Y$Bg3v=6Bxepc`@ub
zeuLrE#oK%T{Qm9xcuUTAfB?dp4*vdOU;}ApQ!8X(;p1oEF`3I?|0j##=9y&-$Ie`X
zYX+$W2q3Hm00WuxKLaPj|L>O>{(m{nz{38Efm1o1f$hWo+dyf!W)J`fAgl)b`NP2T
zkCBJr`*&`Jf2@`aKR*6t`1RoqL!kVj5@gLF01!YdIJ{u+^64!Gp{EBKKD@hm;qPyT
z%RsT$?7ta~qpJl7Ab23!*x0NDQWC)Q$(ZN;+}uX)-eRDpZkhQ1H}RzrfB?dXg;y&X
sMS&U_B%}YoCMJ0U1P~*o*%=_f0C1N91;*}u^8f$<07*qoM6N<$f~X!Axc~qF

literal 699
zcmV;s0!00ZP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY9>D+r9>D>_X;f1H000McNliru)d>p~I5=@er?LP50!T?j
zK~zY`t(DDEt3VWlzu`xVR2G_yapBfoUMbtG@?O4=F4U^*bYsOBevA+xaPA@(YCv+)
zt6kMqnG7`3=kx(yUS4FeSP1YdoX_X-`1mMkno3!g!eX(Ir>7^0qNu_5_xGCH?Y8E}
z$4AXLjwOy`Ns>g8B$4fQE6e3lX0w^BRx3%<R1_dV5a9bhN~v%0;^G1mK@d<B1>^CU
z`}=#YuC8zZEX(?q@MJQf3rZ;*#{nP=L$uad=4Kx+FE5!)Cal+M05+RVEgptpeH}oa
z=agl6aPU=efc1Kf)|$;`!)P?>6gS~~#X*;NC1#3uJ)pNl$HdRi&p+K)tv@+vi`ur`
zxagR85CoKEc@T1(P8SUaZFHr@6mKV}*FpQ_0ISsstu=3NZ;ia0a9x*U2W>Rjw5zqI
znh^lowmCaHtAAJjH_GvMo_bT%uD$R3wRjXoM}@n3&?r$Gm3US6D2hHMrp>l9tKA@_
zRGk>Jsit@zzf_{GDQ(m9Jkm7ne}K6;9*^s!v~L^^hX5o=g6DYvoSvSN=Q*zHQWV9%
z9hl-(Q%%Hi%wRC6#j`Bq<m9A|>CtylmSrfV8sCItHQ()ajrD%NZ>-IE0dVH?IS&sH
zTwh-^7z}EgeQD{cx9|Jh-rh2uPO)wKu>bu0EVJ3{*S^Wq=~QlRZshLnPJG`Nm8Pjg
zQN-)(D`6P2-|rC-{uhqpFdPoiS~D7rP-R(4p6Bd#JF+aJC<=Z8%d&7?7tix>T^CiI
hRu1^l={sgh{Q>{dci5SW8X*7x002ovPDHLkV1ggXM_vE`

diff --git a/lib/images/toolbar/smiley.png b/lib/images/toolbar/smiley.png
new file mode 100644
index 0000000000000000000000000000000000000000..dee8a962ab4b541bb475d7b975d56df7c2a3e5ef
GIT binary patch
literal 860
zcmV-i1Ec(jP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt006JZ
zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!?ny*JRCwBA
z{Qv(y10?_;fLPE4{_JPu0h(F#{~v?Lzkdv7AoGFjQ$Y3(Al=97`~M5FdVm08M0NpC
zvprDJd`7uaMMeQLhW~6rK;3^C{(pbN@b~?BhM%{)?*k1=6b$@-5T*wpfZzuF*~b|8
zU%-AHlSDMbe=dH8zu#^!{QLQq;s2i>3=E7M3``s<42-{-7=Aul&G7T(!64DF|LZ~e
z00IbX!0&yGLO|*vv+i=9e@vek{{Fbn!0`Js!@oa2fe!cqG34KW21a%{24;3$hL6XS
zz5rb!FB$#+9Y6pvflL89yNF4?n&&?oP~A_U=09H<_HBFv<ose_`1_0D&~6~}_ZNmg
zpDr`}{dt#xOS78i-(Q9zkY0cQ0viA{&6`osoZ%nP=Kp`b0}cGm;NZmxrvLx_&0uT)
z1;_@v24u*GvkWW(Y79UFyg_;a0tjY+76UsU(8(X*n!xm*UqJRRDEl{<{qHBxWeh(V
z{{Cf91nC6`Aea}vgZ=sU55u1I#~2>mdIHh-_cxUO$?)**TZVl*pMVWx00tP)Qf81|
zfB=HH;4i~{hTq?TEH(xUdv%7}S06JxzWV~K5v1YK{r3!aZoX$QGv{MqWa0v<XJPpL
zli?0XFF*jXK)tZ__nY$uOagKYT-?tYENm4SE}wqDaQ)(ApsRi}aC0&;n3?f2aC0#;
zu<+?Ke1G$h;rB0wtsuPs0R)c5_v;u%fri}UF<;E{@AplHzhABcBLEm4z-avU2NsPC
z49wiXw7}=i@Ni4!7hsSm8CLy&4G=(JF9-(xe+^1u-|j2|`cImHna`Yoky!}n{Quzi
zXJQj!U=?)%CNL+4w^ufTY)=Gf2I&O|Ae5y1d?}+VFg#{*Yn3Xp32QSju>#Hi_lM!n
z&%X>`pWkA5alHFJ(B>@Tn*TdsdH@255j{6PUcd-SB&9$Xc>trz3>cFPKuxEBcn1)7
mo7AFaCV&89q%=DN1Q-CV1B<;VXJXI*0000<MNUMnLSTZAXoh(J

literal 0
HcmV?d00001

diff --git a/lib/images/toolbar/spellcheck.png b/lib/images/toolbar/spellcheck.png
index 797a0433d01390f1d6967baebaee31734e24d6db..9aecbad4bd47b0a0c91b980676a14e8e0be93d24 100644
GIT binary patch
literal 738
zcmV<80v-K{P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt006JZ
zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!bV)=(RCwBA
z{Qv(y10?_;fS4F41ONfV0wSFIY-e(_a~W*P-f8a8YZK4S!CC&{!>7ZHj0}oLs!qD;
z7ig9I{r%Vc$G1Q482<fdxU=wHI?Moo0Ad7r!EdVj$>0BefBg3IXT`t2|8#+ht&Y{4
zO1EjZxc2GU2WK{3j=g8vE@)wM0YCsTI``Sc|NZ~p>fgWrxBvb5s|wV7jD>@>{O9K%
zPrknYdjI#gKga(5Ww5%l;BGpyM)86f9IsxP{RIdhCKeXv=zstJ3jsB%a&dEb{`&r#
z;q!}+hfg-0bNloCpU|J5|6cL%^4Ox-8h63?m5|c~1_q{y00G1Tw3+{4@liLBgh{3T
z%-`RCi?Z>s+o~ig&*bFdko)=N*M-mTK5f)Y(%ALq-ybOh89NzqqZ*z!U;cdf`{G9v
zKmaik8;y)n=Oh@^c=o%ib88&A`}OPBU2pXNAF{d&5I_td1HgvV-b`R9zv&9&BV&fp
zvp(XzcmD*gc=DgQ_WC;p%fr$zIe-9Sfm`u|;gqBv*Ez<T8><;!{Ym>jOXoXd#5pDg
z7KVwIo}xM8>`V;n&whTvaNw2U|5J7^VA=oz2*nGGX;-R!y+m5J-TCtT?}<-o3<?~z
z?)toDoJ>p%8&1D}%y8hH+5Za&%^&~}K&S@9U0`8Q;5r><z;E#Q{SO9xQ4WR|AAU1z
zIPu{=!+|$e|F1c`Ko1*$0Ky1FMz2!}!Zt#8(v10;uRj0Iu<6*lJ3yOl|KD<Yfh}+W
z0*C=?pqU;la+-GkKST2Qdkl)ZC9tW1VSoU_Eup!$gFzO*W)KDlAVx~FGeCd=0D#$f
Us|Q%G@&Et;07*qoM6N<$f|j^!6aWAK

literal 1076
zcmV-41k3x0P)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY9>D+r9>D>_X;f1H000McNliru)d>p~IsqJYO*jAm1Hnl|
zK~zY`t(8wmTUivwfA=L$5)J+@iB+sp5lY&$AXr-LqKmfH*@#Ff7!le^DQb(%qTs4v
z>qhFXt`$UZ>#pcVrOYr41!YDZTv${@<DX}e7p=zkP8Z^<snK!9Iq>ngymRh%zRP#+
zWo2bWT3T8J_+QZ6+$^)Rvmzph2(+}c$il*cM5ECp#9}cUhGE!<$Ky7(x3^_`ds}vP
zc4TK~M-0P|xw$zBg+dYzhebqCfNX7Tq3b$IsdK|LP4e>cn4X@du&@vfK-07n3knMh
z{}qAL=>#AWiLkr7%fSjxEI94oN%;**kw_%4EbBnQKNXyrV1FO2t&Lwa?XYjO9~Bf8
z6;WDRN=HYBP0-rfN=ZoxeSLi>r5G3(proXPoSdBRo9jBNwiZ5rrvLF{j)ufyF<Dw#
zlJ@p?@p`=ih{NHK)zwu2WMpJSMn*;?H#b){H#a3KD@#U4M<o)895`-nPK+BjBzEPB
zj1CS8AmiiXva+%w&ZFJ;_VzM7JdA0Y)YR123J!CQegQ-T`SJzl!-tSa@LOjm@$_^u
zGc%JF7=|Is%gfT#)FdvKOBx#+1(0w!EP&M4*NeyFk?!tp(RE#VdV0j`^~%p6MldKb
zw_8Tvypf@yA-m>KfdV8Rj}whXaX1{Lic~gcV*_V(HEMpIzn?y3`pzAys;cn&{kYw3
z#>dAgFE3BFsbyIJwwDjX;cy%y&|bcT`FX<Euk+XK+XSy&!{_rQ9pNz-X`1$3#n-Pm
z-@U_q^(tC_e^Qa^>Vl6S*}ZUq-=93efAJ#a<>j{0V+2P%Z+AU0f%C%$)cQK=^=p>L
z#t!l(CgA;h0RCubz~S>zSy^dst{s_yB!V9YN*+95v#aZX%ryC_vlAl{LA`i^vMd&F
z-effxq@tn%x7&SeI8Pk3qsV;r45PXl0RQA9iBJf&yiCI5;m=2pD86)wf`WpS)1UH)
zQo-}~EtbQ95+VQ7Cjh2vYuWet2nK_x9d=d)N-5Ok%UJjB*#+_ZeCF@oB@hUZk&$ug
z<~G6J-rng~@bl*YY!w&t>#J9Iva=~GD@&QXv9Xav;B0PgW@cuFva&ML)6+3c^Z0Fg
z|31;SHpT)0GW~w4Zr#G=avkef*L5Z*CkX@s_Uy2@xG14e=uGczU0t2HT&`1d0)c=G
z4i3uH)RgGDE=ojLUtgECwKXD<2>bi{2aolC45!nH*Xt!eKc9kv0;Md=5~Y-iMx(N~
uw})w(oF_C*BP}hB?Cfj>pw83nS>hY&UhQZeNjQ)I0000<MNUMnLSTaAKmEu6

diff --git a/lib/images/toolbar/strike.png b/lib/images/toolbar/strike.png
index 197aafa9d22cf472500251cb5f6063dee29c96b0..f6dd97647fe836e046867db7e1405e0c383d5f8f 100644
GIT binary patch
literal 450
zcmV;z0X_bSP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt006JZ
zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzR7pfZRCwBA
z{Qv(y10?_;fS4F41ONd<u>k-9#DYz*w6s+4&!0aXzkmNe`|H;)K_IR4^XE^cWy_Yi
zqN@c6AgnF`YPt)=_ohslG7AVgfBg7y4~Si`sRali3<L7=^3s5c1%WmS!o-#@U*7rs
z`}aNA3;+lqCM>q!17ZfCA?2Z=p)>vb{ER{3Km$6l82}JKjM$<vDk^F>FbrIP7^IQm
z>({Smfi9{zdGaKND*yrrY(PatMJbTog)aHx#S4bJckeRXxpN21Mh|PC-X4GeVgMO{
zjQ#!n1(EqiMn-Ac+S+%4^nW=yxijeM0Rjla05><cG<$pda&&PS8JYiLVq$mE#Q_2c
zBM?D;1_oe<fq{V_vN%xeJun<*p{oZ7AQo%}02P81?^aMySPhJk_n^cC#Irtq`h*b^
s00G2EX=VZlAd2$>Kmbu}06>5N0CddmcqPuMV*mgE07*qoM6N<$g5$ie-T(jq

literal 739
zcmV<90v!E`P)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY9>D+r9>D>_X;f1H000McNliru)dmC>9v-;hn6&@^0&q!0
zK~#9!t(DD78&MR+fA7sC&1~AB3@TO;zY2w}T-X1=eY(iPjUe3x#FZ<-oeRNLvuyqq
zT}qVJK!^xxQD<WFVJ4rQ-fku#F=%U@1BZDqZ|-^L-g)-|i~;+Agv2kvJ0J=u1?*p3
zTzrnl<Mcx*_0Q|>)AxO@udi8HSjYe=prQaNm&=q&C6rPxrtkZVj*bGn2YzS(t#v5D
zl~S0d*){kEcxCq64TF7%09rpcxNY0d5#iYm{<ilabeIAU|FWJy|E9~!OIBA`nVXwq
zYHEr^B0;fO90;<vx5xbaJmcfztgo+Auh$2JA9VnbOeR@dTjTWflw2;y;^HD(TU!Gk
z9UL5RczDRk$q6?%H|*@}JnBFJ;&~p`Y8AsUhH_Z1*I8OxBA?HrlwxFLgrlP)W@l#s
zC=?2;tgKKd6aX*`gIFvEungo01j1?)(rUH3>yN-#FGaVvw>XZ&#KZ*YbeglXGhEl@
z{QMk%a=A>UQUM^F&Ek0;p68LxW|^Fvq}goJYPFs&GC;H0BpQukSr%7USEN#@p#pAh
zZsIr&uIsX~u|Xn{=)Kok52aZejfOamBd+U8CX<nwnHez*L#C&vWp{U10I621a({m>
zfNXDXi*4ItS(YS|NvTvS(r&k<)9Hxs`vWObfdI8yEtFQFweGrD2J$-0KJ?dn5O(mM
zK)c-zP2leCZb%@V%jFOeEXyJii44#*%_nIXMsJ>!N+phuj{&{|eo$=Q0$)R%$=`ra
zzy~0%g5mrcu!AXN1})@&@e8N{Mc}6jf<=H>AZG9~{02He1L&v+jZeMs^u5d5<saX}
VEf)wEGdKVM002ovPDHLkV1lduN+kdQ

diff --git a/lib/images/toolbar/ul.png b/lib/images/toolbar/ul.png
new file mode 100644
index 0000000000000000000000000000000000000000..4331bc6c28d331da96dc2cebab008f562ab06893
GIT binary patch
literal 409
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL
zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+AuIMYJ0jkhE&{2`t$$4J+mr<Lc<IR
z4HgDQ7BhwNgOi&wci*>RxVS`$LBK&r!6|swVh6`5zH%p6Bn=iWTBIcH;s5jZcm2cj
z?dv7#{{K7s;q`TWgTJ4j`x{iBon_jiu$O`H2m@F1oS*&N%idM}WpHW!u_U2^A!&(;
z03%b!BL@}^g$;}=H_M5a<ko#v*z#TOWFv=w!vlv9p=8|&f=LtWl}|GA9r^L&M^1u+
zFC(jj(Z7$6+2_=Le&$=Cz{Db8p}=I7Cptx^?$3d(pQONgMc9=b7y@NFKpr@-?m>~`
zp)bGrb3W-$1`Bbzl+I&fX3eYcGBGnd$HsO=Bw`iw#S<$9r&u*gKr}r#*Q+n=Fl(X7
s;hUS&mou$gd1MDLOf>jh8W@-v4mv-~mM^#$0SsFPPgg&ebxsLQ07e0nlK=n!

literal 0
HcmV?d00001

diff --git a/lib/images/toolbar/underline.png b/lib/images/toolbar/underline.png
index db07038fde1121f2f2b38a4032fda86c0206b7f6..ee5e0d9fd537365d5a2556dded62503d9d9c39b7 100644
GIT binary patch
literal 405
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL
zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+AuIMs(ZRPhE&{2`t$$4J+mr<Lc<IR
z4HgE*BTZ*ku2|v05cJnU=fnH^`#ED{V_OY&E?KhV>;AgGTt9w(PJj67>T2}^M;Mtp
z7@x4F#Kgtz+rMPV6Z>5iDJe@F3JN|{mJ~KH9Qtr*zJ0w!gIS_Q>CH{4^84!l|6`1m
zQD}&`!0Ipy$mzYh-+|fS2m=$xYQ`He4W}7^dJGsOJQ94?FfuT<Bp&FOxA!mtxod;Q
zE{0D{lP3o=Y}&DE)hgx-AGlw<Vr1f&%_zLT<|h-^$0}uIW!4EZy1KYLitPpbUBdYV
z9C~g{+O%`$PNoaeUmbWBIW|@?dg#~u{bkz5&A`+#@zNd!0SAf36^j>tme10*FmTLd
xnr7zE$<rY@@hUTmz)?L04u!5_Wrqev2BojZnfx}M+YJm?22WQ%mvv4FO#peUo0tFq

literal 743
zcmV<D0vP>?P)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x0-Q-iK~#9!t(8qn8&MR7pP5dYZfpk=5wR{@gkrG@E?g+>PPbV_DgK1+
z`deJJ;0G-_#D#7|5d^`FAP7Q=5?2aE2sQH+GXwK+yGg>Bn8}E~aG1;G-20yQoIB?L
z3<Ar5cp>`%d;nepk_0T@+}wOqRh1|tNlLtKeuE(3_V$)sF83Sw4ww=k48y=MjFxkp
z_3{bBkW3~6@Dcbc1IV%*d+7N1n4zH|#>U3*JTKN)QIw{@cR*T>%I!v^X&RYK23^<L
z-QDdOPy;DImfIz_AGU3qy}dma7Z({G9%gNAEm0bqc%a}hlAWC$T-Rl8ZjO9D&&kON
z<#IVzMNfh#iKb~}vsq?lW+)U20IaXC$ELJ{pj#wYS67^!osrMyQ51#A$w_j#9Ga%#
zx^7pJL<*YG0~88{*51Ox0)}C*y}jMFZiy6xVMwu9WMpK7>FMd#eltxgD=S^=7KPGH
z!QtT{l}ZJG{{DX2ae8`6sZ?TOVxr?GOq8OHjSbT2G}qVHn5KzkSy+~ZZQC3i9K@>V
znWAd7%KrX7^Yinls@ieE?CdO~qoZtYZc?w;J4hZSh~{u>YYX4^9~8IUmX?;VZJT1T
z82gF<gyT4(TCECQ*M+X@VtjmD^!4?LN~I!f+ZMH2P2At#i+a5-9LEuk<A}@4O96<f
zsVU)kp74EN1VJFeFl@H%&%mGr2-kI6?>b4xjPr{W`U_B|K_E=i6qaR)qoboI51G}~
zRS`vp0?V>uqj^emySuw1o6WWq$iUBwiwiu@Bb7?UcGg~(>$=YQ`8mKJAZRGzJ@D%V
zXL1Sn3VZ@osWF`20t1aHqyU|7EjfIk2K)o6Qsc4|@TNibisvB&Jir0GXrxlao{Lt>
Z{sR)URp#%x)t>+W002ovPDHLkV1l+kT;l)$

diff --git a/lib/scripts/edit.js b/lib/scripts/edit.js
new file mode 100644
index 000000000..641124c8f
--- /dev/null
+++ b/lib/scripts/edit.js
@@ -0,0 +1,308 @@
+/**
+ * Functions for text editing (toolbar stuff)
+ *
+ * @todo I'm no JS guru please help if you know how to improve
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+
+/**
+ * Creates a toolbar button through the DOM
+ *
+ * Style the buttons through the toolbutton class
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function createToolButton(icon,label,key,id){
+    var btn = document.createElement('button');
+    var ico = document.createElement('img');
+
+    // preapare the basic button stuff
+    btn.className = 'toolbutton';
+    btn.title = label;
+    if(key){
+        btn.title += ' [ALT+'+key.toUpperCase()+']';
+        btn.accesskey = key;
+    }
+
+    // set IDs if given
+    if(id){
+        btn.id = id;
+        ico.id = id+'_ico';
+    }
+
+    // create the icon and add it to the button
+    ico.src = DOKU_BASE+'lib/images/toolbar/'+icon;
+    btn.appendChild(ico);
+
+    return btn;
+}
+
+/**
+ * Creates a picker window for inserting text
+ *
+ * The given list can be an associative array with text,icon pairs
+ * or a simple list of text. Style the picker window through the picker
+ * class or the picker buttons with the pickerbutton class. Picker
+ * windows are appended to the body and created invisible.
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function createPicker(id,list,icobase,edid){
+    var cnt = list.length;
+      
+    var picker = document.createElement('div');
+    picker.className = 'picker';
+    picker.id = id;
+    picker.style.position = 'absolute';
+    picker.style.display  = 'none';
+      
+    for(var key in list){
+        var btn = document.createElement('button');
+
+        btn.className = 'pickerbutton'
+
+        // associative array?
+        if(isNaN(key)){
+            var ico = document.createElement('img');
+            ico.src       = DOKU_BASE+'lib/images/'+icobase+'/'+list[key];
+            btn.title     = key;
+            btn.appendChild(ico);
+            eval("btn.onclick = function(){pickerInsert('"+id+"','"+
+                                  jsEscape(key)+"','"+
+                                  jsEscape(edid)
+                                +"');return false;}");
+        }else{
+            var txt = document.createTextNode(list[key]);
+            btn.title     = list[key];
+            btn.appendChild(txt);
+            eval("btn.onclick = function(){pickerInsert('"+id+"','"+
+                                  jsEscape(list[key])+"','"+
+                                  jsEscape(edid)
+                                +"');return false;}");
+        }
+
+        picker.appendChild(btn);
+    }
+    var body = document.getElementsByTagName('body')[0];
+    body.appendChild(picker);
+}
+
+/**
+ * Called by picker buttons to insert Text and close the picker again
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function pickerInsert(pickerid,text,edid){
+    // insert
+    insertAtCarret(edid,text);
+    // close picker
+    pobj = document.getElementById(pickerid);
+    pobj.style.display = 'none';
+}
+
+/**
+ * Show a previosly created picker window
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function showPicker(pickerid,btn){
+    var picker = document.getElementById(pickerid);
+    var x = findPosX(btn);
+    var y = findPosY(btn);
+    if(picker.style.display == 'none'){
+        picker.style.display = 'block';
+        picker.style.left = (x+3)+'px';
+        picker.style.top = (y+btn.offsetHeight+3)+'px';
+    }else{
+        picker.style.display = 'none';
+    }
+}
+
+/**
+ * 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 = document.getElementById(tbid);
+    var cnt = tb.length;
+    for(i=0; i<cnt; i++){
+        // create new button and add to the toolbar
+        btn = createToolButton(tb[i]['icon'],
+                               tb[i]['title'],
+                               tb[i]['key']);
+        toolbar.appendChild(btn);
+
+        // add button action dependend on type
+        switch(tb[i]['type']){
+            case 'format':
+                var sample = tb[i]['title'];
+                if(tb[i]['sample']) sample = tb[i]['sample'];
+      
+                eval("btn.onclick = function(){insertTags('"+
+                                        jsEscape(edid)+"','"+
+                                        jsEscape(tb[i]['open'])+"','"+
+                                        jsEscape(tb[i]['close'])+"','"+
+                                        jsEscape(sample)+
+                                    "');return false;}");
+                break;
+            case 'insert':
+                eval("btn.onclick = function(){insertAtCarret('"+
+                                        jsEscape(edid)+"','"+
+                                        jsEscape(tb[i]['insert'])+
+                                    "');return false;}");
+                break;
+            case 'picker':
+                createPicker('picker'+i,
+                             tb[i]['list'],
+                             tb[i]['icobase'],
+                             edid);
+                eval("btn.onclick = function(){showPicker('picker"+i+
+                                    "',this);return false;}");
+                break;
+            case 'popup':
+                eval("btn.onclick = function(){window.open('"+
+                                        jsEscape(tb[i]['url'])+"','"+
+                                        jsEscape(tb[i]['name'])+"','"+
+                                        jsEscape(tb[i]['options'])+
+                                    "');return false;}");
+                break;
+        } // end switch
+    } // end for
+}
+
+/**
+ * Format selection
+ *
+ * Apply tagOpen/tagClose to selection in textarea, use sampleText instead
+ * of selection if there is none. Copied and adapted from phpBB
+ *
+ * @author phpBB development team
+ * @author MediaWiki development team
+ * @author Andreas Gohr <andi@splitbrain.org>
+ * @author Jim Raynor <jim_raynor@web.de>
+ */
+function insertTags(edid,tagOpen, tagClose, sampleText) {
+  var txtarea = document.getElementById(edid);
+  // IE
+  if(document.selection  && !is_gecko) {
+    var theSelection = document.selection.createRange().text;
+    var replaced = true;
+    if(!theSelection){
+      replaced = false;
+      theSelection=sampleText;
+    }
+    txtarea.focus();
+ 
+    // This has change
+    text = theSelection;
+    if(theSelection.charAt(theSelection.length - 1) == " "){// exclude ending space char, if any
+      theSelection = theSelection.substring(0, theSelection.length - 1);
+      r = document.selection.createRange();
+      r.text = tagOpen + theSelection + tagClose + " ";
+    } else {
+      r = document.selection.createRange();
+      r.text = tagOpen + theSelection + tagClose;
+    }
+    if(!replaced){
+      r.moveStart('character',-text.length-tagClose.length);
+      r.moveEnd('character',-tagClose.length);
+    }
+    r.select();
+  // Mozilla
+  } else if(txtarea.selectionStart || txtarea.selectionStart == '0') {
+    var replaced = false;
+    var startPos = txtarea.selectionStart;
+    var endPos   = txtarea.selectionEnd;
+    if(endPos - startPos) replaced = true;
+    var scrollTop=txtarea.scrollTop;
+    var myText = (txtarea.value).substring(startPos, endPos);
+    if(!myText) { myText=sampleText;}
+    if(myText.charAt(myText.length - 1) == " "){ // exclude ending space char, if any
+      subst = tagOpen + myText.substring(0, (myText.length - 1)) + tagClose + " ";
+    } else {
+      subst = tagOpen + myText + tagClose;
+    }
+    txtarea.value = txtarea.value.substring(0, startPos) + subst +
+                    txtarea.value.substring(endPos, txtarea.value.length);
+    txtarea.focus();
+ 
+    //set new selection
+    if(replaced){
+      var cPos=startPos+(tagOpen.length+myText.length+tagClose.length);
+      txtarea.selectionStart=cPos;
+      txtarea.selectionEnd=cPos;
+    }else{
+      txtarea.selectionStart=startPos+tagOpen.length;   
+      txtarea.selectionEnd=startPos+tagOpen.length+myText.length;
+    }
+    txtarea.scrollTop=scrollTop;
+  // All others
+  } else {
+    var copy_alertText=alertText;
+    var re1=new RegExp("\\$1","g");
+    var re2=new RegExp("\\$2","g");
+    copy_alertText=copy_alertText.replace(re1,sampleText);
+    copy_alertText=copy_alertText.replace(re2,tagOpen+sampleText+tagClose);
+    var text;
+    if (sampleText) {
+      text=prompt(copy_alertText);
+    } else {
+      text="";
+    }
+    if(!text) { text=sampleText;}
+    text=tagOpen+text+tagClose;
+    //append to the end
+    txtarea.value += "\n"+text;
+
+    // in Safari this causes scrolling
+    if(!is_safari) {
+      txtarea.focus();
+    }
+
+  }
+  // reposition cursor if possible
+  if (txtarea.createTextRange) txtarea.caretPos = document.selection.createRange().duplicate();
+}
+
+/*
+ * Insert the given value at the current cursor position
+ *
+ * @see http://www.alexking.org/index.php?content=software/javascript/content.php
+ */
+function insertAtCarret(edid,value){
+  var field = document.getElementById(edid);
+
+  //IE support
+  if (document.selection) {
+    field.focus();
+    if(opener == null){
+      sel = document.selection.createRange();
+    }else{
+      sel = opener.document.selection.createRange();
+    }
+    sel.text = value;
+  //MOZILLA/NETSCAPE support
+  }else if (field.selectionStart || field.selectionStart == '0') {
+    var startPos  = field.selectionStart;
+    var endPos    = field.selectionEnd;
+    var scrollTop = field.scrollTop;
+    field.value = field.value.substring(0, startPos)
+                  + value
+                  + field.value.substring(endPos, field.value.length);
+
+    field.focus();
+    var cPos=startPos+(value.length);
+    field.selectionStart=cPos;
+    field.selectionEnd=cPos;
+    field.scrollTop=scrollTop;
+  } else {
+    field.value += "\n"+value;
+  }
+  // reposition cursor if possible
+  if (field.createTextRange) field.caretPos = document.selection.createRange().duplicate();
+}
+
diff --git a/lib/scripts/script.js b/lib/scripts/script.js
index 8ee3c3805..490394dfb 100644
--- a/lib/scripts/script.js
+++ b/lib/scripts/script.js
@@ -16,9 +16,87 @@ if (clientPC.indexOf('opera')!=-1) {
     var is_opera_seven = (window.opera && document.childNodes);
 }
 
+//http://simon.incutio.com/archive/2004/05/26/addLoadEvent#comment2
+function addEvent(oTarget, sType, fpDest) {
+  var oOldEvent = oTarget[sType];
+  if (typeof oOldEvent != "function") {
+    oTarget[sType] = fpDest;
+  } else {
+    oTarget[sType] = function(e) {
+      oOldEvent(e);
+      fpDest(e);
+    }
+  }
+}
+
+/**
+ * Get the X offset of the top left corner of the given object
+ *
+ * @link http://www.quirksmode.org/index.html?/js/findpos.html
+ */
+function findPosX(object){
+  var curleft = 0;
+  if(typeof(object) == 'object'){
+    var obj = object;
+  }else{
+    var obj = document.getElementById(object);
+  }
+  if (obj.offsetParent){
+    while (obj.offsetParent){
+      curleft += obj.offsetLeft;
+      obj = obj.offsetParent;
+    }
+  }
+  else if (obj.x){
+    curleft += obj.x;
+  }
+  return curleft;
+} //end findPosX function
+
+/**
+ * Get the Y offset of the top left corner of the given object
+ *
+ * @link http://www.quirksmode.org/index.html?/js/findpos.html
+ */
+function findPosY(object){
+  var curtop = 0;
+  if(typeof(object) == 'object'){
+    var obj = object;
+  }else{
+    var obj = document.getElementById(object);
+  }
+  if (obj.offsetParent){
+    while (obj.offsetParent){
+      curtop += obj.offsetTop;
+      obj = obj.offsetParent;
+    }
+  }
+  else if (obj.y){
+    curtop += obj.y;
+  }
+  return curtop;
+} //end findPosY function
+
+/**
+ * Escape special chars in JavaScript
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function jsEscape(text){
+    var re=new RegExp("\\\\","g");
+    text=text.replace(re,"\\\\");
+    var re=new RegExp("'","g");
+    text=text.replace(re,"\\'");
+    re=new RegExp('"',"g");
+    text=text.replace(re,'&quot;');
+    re=new RegExp("\\\\\\\\n","g");
+    text=text.replace(re,"\\n");
+    return text;
+}
 
 /**
  * This function escapes some special chars
+ * @deprecated by above function
  */
 function escapeQuotes(text) {
   var re=new RegExp("'","g");
@@ -72,6 +150,7 @@ function summaryCheck(){
 /**
  * This function generates the actual toolbar buttons with localized text
  * we use it to avoid creating the toolbar where javascript is not enabled
+ * @deprecated
  */
 function formatButton(imageFile, speedTip, tagOpen, tagClose, sampleText, accessKey) {
   speedTip=escapeQuotes(speedTip);
@@ -97,6 +176,7 @@ function formatButton(imageFile, speedTip, tagOpen, tagClose, sampleText, access
 /**
  * This function generates the actual toolbar buttons with localized text
  * we use it to avoid creating the toolbar where javascript is not enabled
+ * @deprecated
  */
 function insertButton(imageFile, speedTip, value, accessKey) {
   speedTip=escapeQuotes(speedTip);
@@ -119,6 +199,7 @@ function insertButton(imageFile, speedTip, value, accessKey) {
 
 /**
  * This adds a button for the MediaSelection Popup
+ * @deprecated
  */
 function mediaButton(imageFile, speedTip, accessKey, namespace) {
   speedTip=escapeQuotes(speedTip);
@@ -135,99 +216,6 @@ function mediaButton(imageFile, speedTip, accessKey, namespace) {
   return;
 }
 
-/**
- * apply tagOpen/tagClose to selection in textarea, use sampleText instead
- * of selection if there is none copied and adapted from phpBB
- *
- * @author phpBB development team
- * @author MediaWiki development team
- * @author Andreas Gohr <andi@splitbrain.org>
- * @author Jim Raynor <jim_raynor@web.de>
- */
-function insertTags(tagOpen, tagClose, sampleText) {
-  var txtarea = document.editform.wikitext;
-  // IE
-  if(document.selection  && !is_gecko) {
-    var theSelection = document.selection.createRange().text;
-    var replaced = true;
-    if(!theSelection){
-      replaced = false;
-      theSelection=sampleText;
-    }
-    txtarea.focus();
- 
-    // This has change
-    text = theSelection;
-    if(theSelection.charAt(theSelection.length - 1) == " "){// exclude ending space char, if any
-      theSelection = theSelection.substring(0, theSelection.length - 1);
-      r = document.selection.createRange();
-      r.text = tagOpen + theSelection + tagClose + " ";
-    } else {
-      r = document.selection.createRange();
-      r.text = tagOpen + theSelection + tagClose;
-    }
-    if(!replaced){
-      r.moveStart('character',-text.length-tagClose.length);
-      r.moveEnd('character',-tagClose.length);
-    }
-    r.select();
-  // Mozilla
-  } else if(txtarea.selectionStart || txtarea.selectionStart == '0') {
-    var replaced = false;
-    var startPos = txtarea.selectionStart;
-    var endPos   = txtarea.selectionEnd;
-    if(endPos - startPos) replaced = true;
-    var scrollTop=txtarea.scrollTop;
-    var myText = (txtarea.value).substring(startPos, endPos);
-    if(!myText) { myText=sampleText;}
-    if(myText.charAt(myText.length - 1) == " "){ // exclude ending space char, if any
-      subst = tagOpen + myText.substring(0, (myText.length - 1)) + tagClose + " ";
-    } else {
-      subst = tagOpen + myText + tagClose;
-    }
-    txtarea.value = txtarea.value.substring(0, startPos) + subst +
-                    txtarea.value.substring(endPos, txtarea.value.length);
-    txtarea.focus();
- 
-    //set new selection
-    if(replaced){
-      var cPos=startPos+(tagOpen.length+myText.length+tagClose.length);
-      txtarea.selectionStart=cPos;
-      txtarea.selectionEnd=cPos;
-    }else{
-      txtarea.selectionStart=startPos+tagOpen.length;   
-      txtarea.selectionEnd=startPos+tagOpen.length+myText.length;
-    }
-    txtarea.scrollTop=scrollTop;
-  // All others
-  } else {
-    var copy_alertText=alertText;
-    var re1=new RegExp("\\$1","g");
-    var re2=new RegExp("\\$2","g");
-    copy_alertText=copy_alertText.replace(re1,sampleText);
-    copy_alertText=copy_alertText.replace(re2,tagOpen+sampleText+tagClose);
-    var text;
-    if (sampleText) {
-      text=prompt(copy_alertText);
-    } else {
-      text="";
-    }
-    if(!text) { text=sampleText;}
-    text=tagOpen+text+tagClose;
-    //append to the end
-    txtarea.value += "\n"+text;
-
-    // in Safari this causes scrolling
-    if(!is_safari) {
-      txtarea.focus();
-    }
-
-  }
-  // reposition cursor if possible
-  if (txtarea.createTextRange) txtarea.caretPos = document.selection.createRange().duplicate();
-}
-
-
 /*
  * Insert the selected filename and close the window
  *
@@ -238,41 +226,6 @@ function mediaSelect(file){
   window.close(); 
 }
 
-/*
- * Insert the given value at the current cursor position
- *
- * @see http://www.alexking.org/index.php?content=software/javascript/content.php
- */
-function insertAtCarret(field,value){
-  //IE support
-  if (document.selection) {
-    field.focus();
-    if(opener == null){
-      sel = document.selection.createRange();
-    }else{
-      sel = opener.document.selection.createRange();
-    }
-    sel.text = value;
-  //MOZILLA/NETSCAPE support
-  }else if (field.selectionStart || field.selectionStart == '0') {
-    var startPos  = field.selectionStart;
-    var endPos    = field.selectionEnd;
-    var scrollTop = field.scrollTop;
-    field.value = field.value.substring(0, startPos)
-                  + value
-                  + field.value.substring(endPos, field.value.length);
-
-    field.focus();
-    var cPos=startPos+(value.length);
-    field.selectionStart=cPos;
-    field.selectionEnd=cPos;
-    field.scrollTop=scrollTop;
-  } else {
-    field.value += "\n"+value;
-  }
-  // reposition cursor if possible
-  if (field.createTextRange) field.caretPos = document.selection.createRange().duplicate();
-}
 
 /**
  * For the upload Dialog. Prefills the wikiname.
@@ -321,38 +274,6 @@ function toggleToc() {
   }
 }
 
-/**
- * Sizecontrol inspired by TikiWiki. This displays the buttons.
- */
-function showSizeCtl(){
-  if(document.getElementById) {
-    var textarea = document.getElementById('wikitext');
-    var hgt = getCookie('DokuWikisizeCtl');
-    if(hgt == null){
-      textarea.style.height = '300px';
-    }else{
-      textarea.style.height = hgt;
-    }
-    document.writeln('<a href="javascript:sizeCtl(100)"><img src="'+DOKU_BASE+'lib/images/larger.gif" width="20" height="20" border="0"></a>');
-    document.writeln('<a href="javascript:sizeCtl(-100)"><img src="'+DOKU_BASE+'lib/images/smaller.gif" width="20" height="20" border="0"></a>');
-  }
-}
-
-/**
- * This sets the vertical size of the editbox
- */
-function sizeCtl(val){
-  var textarea = document.getElementById('wikitext');
-  var height = parseInt(textarea.style.height.substr(0,textarea.style.height.length-2));
-  height += val;
-  textarea.style.height = height+'px';
-  
-  var now = new Date();
-  fixDate(now);
-  now.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000); //expire in a year
-  setCookie('DokuWikisizeCtl',textarea.style.height,now);
-}
-
 
 /**
  * global var used for not saved yet warning
@@ -497,3 +418,43 @@ function fnt(id, e, evt) {
     domTT_activate(e, evt, 'content', footnote, 'type', 'velcro', 'id', 'insitu-fn'+id, 'styleClass', 'insitu-footnote', 'maxWidth', document.body.offsetWidth*0.4);
     currentFootnote = id;    
 }
+
+
+/**
+ * Add the edit window size controls
+ */
+function initSizeCtl(ctlid,edid){
+    var ctl      = document.getElementById(ctlid);
+    var textarea = document.getElementById(edid);
+
+    var hgt = getCookie('DokuWikisizeCtl');
+    if(hgt == null){
+      textarea.style.height = '300px';
+    }else{
+      textarea.style.height = hgt;
+    }
+
+    var l = document.createElement('img');
+    var s = document.createElement('img');
+    l.src = DOKU_BASE+'lib/images/larger.gif';
+    s.src = DOKU_BASE+'lib/images/smaller.gif';
+    l.onclick = function(){sizeCtl(edid,100);}
+    s.onclick = function(){sizeCtl(edid,-100);}
+    ctl.appendChild(l);
+    ctl.appendChild(s);
+}
+
+/**
+ * This sets the vertical size of the editbox
+ */
+function sizeCtl(edid,val){
+  var textarea = document.getElementById(edid);
+  var height = parseInt(textarea.style.height.substr(0,textarea.style.height.length-2));
+  height += val;
+  textarea.style.height = height+'px';
+  
+  var now = new Date();
+  fixDate(now);
+  now.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000); //expire in a year
+  setCookie('DokuWikisizeCtl',textarea.style.height,now);
+}
diff --git a/lib/scripts/spellcheck.js b/lib/scripts/spellcheck.js
index e86c079df..d47430c31 100644
--- a/lib/scripts/spellcheck.js
+++ b/lib/scripts/spellcheck.js
@@ -40,45 +40,19 @@
  * OF SUCH DAMAGE.
  */
 
-/**
- * Get the X offset of the top left corner of the given object
+/*
+ * Uses some general functions defined elsewhere. Here is a list:
  *
- * @author Garrison Locke <http://www.broken-notebook.com>
- */
-function findPosX(object){
-  var curleft = 0;
-  var obj = document.getElementById(object);
-  if (obj.offsetParent){
-    while (obj.offsetParent){
-      curleft += obj.offsetLeft;
-      obj = obj.offsetParent;
-    }
-  }
-  else if (obj.x){
-    curleft += obj.x;
-  }
-  return curleft;
-} //end findPosX function
-
-/**
- * Get the Y offset of the top left corner of the given object
+ * Defined in script.js:
  *
- * @author Garrison Locke <http://www.broken-notebook.com>
+ *   findPosX()
+ *   findPosY()
+ *   addEvent()
+ *
+ * Defined in edit.js:
+ *
+ *   createToolButton()
  */
-function findPosY(object){
-  var curtop = 0;
-  var obj = document.getElementById(object);
-  if (obj.offsetParent){
-    while (obj.offsetParent){
-      curtop += obj.offsetTop;
-      obj = obj.offsetParent;
-    }
-  }
-  else if (obj.y){
-    curtop += obj.y;
-  }
-  return curtop;
-} //end findPosY function
 
 /**
  * quotes single quotes
@@ -89,29 +63,6 @@ function qquote(str){
   return str.split('\'').join('\\\'');
 }
 
-/**
- * This function generates a spellchecker button with localized tooltips
- */
-function spellButton(imageFile, speedTip, funcCall, accessKey) {
-  speedTip=escapeQuotes(speedTip);
-  funcCall=escapeQuotes(funcCall);
-
-  button = "<a ";
-  if(accessKey){
-    button = button+"accesskey=\""+accessKey+"\" ";
-    speedTip = speedTip+' [ALT+'+accessKey.toUpperCase()+']';
-  }
-  if(funcCall){
-    button = button+"href=\"javascript:"+funcCall+";\"";
-  }
-  button = button+">";
-  button = button+"<img width=\"24\" height=\"24\" src=\""+
-                DOKU_BASE+'lib/images/toolbar/'+imageFile+"\" border=\"0\" alt=\""+
-                speedTip+"\" title=\""+speedTip+"\">";
-  button = button+"</a>";
-  return button;
-}
-
 /**
  * AJAX Spellchecker Class
  *
@@ -127,11 +78,13 @@ function ajax_spell_class(){
   this.utf8ok = 1;
   this.handler = DOKU_BASE+'lib/exe/spellcheck.php';
   // to hold the page objects (initialized with init())
-  this.textboxObj = null;
+  this.textboxObj = null; 
   this.showboxObj = null;
   this.suggestObj = null;
-  this.actionObj  = null;
   this.editbarObj = null;
+  this.buttonObj = null;
+  this.imageObj  = null;
+
   // hold translations
   this.txtStart = 'Check Spelling';
   this.txtStop  = 'Resume Editing';
@@ -162,7 +115,6 @@ function ajax_spell_class(){
     this.editbarObj = document.getElementById('wikieditbar');
     this.showboxObj = document.getElementById('spell_result'); 
     this.suggestObj = document.getElementById('spell_suggest');
-    this.actionObj  = document.getElementById('spell_action'); 
 
     // set Translation Strings
     this.txtStart = txtStart;
@@ -172,11 +124,20 @@ function ajax_spell_class(){
     this.txtNoSug = txtNoSug;
     this.txtChange= txtChange;
 
+    // create ToolBar Button with ID and add it to the toolbar with null action
+    var toolbarObj = document.getElementById('toolbar');
+    this.buttonObj = createToolButton('spellcheck.png',txtStart,'k','spellcheck');
+    this.buttonObj.onclick = function(){return false;};
+    toolbarObj.appendChild(this.buttonObj);
+    this.imageObj  = document.getElementById('spellcheck_ico');
+
     // start UTF-8 compliance test - send an UTF-8 char and see what comes back
     ajax.AjaxFailedAlert = '';
     ajax.encodeURIString = false;
     ajax.onCompletion    = this.initReady;
     ajax.runAJAX('call=utf8test&data='+encodeURIComponent('ü'));
+
+    // second part of initialisation is in initReady() function
   }
 
   /**
@@ -208,16 +169,28 @@ function ajax_spell_class(){
   this.setState = function(state){
     switch (state){
       case 'stop':
-        ajax_spell.actionObj.innerHTML = spellButton("spellstop.png",ajax_spell.txtStop,"ajax_spell.resume()","");
+        ajax_spell.buttonObj.onclick   = function(){ ajax_spell.resume(); return false; };
+        ajax_spell.buttonObj.title     = ajax_spell.txtStop;
+        ajax_spell.buttonObj.accesskey = '';
+        ajax_spell.imageObj.src = DOKU_BASE+'lib/images/toolbar/spellstop.png';
         break;
       case 'noerr':
-        ajax_spell.actionObj.innerHTML = spellButton("spellnoerr.png",ajax_spell.txtNoErr,"ajax_spell.setState(\"start\")","");
+        ajax_spell.buttonObj.onclick   = function(){ajax_spell.setState('start'); return false; };
+        ajax_spell.buttonObj.title     = ajax_spell.txtNoErr;
+        ajax_spell.buttonObj.accesskey = '';
+        ajax_spell.imageObj.src = DOKU_BASE+'lib/images/toolbar/spellnoerr.png';
         break;
       case 'run':
-        ajax_spell.actionObj.innerHTML = spellButton("spellwait.gif",ajax_spell.txtRun,"","");
+        ajax_spell.buttonObj.onclick   = function(){return false;};
+        ajax_spell.buttonObj.title     = ajax_spell.txtRun;
+        ajax_spell.buttonObj.accesskey = '';
+        ajax_spell.imageObj.src = DOKU_BASE+'lib/images/toolbar/spellwait.gif';
         break;
       default:
-        ajax_spell.actionObj.innerHTML = spellButton("spellcheck.png",ajax_spell.txtStart,"ajax_spell.run()","k");
+        ajax_spell.buttonObj.onclick   = function(){ ajax_spell.run(); return false; };
+        ajax_spell.buttonObj.title     = ajax_spell.txtStart+' [ALT-K]';
+        ajax_spell.buttonObj.accesskey = 'k';
+        ajax_spell.imageObj.src = DOKU_BASE+'lib/images/toolbar/spellcheck.png';
         break;
     }
   }
@@ -311,10 +284,10 @@ function ajax_spell_class(){
     }
 
     // register click event
-    document.onclick = ajax_spell.docClick;
+    addEvent(document,'onclick',ajax_spell.docClick);
 
     // register focus event
-    ajax_spell.textboxObj.onfocus = ajax_spell.setState;
+    addEvent(ajax_spell.textboxObj,'onfocus',ajax_spell.setState);
 
     // get started
     ajax_spell.setState('start');    
@@ -395,14 +368,14 @@ function ajax_spell_class(){
    * @author Andreas Gohr <andi@splitbrain.org>
    */
   this.run = function(){
-    this.setState('run');
-    this.textboxObj.disabled = true;
-    var ajax = new sack(this.handler);
+    ajax_spell.setState('run');
+    ajax_spell.textboxObj.disabled = true;
+    var ajax = new sack(ajax_spell.handler);
     ajax.AjaxFailedAlert = '';
     ajax.encodeURIString = false;
     ajax.onCompletion    = this.start;
     ajax.runAJAX('call=check&utf8='+ajax_spell.utf8ok+
-                 '&data='+encodeURIComponent(this.textboxObj.value));
+                 '&data='+encodeURIComponent(ajax_spell.textboxObj.value));
   }
 
   /**
@@ -411,13 +384,13 @@ function ajax_spell_class(){
    * @author Andreas Gohr <andi@splitbrain.org>
    */
   this.resume = function(){
-    this.setState('run');
-    var text = this.showboxObj.innerHTML;
+    ajax_spell.setState('run');
+    var text = ajax_spell.showboxObj.innerHTML;
     if(text != ''){
-      var ajax = new sack(this.handler);
+      var ajax = new sack(ajax_spell.handler);
       ajax.AjaxFailedAlert = '';
       ajax.encodeURIString = false;
-      ajax.onCompletion    = this.stop;
+      ajax.onCompletion    = ajax_spell.stop;
       ajax.runAJAX('call=resume&utf8='+ajax_spell.utf8ok+
                    '&data='+encodeURIComponent(text));
     }
diff --git a/lib/tpl/default/design.css b/lib/tpl/default/design.css
index 83547b9b4..7bc6085f2 100644
--- a/lib/tpl/default/design.css
+++ b/lib/tpl/default/design.css
@@ -666,6 +666,30 @@ div.ajax_qsearch {
   padding: 4px;
 }
 
+/* --------- Toolbar -------------------- */
+button.toolbutton{
+  background-color: #fff;
+  padding: 0px;
+  margin: 0 1px 0 0;
+	border: 1px solid #8cacbb;
+	cursor: pointer;
+}
+
+div.picker {
+  width: 250px;
+  border: 1px solid #8cacbb;
+  background: #eef3f8;
+}
+
+button.pickerbutton {
+  padding: 0px;
+  margin: 0 1px 1px 0;
+  border: 0;
+  background-color: transparent;
+  font-size: 80%;
+	cursor: pointer;
+}
+
 /* ---------- Spellchecking ------------- */
 
 a.spell_error {
-- 
GitLab