diff --git a/angular.json b/angular.json
index f1693a005bfa9fff1f7d22efe99e45493be57e63..31f04944fd9bafa1df96f4a112516d30fd47097e 100644
--- a/angular.json
+++ b/angular.json
@@ -29,7 +29,8 @@
               "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css",
               "node_modules/quill/dist/quill.core.css",
               "node_modules/quill/dist/quill.bubble.css",
-              "node_modules/quill/dist/quill.snow.css"
+              "node_modules/quill/dist/quill.snow.css",
+              "node_modules/quill-emoji/dist/quill-emoji.css"
             ],
             "scripts": [
               "node_modules/marked/lib/marked.js",
@@ -40,7 +41,8 @@
               "node_modules/prismjs/plugins/line-highlight/prism-line-highlight.js",
               "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.js",
               "node_modules/katex/dist/katex.min.js",
-              "node_modules/quill/dist/quill.js"
+              "node_modules/quill/dist/quill.js",
+              "node_modules/quill-image-resize-module/image-resize.min.js"
             ]
           },
           "configurations": {
diff --git a/package-lock.json b/package-lock.json
index 5ba02ab68b481f3dcdf7ba158b449db8d1090b10..bb315dc069d0be9cb262a214bf4417281c74ab6c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -46,6 +46,8 @@
         "ngx-quill": "^14.2.0",
         "prismjs": "^1.23.0",
         "quill": "^1.3.7",
+        "quill-emoji": "^0.2.0",
+        "quill-image-resize-module": "^3.0.0",
         "rxjs": "^6.5.4",
         "tslib": "^2.0.0",
         "typescript-map": "0.0.7",
@@ -3730,6 +3732,14 @@
       "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
       "dev": true
     },
+    "node_modules/amdefine": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+      "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
+      "engines": {
+        "node": ">=0.4.2"
+      }
+    },
     "node_modules/angular-tag-cloud-module": {
       "version": "5.3.0",
       "resolved": "https://registry.npmjs.org/angular-tag-cloud-module/-/angular-tag-cloud-module-5.3.0.tgz",
@@ -5253,6 +5263,43 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/clean-css": {
+      "version": "3.4.28",
+      "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz",
+      "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=",
+      "dependencies": {
+        "commander": "2.8.x",
+        "source-map": "0.4.x"
+      },
+      "bin": {
+        "cleancss": "bin/cleancss"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/clean-css/node_modules/commander": {
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
+      "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
+      "dependencies": {
+        "graceful-readlink": ">= 1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.6.x"
+      }
+    },
+    "node_modules/clean-css/node_modules/source-map": {
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+      "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+      "dependencies": {
+        "amdefine": ">=0.0.4"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
     "node_modules/clean-stack": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -6768,6 +6815,20 @@
       "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
       "dev": true
     },
+    "node_modules/emoji-data-css": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/emoji-data-css/-/emoji-data-css-1.0.1.tgz",
+      "integrity": "sha1-T5W0g5S1hXHtMoSs+nCepRGHX48=",
+      "dependencies": {
+        "clean-css": "^3.4.20",
+        "emoji-datasource": "^2.4.4"
+      }
+    },
+    "node_modules/emoji-datasource": {
+      "version": "2.4.4",
+      "resolved": "https://registry.npmjs.org/emoji-datasource/-/emoji-datasource-2.4.4.tgz",
+      "integrity": "sha1-uXrBiWvCCOzxgzVkogaHpSFdA4k="
+    },
     "node_modules/emoji-regex": {
       "version": "8.0.0",
       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -8566,6 +8627,14 @@
       "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
       "dev": true
     },
+    "node_modules/fuse.js": {
+      "version": "3.6.1",
+      "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz",
+      "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/gauge": {
       "version": "2.7.4",
       "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
@@ -8762,6 +8831,11 @@
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
       "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
     },
+    "node_modules/graceful-readlink": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
+      "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU="
+    },
     "node_modules/handle-thing": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
@@ -14847,6 +14921,33 @@
         "node": ">=0.10"
       }
     },
+    "node_modules/quill-emoji": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/quill-emoji/-/quill-emoji-0.2.0.tgz",
+      "integrity": "sha512-0kqHKTFA9hk1Vf5g32KBm/NYZal6n9N/ATmk13Hka/XYsgrEIaShSR84B5VMB7bg5o9+TMeIzc+wey5OP7hv+A==",
+      "dependencies": {
+        "emoji-data-css": "^1.0.1",
+        "fuse.js": "^3.3.0"
+      },
+      "peerDependencies": {
+        "quill": "^1.3.5"
+      }
+    },
+    "node_modules/quill-image-resize-module": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/quill-image-resize-module/-/quill-image-resize-module-3.0.0.tgz",
+      "integrity": "sha1-D9k3Rqg3M22VsvU2FAQWpiPHF3E=",
+      "dependencies": {
+        "lodash": "^4.17.4",
+        "quill": "^1.2.2",
+        "raw-loader": "^0.5.1"
+      }
+    },
+    "node_modules/quill-image-resize-module/node_modules/raw-loader": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz",
+      "integrity": "sha1-DD0L6u2KAclm2Xh793goElKpeao="
+    },
     "node_modules/quill/node_modules/clone": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
@@ -20718,8 +20819,7 @@
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-4.2.0.tgz",
       "integrity": "sha512-qM4hpweuQ14ul8CU6LKpUWFZs6POUE7HZKdTllUrYuoZMrTpNB1XGelR0pweYzbfo4XRnUaO1NVgWhWOWiD5MA==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "@angular-eslint/eslint-plugin": {
       "version": "4.2.0",
@@ -23243,8 +23343,7 @@
       "version": "5.3.1",
       "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
       "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "adjust-sourcemap-loader": {
       "version": "4.0.0",
@@ -23342,15 +23441,13 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
       "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "ajv-keywords": {
       "version": "3.5.2",
       "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
       "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "alphanum-sort": {
       "version": "1.0.2",
@@ -23358,6 +23455,11 @@
       "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
       "dev": true
     },
+    "amdefine": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+      "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
+    },
     "angular-tag-cloud-module": {
       "version": "5.3.0",
       "resolved": "https://registry.npmjs.org/angular-tag-cloud-module/-/angular-tag-cloud-module-5.3.0.tgz",
@@ -24481,8 +24583,7 @@
       "version": "5.2.2",
       "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz",
       "integrity": "sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "class-utils": {
       "version": "0.3.6",
@@ -24564,6 +24665,33 @@
         }
       }
     },
+    "clean-css": {
+      "version": "3.4.28",
+      "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz",
+      "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=",
+      "requires": {
+        "commander": "2.8.x",
+        "source-map": "0.4.x"
+      },
+      "dependencies": {
+        "commander": {
+          "version": "2.8.1",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
+          "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
+          "requires": {
+            "graceful-readlink": ">= 1.0.0"
+          }
+        },
+        "source-map": {
+          "version": "0.4.4",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+          "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+          "requires": {
+            "amdefine": ">=0.0.4"
+          }
+        }
+      }
+    },
     "clean-stack": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -25381,8 +25509,7 @@
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-2.0.1.tgz",
       "integrity": "sha512-i8vLRZTnEH9ubIyfdZCAdIdgnHAUeQeByEeQ2I7oTilvP9oHO6RScpeq3GsFUVqeB8uZgOQ9pw8utofNn32hhQ==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "csso": {
       "version": "4.2.0",
@@ -25795,6 +25922,20 @@
         }
       }
     },
+    "emoji-data-css": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/emoji-data-css/-/emoji-data-css-1.0.1.tgz",
+      "integrity": "sha1-T5W0g5S1hXHtMoSs+nCepRGHX48=",
+      "requires": {
+        "clean-css": "^3.4.20",
+        "emoji-datasource": "^2.4.4"
+      }
+    },
+    "emoji-datasource": {
+      "version": "2.4.4",
+      "resolved": "https://registry.npmjs.org/emoji-datasource/-/emoji-datasource-2.4.4.tgz",
+      "integrity": "sha1-uXrBiWvCCOzxgzVkogaHpSFdA4k="
+    },
     "emoji-regex": {
       "version": "8.0.0",
       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -26288,8 +26429,7 @@
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz",
       "integrity": "sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "eslint-scope": {
       "version": "5.1.1",
@@ -27205,6 +27345,11 @@
       "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
       "dev": true
     },
+    "fuse.js": {
+      "version": "3.6.1",
+      "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz",
+      "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw=="
+    },
     "gauge": {
       "version": "2.7.4",
       "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
@@ -27349,6 +27494,11 @@
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
       "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
     },
+    "graceful-readlink": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
+      "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU="
+    },
     "handle-thing": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
@@ -27855,8 +28005,7 @@
       "version": "5.1.0",
       "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
       "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "ieee754": {
       "version": "1.2.1",
@@ -28878,8 +29027,7 @@
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.6.0.tgz",
       "integrity": "sha512-ELO9yf0cNqpzaNLsfFgXd/wxZVYkE2+ECUwhMHUD4PZ17kcsPsYsVyjquiRqyMn2jkd2sHt0IeMyAyq1MC23Fw==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "karma-source-map-support": {
       "version": "1.4.0",
@@ -29948,8 +30096,7 @@
     "ngx-matomo": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/ngx-matomo/-/ngx-matomo-0.1.4.tgz",
-      "integrity": "sha512-AKZMnJGyytZqAxuSh+k/AulyQhgqlnnsmtkfvHMJyNuh5g+wVpIbwac36RyeFU3El6INgZVso2CCLElV3bQnBQ==",
-      "requires": {}
+      "integrity": "sha512-AKZMnJGyytZqAxuSh+k/AulyQhgqlnnsmtkfvHMJyNuh5g+wVpIbwac36RyeFU3El6INgZVso2CCLElV3bQnBQ=="
     },
     "ngx-matomo-v9": {
       "version": "0.3.0",
@@ -31149,29 +31296,25 @@
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz",
       "integrity": "sha512-lgZBPTDvWrbAYY1v5GYEv8fEO/WhKOu/hmZqmCYfrpD6eyDWWzAOsl2rF29lpvziKO02Gc5GJQtlpkTmakwOWg==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "postcss-discard-duplicates": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz",
       "integrity": "sha512-svx747PWHKOGpAXXQkCc4k/DsWo+6bc5LsVrAsw+OU+Ibi7klFZCyX54gjYzX4TH+f2uzXjRviLARxkMurA2bA==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "postcss-discard-empty": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz",
       "integrity": "sha512-vfU8CxAQ6YpMxV2SvMcMIyF2LX1ZzWpy0lqHDsOdaKKLQVQGVP1pzhrI9JlsO65s66uQTfkQBKBD/A5gp9STFw==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "postcss-discard-overridden": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.0.1.tgz",
       "integrity": "sha512-Y28H7y93L2BpJhrdUR2SR2fnSsT+3TVx1NmVQLbcnZWwIUpJ7mfcTC6Za9M2PG6w8j7UQRfzxqn8jU2VwFxo3Q==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "postcss-import": {
       "version": "14.0.0",
@@ -31290,8 +31433,7 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
       "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "postcss-modules-local-by-default": {
       "version": "4.0.0",
@@ -31326,8 +31468,7 @@
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz",
       "integrity": "sha512-6J40l6LNYnBdPSk+BHZ8SF+HAkS4q2twe5jnocgd+xWpz/mx/5Sa32m3W1AA8uE8XaXN+eg8trIlfu8V9x61eg==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "postcss-normalize-display-values": {
       "version": "5.0.1",
@@ -32030,6 +32171,32 @@
         "fast-diff": "1.1.2"
       }
     },
+    "quill-emoji": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/quill-emoji/-/quill-emoji-0.2.0.tgz",
+      "integrity": "sha512-0kqHKTFA9hk1Vf5g32KBm/NYZal6n9N/ATmk13Hka/XYsgrEIaShSR84B5VMB7bg5o9+TMeIzc+wey5OP7hv+A==",
+      "requires": {
+        "emoji-data-css": "^1.0.1",
+        "fuse.js": "^3.3.0"
+      }
+    },
+    "quill-image-resize-module": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/quill-image-resize-module/-/quill-image-resize-module-3.0.0.tgz",
+      "integrity": "sha1-D9k3Rqg3M22VsvU2FAQWpiPHF3E=",
+      "requires": {
+        "lodash": "^4.17.4",
+        "quill": "^1.2.2",
+        "raw-loader": "^0.5.1"
+      },
+      "dependencies": {
+        "raw-loader": {
+          "version": "0.5.1",
+          "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz",
+          "integrity": "sha1-DD0L6u2KAclm2Xh793goElKpeao="
+        }
+      }
+    },
     "randombytes": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -36430,8 +36597,7 @@
       "version": "7.4.6",
       "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
       "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
-      "dev": true,
-      "requires": {}
+      "dev": true
     },
     "xml2js": {
       "version": "0.4.23",
diff --git a/package.json b/package.json
index 56a69f7797c86cc44b62d5e457baa4b264676238..5e9dd6689e33f2560deda91d908dfa1af35d393e 100644
--- a/package.json
+++ b/package.json
@@ -50,6 +50,8 @@
     "ngx-quill": "^14.2.0",
     "prismjs": "^1.23.0",
     "quill": "^1.3.7",
+    "quill-emoji": "^0.2.0",
+    "quill-image-resize-module": "^3.0.0",
     "rxjs": "^6.5.4",
     "tslib": "^2.0.0",
     "typescript-map": "0.0.7",
diff --git a/src/app/components/shared/write-comment/write-comment.component.html b/src/app/components/shared/write-comment/write-comment.component.html
index 6b06f2fff572f4232e41cac0572e86eb57a19d5f..b931a1daaf5a5cafb7d813d73e1a848bc72312c5 100644
--- a/src/app/components/shared/write-comment/write-comment.component.html
+++ b/src/app/components/shared/write-comment/write-comment.component.html
@@ -46,26 +46,22 @@
 </ars-row>
 <ars-row [height]="12"></ars-row>
 <ars-row *ngIf="enabled">
-  <mat-tab-group>
-    <mat-tab label="Bearbeiten">
-      <div #editorErrorLayer id="editorErrorLayer"></div>
-      <quill-editor #editor [maxLength]="10" placeholder="{{ 'comment-page.enter-comment' | translate }}"
-                    [modules]="quillModules" (document:click)="onDocumentClick($event)">
-      </quill-editor>
-      <div #tooltipContainer></div>
-      <div fxLayout="row" style="justify-content: space-between; padding: 0 5px">
-        <span aria-hidden="true" style="font-size: 75%">
-          {{ 'comment-page.Markdown-hint' | translate }}
-        </span>
-        <span aria-hidden="true" style="font-size: 75%">
-          {{currentHTML.length}} / {{user.role === 3 ? 1000 : 500}}
-        </span>
-      </div>
-    </mat-tab>
-    <mat-tab label="Vorschau">
-      <app-custom-markdown [data]="currentHTML" [isRawHTML]="true"></app-custom-markdown>
-    </mat-tab>
-  </mat-tab-group>
+  <div #editorErrorLayer id="editorErrorLayer"></div>
+  <quill-editor #editor
+                [maxLength]="user.role === 3 ? 1000 : 500"
+                placeholder="{{ 'comment-page.enter-comment' | translate }}"
+                [modules]="quillModules"
+                (document:click)="onDocumentClick($event)">
+  </quill-editor>
+  <div #tooltipContainer></div>
+  <div fxLayout="row" style="justify-content: space-between; padding: 0 5px">
+    <span aria-hidden="true" style="font-size: 75%">
+      {{ 'comment-page.Markdown-hint' | translate }}
+    </span>
+    <span aria-hidden="true" style="font-size: 75%">
+      {{currentHTML.length}} / {{user.role === 3 ? 1000 : 500}}
+    </span>
+  </div>
 </ars-row>
 <ars-row ars-flex-box *ngIf="enabled" class="spellcheck">
   <ars-col>
diff --git a/src/app/components/shared/write-comment/write-comment.component.scss b/src/app/components/shared/write-comment/write-comment.component.scss
index 5b77b630afe4c4afb39c39d7acd25779385a01b3..2579d849f5dc293cd28563a01bd3209d250dda7c 100644
--- a/src/app/components/shared/write-comment/write-comment.component.scss
+++ b/src/app/components/shared/write-comment/write-comment.component.scss
@@ -258,6 +258,22 @@ $borderOffset: 2px;
   }
 
   .ql-tooltip {
+    &[data-mode=formula]::before {
+      --quill-tooltip-label: var(--quill-tooltip-label-formula);
+    }
+    &[data-mode=video]::before {
+      --quill-tooltip-label: var(--quill-tooltip-label-video);
+    }
+    &[data-mode=image]::before {
+      --quill-tooltip-label: var(--quill-tooltip-label-image);
+    }
+    &[data-mode=link]::before {
+      --quill-tooltip-label: var(--quill-tooltip-label-link);
+    }
+    &::before {
+      content: var(--quill-tooltip-label) !important;
+    }
+
     color: var(--on-surface);
     background-color: var(--surface);
 
@@ -266,9 +282,15 @@ $borderOffset: 2px;
       background: var(--primary);
       border-radius: 4px;
       color: var(--on-primary);
+      content: var(--quill-tooltip-action) !important;
+    }
+
+    &.ql-editing .ql-action::after {
+      --quill-tooltip-action: var(--quill-tooltip-action-save);
     }
 
     .ql-remove::before {
+      content: var(--quill-tooltip-remove) !important;
       padding: 7px !important;
       background: var(--cancel);
       border-radius: 4px;
diff --git a/src/app/components/shared/write-comment/write-comment.component.ts b/src/app/components/shared/write-comment/write-comment.component.ts
index e1177d335e5949d45ec4e3b86cb71bd2ffeb26f0..1d4d08f4e13679ec0f3e251d5d91031a93a0e008 100644
--- a/src/app/components/shared/write-comment/write-comment.component.ts
+++ b/src/app/components/shared/write-comment/write-comment.component.ts
@@ -8,28 +8,31 @@ import { EventService } from '../../../services/util/event.service';
 import { QuillEditorComponent, QuillModules } from 'ngx-quill';
 import { CreateCommentKeywords } from '../../../utils/create-comment-keywords';
 import { Marks } from './write-comment.marks';
+import { LanguageService } from '../../../services/util/language.service';
+import Delta from 'quill-delta';
+import Quill from 'quill';
+import ImageResize from 'quill-image-resize-module';
+import 'quill-emoji/dist/quill-emoji.js';
 
-const participantOptions: QuillModules = {
-  toolbar: [
-    ['bold', 'strike'],
-    ['blockquote', 'code-block'],
-    [{ list: 'ordered' }, { list: 'bullet' }],
-    ['link']
-  ]
-};
-
-const moderatorOptions: QuillModules = {
-  toolbar: [
-    ['bold', 'strike'],
-    ['blockquote', 'code-block'],
-    [{ header: 1 }, { header: 2 }],
-    [{ list: 'ordered' }, { list: 'bullet' }],
-    [{ indent: '-1' }, { indent: '+1' }],
-    [{ color: [] }],
-    [{ align: [] }],
-    ['link', 'image', 'video']
-  ]
-};
+Quill.register('modules/imageResize', ImageResize);
+
+const participantToolbar = [
+  ['bold', 'strike'],
+  ['blockquote', 'code-block'],
+  [{ list: 'ordered' }, { list: 'bullet' }],
+  ['link', 'formula']
+];
+
+const moderatorToolbar = [
+  ['bold', 'strike'],
+  ['blockquote', 'code-block'],
+  [{ header: 1 }, { header: 2 }],
+  [{ list: 'ordered' }, { list: 'bullet' }],
+  [{ indent: '-1' }, { indent: '+1' }],
+  [{ color: [] }],
+  [{ align: [] }],
+  ['link', 'image', 'video', 'formula']
+];
 
 @Component({
   selector: 'app-write-comment',
@@ -63,17 +66,42 @@ export class WriteCommentComponent implements OnInit, AfterViewInit {
   hasSpellcheckConfidence = true;
   newLang = 'auto';
   marks: Marks;
-  quillModules = participantOptions;
+  quillModules: QuillModules = {
+    toolbar: {
+      container: participantToolbar,
+      handlers: {
+        image: () => this.handle('image'),
+        video: () => this.handle('video'),
+        link: () => this.handleLink(),
+        formula: () => this.handle('formula')
+      }
+    },
+    'emoji-toolbar': true,
+    'emoji-textarea': true,
+    'emoji-shortname': true,
+    imageResize: {
+      modules: ['Resize', 'DisplaySize', 'Toolbar']
+    }
+  };
 
   constructor(private notification: NotificationService,
+              private languageService: LanguageService,
               private translateService: TranslateService,
               public eventService: EventService,
               public languagetoolService: LanguagetoolService) {
+    this.languageService.langEmitter.subscribe(lang => {
+      this.translateService.use(lang);
+      this.updateCSSVariables();
+    });
   }
 
   ngOnInit(): void {
     this.translateService.use(localStorage.getItem('currentLang'));
-    this.quillModules = this.user && this.user.role > 0 ? moderatorOptions : participantOptions;
+    if (this.user && this.user.role > 0) {
+      this.quillModules.toolbar['container'] = moderatorToolbar;
+    }
+    this.translateService.use(localStorage.getItem('currentLang'));
+    this.updateCSSVariables();
   }
 
   ngAfterViewInit() {
@@ -83,12 +111,24 @@ export class WriteCommentComponent implements OnInit, AfterViewInit {
       this.currentText = e.text;
     });
     this.editor.onEditorCreated.subscribe(_ => {
-      this.marks = new Marks(this.editorErrorLayer.nativeElement, this.tooltipContainer.nativeElement,
-        this.editor.editorElem.firstElementChild as HTMLDivElement);
+      this.marks = new Marks(this.editorErrorLayer.nativeElement, this.tooltipContainer.nativeElement, this.editor);
       this.syncErrorLayer();
       setTimeout(() => this.syncErrorLayer(), 200); // animations?
     });
     this.editor.onEditorChanged.subscribe(_ => {
+      const elem: HTMLDivElement = document.querySelector('div.ql-tooltip');
+      if (elem) { // fix tooltip
+        setTimeout(() => {
+          const left = parseFloat(elem.style.left);
+          const right = left + elem.getBoundingClientRect().width;
+          const containerWidth = this.editor.editorElem.getBoundingClientRect().width;
+          if (left < 0) {
+            elem.style.left = '0';
+          } else if (right > containerWidth) {
+            elem.style.left = (containerWidth - right + left) + 'px';
+          }
+        });
+      }
       this.syncErrorLayer();
       this.marks.sync();
     });
@@ -132,10 +172,8 @@ export class WriteCommentComponent implements OnInit, AfterViewInit {
     if (!this.marks) {
       return;
     }
-    const range = window.getSelection && window.getSelection().rangeCount > 0 ? window.getSelection().getRangeAt(0) : null;
-    const isClick = range && range.startContainer === range.endContainer && range.startOffset === range.endOffset &&
-      (e.target as HTMLElement).contains(range.commonAncestorContainer);
-    this.marks.onClick(isClick ? range : null);
+    const range = this.editor.quillEditor.getSelection(false);
+    this.marks.onClick(range && range.length === 0 ? range.index : null);
   }
 
   maxLength(commentBody: HTMLDivElement, size: number): void {
@@ -206,4 +244,71 @@ export class WriteCommentComponent implements OnInit, AfterViewInit {
     return true;
   }
 
+  private updateCSSVariables() {
+    const variables = [
+      'quill.tooltip-remove', 'quill.tooltip-action-save', 'quill.tooltip-action', 'quill.tooltip-label',
+      'quill.tooltip-label-link', 'quill.tooltip-label-image', 'quill.tooltip-label-video',
+      'quill.tooltip-label-formula'
+    ];
+    for (const variable of variables) {
+      this.translateService.get(variable).subscribe(translation => {
+        document.body.style.setProperty('--' + variable.replace('.', '-'), JSON.stringify(translation));
+      });
+    }
+  }
+
+  private handleLink(): void {
+    const quill = this.editor.quillEditor;
+    const selection = quill.getSelection(false);
+    if (!selection || !selection.length) {
+      return;
+    }
+    const tooltip = quill.theme.tooltip;
+    const originalSave = tooltip.save;
+    const originalHide = tooltip.hide;
+    tooltip.save = () => {
+      const value = tooltip.textbox.value;
+      if (value) {
+        const delta = new Delta()
+          .retain(selection.index)
+          .retain(selection.length, { link: value });
+        quill.updateContents(delta);
+        tooltip.hide();
+      }
+    };
+    // Called on hide and save.
+    tooltip.hide = () => {
+      tooltip.save = originalSave;
+      tooltip.hide = originalHide;
+      tooltip.hide();
+    };
+    tooltip.edit('link');
+    tooltip.textbox.value = quill.getText(selection.index, selection.length);
+    this.translateService.get('quill.tooltip-placeholder-link')
+      .subscribe(translation => tooltip.textbox.placeholder = translation);
+  }
+
+  private handle(type: string): void {
+    const quill = this.editor.quillEditor;
+    const tooltip = quill.theme.tooltip;
+    const originalSave = tooltip.save;
+    const originalHide = tooltip.hide;
+    tooltip.save = () => {
+      const range = quill.getSelection(true);
+      const value = tooltip.textbox.value;
+      if (value) {
+        quill.insertEmbed(range.index, type, value, 'user');
+      }
+    };
+    // Called on hide and save.
+    tooltip.hide = () => {
+      tooltip.save = originalSave;
+      tooltip.hide = originalHide;
+      tooltip.hide();
+    };
+    tooltip.edit(type);
+    this.translateService.get('quill.tooltip-placeholder-' + type)
+      .subscribe(translation => tooltip.textbox.placeholder = translation);
+  }
+
 }
diff --git a/src/app/components/shared/write-comment/write-comment.marks.ts b/src/app/components/shared/write-comment/write-comment.marks.ts
index ce937236f0da44c1446214f20d96f1a6d1ee09be..b387e18f949bd064eb99ca0ca1ba442870b4287c 100644
--- a/src/app/components/shared/write-comment/write-comment.marks.ts
+++ b/src/app/components/shared/write-comment/write-comment.marks.ts
@@ -1,4 +1,5 @@
 import { LanguagetoolResult } from '../../../services/http/languagetool.service';
+import { QuillEditorComponent } from 'ngx-quill';
 
 export class Marks {
 
@@ -6,7 +7,7 @@ export class Marks {
 
   constructor(private markContainer: HTMLDivElement,
               private tooltipContainer: HTMLDivElement,
-              private editor: HTMLDivElement) {
+              private editor: QuillEditorComponent) {
   }
 
   clear() {
@@ -16,11 +17,12 @@ export class Marks {
     this.textErrors.length = 0;
   }
 
-  onClick(range: Range) {
+  onClick(index: number) {
+    const editorRect = this.editor.editorElem.firstElementChild.getBoundingClientRect();
     for (const textError of this.textErrors) {
       textError.close();
-      if (range) {
-        textError.open(range);
+      if (index !== null) {
+        textError.open(index, editorRect.y, editorRect.x);
       }
     }
   }
@@ -31,10 +33,10 @@ export class Marks {
       if (op['insert']) {
         const len = op['insert'].length;
         for (const textError of this.textErrors) {
-          if (index > textError.endIndex) {
+          if (index > textError.startIndex + textError.markLength) {
             continue;
           }
-          textError.endIndex += len;
+          textError.markLength += len;
           if (index >= textError.startIndex) {
             continue;
           }
@@ -47,26 +49,26 @@ export class Marks {
         const len = op['delete'];
         const endDelete = index + len;
         this.textErrors = this.textErrors.filter((textError) => {
-          if (index >= textError.endIndex) {
+          if (index >= textError.startIndex + textError.markLength) {
             return true;
           }
           if (index > textError.startIndex) {
-            if (endDelete < textError.endIndex) {
-              textError.endIndex -= len;
+            if (endDelete < textError.startIndex + textError.markLength) {
+              textError.markLength -= len;
               return true;
             }
-            textError.endIndex = index;
+            textError.markLength = index - textError.startIndex;
             return true;
           }
           if (endDelete < textError.startIndex) {
             textError.startIndex -= len;
-            textError.endIndex -= len;
+            textError.markLength -= len;
             return true;
           }
-          if (endDelete < textError.endIndex) {
-            const errLen = textError.endIndex - endDelete;
+          if (endDelete < textError.startIndex + textError.markLength) {
+            const errLen = textError.startIndex + textError.markLength - endDelete;
             textError.startIndex = index;
-            textError.endIndex = index + errLen;
+            textError.markLength = errLen;
             return true;
           }
           textError.remove();
@@ -76,26 +78,17 @@ export class Marks {
         console.log(op);
       }
     }
-    let currentElement: Node = this.editor;
-    let currentOffset = 0;
-    let depth = 0;
-    for (const error of this.textErrors) {
-      [currentElement, currentOffset, depth] = error.rebuildMark(depth, currentElement, currentOffset);
-    }
+    this.sync();
   }
 
   buildErrors(initialText: string, wrongWords: string[], res: LanguagetoolResult): void {
-    let currentElement: Node = this.editor;
-    let currentOffset = 0;
-    let depth = 0;
     for (let i = 0; i < res.matches.length; i++) {
       const match = res.matches[i];
       const foundWord = initialText.slice(match.offset, match.offset + match.length);
       if (!wrongWords.includes(foundWord)) {
         continue;
       }
-      const mark = new Mark(match.offset, match.offset + match.length, this.markContainer, this.tooltipContainer);
-      [currentElement, currentOffset, depth] = mark.rebuildMark(depth, currentElement, currentOffset);
+      const mark = new Mark(match.offset, match.length, this.markContainer, this.tooltipContainer, this.editor.quillEditor);
       mark.setSuggestions(res, i, () => {
         const index = this.textErrors.findIndex(elem => elem === mark);
         if (index >= 0) {
@@ -105,121 +98,48 @@ export class Marks {
       });
       this.textErrors.push(mark);
     }
+    this.sync();
   }
 
   sync(): void {
     const parentRect = this.markContainer.getBoundingClientRect();
+    const editorRect = this.editor.editorElem.firstElementChild.getBoundingClientRect();
     for (const error of this.textErrors) {
-      error.syncMark(parentRect);
+      error.syncMark(parentRect, editorRect.y - parentRect.y);
     }
   }
 }
 
-interface MarkedRange {
-  mark: HTMLSpanElement;
-  range: Range;
-}
-
 class Mark {
 
-  private marks: MarkedRange[] = [];
-  private textRange: Range;
+  private marks: HTMLSpanElement[] = [];
   private dropdown: HTMLDivElement;
 
   constructor(public startIndex,
-              public endIndex,
+              public markLength,
               private markContainer: HTMLDivElement,
-              private tooltipContainer: HTMLDivElement) {
-  }
-
-  private static calcNodeTextSize(node: Node): number {
-    if (node instanceof HTMLBRElement) {
-      return 1;
-    }
-    return node.textContent.length;
-  }
-
-  private static findNode(depth: number,
-                          currentElement: Node,
-                          currentOffset: number,
-                          target: number,
-                          onNodeLeave?: (Node) => void): [Node, number, number] {
-    while (currentElement.firstChild) {
-      currentElement = currentElement.firstChild;
-      depth += 1;
-    }
-    let length = Mark.calcNodeTextSize(currentElement);
-    while (currentOffset + length <= target) {
-      if (onNodeLeave) {
-        onNodeLeave(currentElement);
-      }
-      currentOffset += length;
-      const wasAlreadyBreak = currentElement instanceof HTMLBRElement;
-      let currentBefore = currentElement.parentElement;
-      currentElement = currentElement.nextSibling;
-      while (!currentElement) {
-        if (depth <= 1) {
-          throw new Error('The requested text position was not inside the container.');
-        }
-        if (depth === 2 && !wasAlreadyBreak) {
-          currentOffset += 1;
-        }
-        currentElement = currentBefore.nextSibling;
-        currentBefore = currentBefore.parentElement;
-        depth -= 1;
-      }
-      while (currentElement.firstChild) {
-        currentElement = currentElement.firstChild;
-        depth += 1;
-      }
-      length = Mark.calcNodeTextSize(currentElement);
-    }
-    return [currentElement, currentOffset, depth];
-  }
-
-  isCollapsed(): boolean {
-    return this.marks.some(range => range.range.collapsed);
+              private tooltipContainer: HTMLDivElement,
+              private quillEditor: any) {
   }
 
-  rebuildMark(depth: number, currentElement: Node, currentOffset: number): [Node, number, number] {
-    this.textRange = document.createRange();
-    for (const mark of this.marks) {
-      mark.mark.remove();
+  syncMark(parentRect: DOMRect, offset: number) {
+    const boundaries = this.calculateBoundaries();
+    for (let i = this.marks.length; i < boundaries.length; i++) {
+      const elem = document.createElement('span');
+      this.markContainer.appendChild(elem);
+      this.marks.push(elem);
     }
-    this.marks.length = 0;
-    [currentElement, currentOffset, depth] = Mark.findNode(depth, currentElement, currentOffset, this.startIndex);
-    let rangeStart = this.startIndex - currentOffset;
-    rangeStart = rangeStart === -1 ? 0 : rangeStart;
-    this.textRange.setStart(currentElement, rangeStart);
-    [currentElement, currentOffset, depth] = Mark.findNode(depth, currentElement, currentOffset, this.endIndex - 1,
-      (node: Node) => {
-        const currentRange = this.textRange.cloneRange();
-        if (currentRange.startContainer !== node) {
-          currentRange.setStart(node, 0);
-        }
-        currentRange.setEnd(node, node.textContent.length);
-        this.marks.push(this.createMarkedRange(currentRange));
-      });
-    const rangeEnd = this.endIndex - currentOffset;
-    this.textRange.setEnd(currentElement, rangeEnd);
-    if (this.textRange.startContainer !== this.textRange.endContainer) {
-      const currentRange = this.textRange.cloneRange();
-      currentRange.setStart(currentElement, 0);
-      this.marks.push(this.createMarkedRange(currentRange));
-    } else {
-      this.marks.push(this.createMarkedRange(this.textRange));
+    for (let i = this.marks.length - 1; i >= boundaries.length; i--) {
+      this.marks[i].remove();
     }
-
-    return [currentElement, currentOffset, depth];
-  }
-
-  syncMark(parentRect: DOMRect) {
-    for (const mark of this.marks) {
-      const rect = mark.range.getBoundingClientRect();
-      mark.mark.style.setProperty('--width', rect.width + 'px');
-      mark.mark.style.setProperty('--height', rect.height + 'px');
-      mark.mark.style.setProperty('--left', (rect.x - parentRect.x) + 'px');
-      mark.mark.style.setProperty('--top', (rect.y - parentRect.y) + 'px');
+    this.marks.length = boundaries.length;
+    for (let i = 0; i < this.marks.length; i++) {
+      const mark = this.marks[i];
+      const rect = this.quillEditor.getBounds(boundaries[i][0], boundaries[i][1]);
+      mark.style.setProperty('--width', rect.width + 'px');
+      mark.style.setProperty('--height', rect.height + 'px');
+      mark.style.setProperty('--left', rect.left + 'px');
+      mark.style.setProperty('--top', (rect.top + offset) + 'px');
     }
   }
 
@@ -228,24 +148,29 @@ class Mark {
     this.dropdown.remove();
   }
 
-  open(range: Range): void {
-    for (const markedRange of this.marks) {
-      if (markedRange.range.compareBoundaryPoints(Range.END_TO_END, range) >= 0 &&
-        markedRange.range.compareBoundaryPoints(Range.START_TO_START, range) < 0) {
-        this.dropdown.style.display = 'block';
-        const rangeRect = markedRange.range.getBoundingClientRect();
-        this.dropdown.style.left = (rangeRect.x + rangeRect.width / 2) + 'px';
-        this.dropdown.style.top = rangeRect.y + 'px';
-        this.tooltipContainer.appendChild(this.dropdown);
-        this.dropdown.style.transform = 'translateY(-' + this.dropdown.getBoundingClientRect().height + 'px)';
-        return;
-      }
+  open(index: number, editorOffsetTop: number, editorOffsetLeft: number): void {
+    if (index < this.startIndex || index >= this.startIndex + this.markLength) {
+      return;
+    }
+    const boundaries = this.calculateBoundaries();
+    const i = boundaries.findIndex(value => index >= value[0] && index < value[0] + value[1]);
+    this.dropdown.style.display = 'block';
+    if (i >= 0) {
+      const rangeRect = this.marks[i].getBoundingClientRect();
+      this.dropdown.style.left = (rangeRect.x + rangeRect.width / 2) + 'px';
+      this.dropdown.style.top = rangeRect.y + 'px';
+    } else {
+      const bounds = this.quillEditor.getBounds(index);
+      this.dropdown.style.left = (bounds.left + editorOffsetLeft) + 'px';
+      this.dropdown.style.top = (bounds.top + editorOffsetTop) + 'px';
     }
+    this.tooltipContainer.appendChild(this.dropdown);
+    this.dropdown.style.transform = 'translateY(-' + this.dropdown.getBoundingClientRect().height + 'px)';
   }
 
   remove() {
     for (const mark of this.marks) {
-      mark.mark.remove();
+      mark.remove();
     }
     this.marks.length = 0;
     this.dropdown.remove();
@@ -269,13 +194,11 @@ class Mark {
         this.dropdown.append(dropdownElem);
         dropdownElem.addEventListener('click', () => {
           if (document.queryCommandSupported('insertText')) {
-            const selection = window.getSelection();
-            selection.removeAllRanges();
-            selection.addRange(this.textRange);
+            this.quillEditor.setSelection(this.startIndex, this.markLength, 'user');
             document.execCommand('insertText', false, suggestions[j].value);
           } else {
-            this.textRange.deleteContents();
-            this.textRange.insertNode(document.createTextNode(suggestions[j].value));
+            this.quillEditor.deleteText(this.startIndex, this.markLength, 'user');
+            this.quillEditor.insertText(this.startIndex, suggestions[j].value, 'user');
           }
           removeMark();
         });
@@ -283,19 +206,22 @@ class Mark {
     }
   }
 
-  private createMarkedRange(range: Range): MarkedRange {
-    const rect = range.getBoundingClientRect();
-    const parentRect = this.markContainer.getBoundingClientRect();
-    const elem = document.createElement('span');
-    elem.style.setProperty('--width', rect.width + 'px');
-    elem.style.setProperty('--height', rect.height + 'px');
-    elem.style.setProperty('--left', (rect.x - parentRect.x) + 'px');
-    elem.style.setProperty('--top', (rect.y - parentRect.y) + 'px');
-    this.markContainer.append(elem);
-    return {
-      mark: elem,
-      range
-    };
+  private calculateBoundaries(): [start: number, length: number][] {
+    const text: string = this.quillEditor.getText(this.startIndex, this.markLength);
+    const bounds = [];
+    let i = text.indexOf('\n');
+    let currentIndex = 0;
+    while (i >= 0) {
+      if (i > currentIndex) {
+        bounds.push([this.startIndex + currentIndex, i - currentIndex]);
+      }
+      currentIndex = i + 1;
+      i = text.indexOf('\n', currentIndex);
+    }
+    if (this.markLength > currentIndex) {
+      bounds.push([this.startIndex + currentIndex, this.markLength - currentIndex]);
+    }
+    return bounds;
   }
 
 }
diff --git a/src/assets/i18n/creator/de.json b/src/assets/i18n/creator/de.json
index 381960d8ccb435e91a0e09b2c86d06aa58f0169a..2a8f1570991cb197ae1366bd4c9d6f058523f693 100644
--- a/src/assets/i18n/creator/de.json
+++ b/src/assets/i18n/creator/de.json
@@ -238,6 +238,20 @@
     "created-2": "« wurde erstellt.",
     "no-empty-name": "Gib einen Namen ein. Der Raum-Code wird generiert."
   },
+  "quill": {
+    "tooltip-remove": "Löschen",
+    "tooltip-action-save": "Speichern",
+    "tooltip-action": "Editieren",
+    "tooltip-label": "URL besuchen:",
+    "tooltip-label-link": "Link eingeben:",
+    "tooltip-placeholder-link": "https://quilljs.com",
+    "tooltip-label-image": "Bild-URL eingeben:",
+    "tooltip-placeholder-image": "URL Adresse",
+    "tooltip-label-video": "Video-URL eingeben:",
+    "tooltip-placeholder-video": "URL Adresse",
+    "tooltip-label-formula": "Formel eingeben:",
+    "tooltip-placeholder-formula": "e=mc^2"
+  },
   "room-page": {
     "a11y-add-moderator": "Fügt den eingegebenen Benutzer als Moderator hinzu.",
     "a11y-cloud_download": "Direktlink zur Sitzung in die Zwischenablage kopieren",
diff --git a/src/assets/i18n/creator/en.json b/src/assets/i18n/creator/en.json
index daf3b2b01ccd8c656eb5c60ebfcf6fd0877faa80..bcdbd67ad12f941b5bc13f0bd7bf43000900415a 100644
--- a/src/assets/i18n/creator/en.json
+++ b/src/assets/i18n/creator/en.json
@@ -239,6 +239,20 @@
     "created-2": "« created.",
     "no-empty-name": "Please enter a name."
   },
+  "quill": {
+    "tooltip-remove": "Delete",
+    "tooltip-action-save": "Save",
+    "tooltip-action": "Edit",
+    "tooltip-label": "Visit URL:",
+    "tooltip-label-link": "Enter link:",
+    "tooltip-placeholder-link": "https://quilljs.com",
+    "tooltip-label-image": "Enter image:",
+    "tooltip-placeholder-image": "Embed URL",
+    "tooltip-label-video": "Enter video:",
+    "tooltip-placeholder-video": "Embed URL",
+    "tooltip-label-formula": "Enter formula:",
+    "tooltip-placeholder-formula": "e=mc^2"
+  },
   "room-page": {
     "a11y-add-moderator": "Add the entered User as Moderator",
     "a11y-cloud_download": "Copy link to session to the clipboard",
diff --git a/src/assets/i18n/participant/de.json b/src/assets/i18n/participant/de.json
index 7a63a6d40d38729a87658bfe6c909e0577f83927..84b38ce5d606f67434c6342bc8957be85ca229c5 100644
--- a/src/assets/i18n/participant/de.json
+++ b/src/assets/i18n/participant/de.json
@@ -248,6 +248,20 @@
     "overview-questioners-tooltip": "Anzahl Fragensteller*innen",
     "questions-blocked": "Neue Fragen deaktiviert "
   },
+  "quill": {
+    "tooltip-remove": "Löschen",
+    "tooltip-action-save": "Speichern",
+    "tooltip-action": "Editieren",
+    "tooltip-label": "URL besuchen:",
+    "tooltip-label-link": "Link eingeben:",
+    "tooltip-placeholder-link": "https://quilljs.com",
+    "tooltip-label-image": "Bild-URL eingeben:",
+    "tooltip-placeholder-image": "URL Adresse",
+    "tooltip-label-video": "Video-URL eingeben:",
+    "tooltip-placeholder-video": "URL Adresse",
+    "tooltip-label-formula": "Formel eingeben:",
+    "tooltip-placeholder-formula": "e=mc^2"
+  },
   "tag-cloud": {
     "demo-data-topic": "Thema %d",
     "overview-question-topic-tooltip": "Anzahl Fragen mit diesem Thema",
diff --git a/src/assets/i18n/participant/en.json b/src/assets/i18n/participant/en.json
index 936d67e96a4ad67b62cf64b3f28780cc7e910aa2..56949fa39d7ac5d3e313c4e4b1979d5df9e0c0cd 100644
--- a/src/assets/i18n/participant/en.json
+++ b/src/assets/i18n/participant/en.json
@@ -254,6 +254,20 @@
     "overview-questioners-tooltip": "Number of questioners",
     "questions-blocked": "New questions blocked"
   },
+  "quill": {
+    "tooltip-remove": "Delete",
+    "tooltip-action-save": "Save",
+    "tooltip-action": "Edit",
+    "tooltip-label": "Visit URL:",
+    "tooltip-label-link": "Enter link:",
+    "tooltip-placeholder-link": "https://quilljs.com",
+    "tooltip-label-image": "Enter image:",
+    "tooltip-placeholder-image": "Embed URL",
+    "tooltip-label-video": "Enter video:",
+    "tooltip-placeholder-video": "Embed URL",
+    "tooltip-label-formula": "Enter formula:",
+    "tooltip-placeholder-formula": "e=mc^2"
+  },
   "tag-cloud": {
     "demo-data-topic": "Topic %d",
     "overview-question-topic-tooltip": "Number of questions with this topic",