diff --git a/README.md b/README.md index b3fafc9f41..87d28510e8 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,6 @@ OpenSlides Client uses the following software or parts of them: - [@pebula/ngrid-material@4.0.0](undefined), License: UNKNOWN - [@pebula/ngrid@4.0.0](https://github.com/shlomiassaf/ngrid), License: MIT - [@pebula/utils@1.0.2](undefined), License: UNKNOWN -- [@tinymce/tinymce-angular@5.0.1](https://github.com/tinymce/tinymce-angular), License: Apache-2.0 - [@videojs/http-streaming@2.13.1](https://github.com/videojs/http-streaming), License: Apache-2.0 - [acorn@8.7.0](https://github.com/acornjs/acorn), License: MIT - [broadcast-channel@4.10.0](https://github.com/pubkey/broadcast-channel), License: MIT @@ -154,7 +153,6 @@ OpenSlides Client uses the following software or parts of them: - [pdfmake@0.2.4](https://github.com/bpampuch/pdfmake), License: MIT - [rxjs@7.5.4](https://github.com/reactivex/rxjs), License: Apache-2.0 - [tinycolor2@1.4.2](https://github.com/bgrins/TinyColor), License: MIT -- [tinymce@5.10.3](https://github.com/tinymce/tinymce), License: LGPL-2.1 - [ts-dedent@2.2.0](https://github.com/tamino-martinius/node-ts-dedent), License: MIT - [tslib@2.3.1](https://github.com/Microsoft/tslib), License: 0BSD - [tsparticles@1.41.4](https://github.com/matteobruni/tsparticles), License: MIT diff --git a/client/README.md b/client/README.md index 6635d77018..37cf211314 100644 --- a/client/README.md +++ b/client/README.md @@ -39,7 +39,6 @@ OpenSlides uses the following software or parts of them: - [@pebula/ngrid-material@4.0.0](undefined), License: UNKNOWN - [@pebula/ngrid@4.0.0](https://github.com/shlomiassaf/ngrid), License: MIT - [@pebula/utils@1.0.2](undefined), License: UNKNOWN -- [@tinymce/tinymce-angular@5.0.1](https://github.com/tinymce/tinymce-angular), License: Apache-2.0 - [@videojs/http-streaming@2.13.1](https://github.com/videojs/http-streaming), License: Apache-2.0 - [acorn@8.7.0](https://github.com/acornjs/acorn), License: MIT - [broadcast-channel@4.10.0](https://github.com/pubkey/broadcast-channel), License: MIT @@ -63,7 +62,6 @@ OpenSlides uses the following software or parts of them: - [pdfmake@0.2.4](https://github.com/bpampuch/pdfmake), License: MIT - [rxjs@7.5.4](https://github.com/reactivex/rxjs), License: Apache-2.0 - [tinycolor2@1.4.2](https://github.com/bgrins/TinyColor), License: MIT -- [tinymce@5.10.3](https://github.com/tinymce/tinymce), License: LGPL-2.1 - [ts-dedent@2.2.0](https://github.com/tamino-martinius/node-ts-dedent), License: MIT - [tslib@2.3.1](https://github.com/Microsoft/tslib), License: 0BSD - [tsparticles@1.41.4](https://github.com/matteobruni/tsparticles), License: MIT diff --git a/client/angular.json b/client/angular.json index 694a738072..4e9775a3e8 100644 --- a/client/angular.json +++ b/client/angular.json @@ -32,11 +32,6 @@ "src/manifest.webmanifest", "src/sw.js", "src/ngsw-safety.json", - { - "glob": "**/*", - "input": "node_modules/tinymce", - "output": "/tinymce/" - }, { "glob": "**/*", "input": "node_modules/cm-chessboard/assets/", @@ -55,7 +50,7 @@ { "type": "initial", "maximumWarning": "1500kb", - "maximumError": "3500kb" + "maximumError": "4mb" }, { "type": "anyComponentStyle", diff --git a/client/package-lock.json b/client/package-lock.json index 2cf6d3b9bf..3c10ab8932 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -24,7 +24,22 @@ "@ngx-pwa/local-storage": "^17.0.0", "@ngx-translate/core": "^15.0.0", "@ngx-translate/http-loader": "^8.0.0", - "@tinymce/tinymce-angular": "^7.0.0", + "@tiptap/core": "^2.4.0", + "@tiptap/extension-color": "^2.4.0", + "@tiptap/extension-highlight": "^2.4.0", + "@tiptap/extension-image": "^2.4.0", + "@tiptap/extension-link": "^2.4.0", + "@tiptap/extension-subscript": "^2.4.0", + "@tiptap/extension-superscript": "^2.4.0", + "@tiptap/extension-table": "^2.4.0", + "@tiptap/extension-table-cell": "^2.4.0", + "@tiptap/extension-table-header": "^2.4.0", + "@tiptap/extension-table-row": "^2.4.0", + "@tiptap/extension-text-align": "^2.4.0", + "@tiptap/extension-text-style": "^2.4.0", + "@tiptap/extension-underline": "^2.4.0", + "@tiptap/pm": "^2.4.0", + "@tiptap/starter-kit": "^2.4.0", "@types/pdfmake": "^0.2.2", "@videojs/http-streaming": "^2.15.0", "acorn": "^8.8.0", @@ -54,7 +69,6 @@ "qrcode": "^1.5.3", "rxjs": "^7.8.1", "tinycolor2": "1.4.2", - "tinymce": "^5.10.9", "ts-dedent": "^2.2.0", "tslib": "^2.3.0", "tsparticles": "~1.42.4", @@ -5998,6 +6012,11 @@ "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==", "dev": true }, + "node_modules/@remirror/core-constants": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-2.0.2.tgz", + "integrity": "sha512-dyHY+sMF0ihPus3O27ODd4+agdHMEmuRdyiZJ2CCWjPV5UFmn17ZbElvk6WOGVE4rdCJKZQCrPV2BcikOMLUGQ==" + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.18.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", @@ -6317,18 +6336,458 @@ "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "dev": true }, - "node_modules/@tinymce/tinymce-angular": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@tinymce/tinymce-angular/-/tinymce-angular-7.0.0.tgz", - "integrity": "sha512-IKNaG/ihlxE1XCfq6lzULbnsqZO9KNJtlpu5jo6JDJDL9zcFzj/N2A16Kk7rTj1yfmDoB1IXAk/BpMOvgDY8cg==", + "node_modules/@tiptap/core": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.4.0.tgz", + "integrity": "sha512-YJSahk8pkxpCs8SflCZfTnJpE7IPyUWIylfgXM2DefjRQa5DZ+c6sNY0s/zbxKYFQ6AuHVX40r9pCfcqHChGxQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/pm": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-blockquote": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.4.0.tgz", + "integrity": "sha512-nJJy4KsPgQqWTTDOWzFRdjCfG5+QExfZj44dulgDFNh+E66xhamnbM70PklllXJgEcge7xmT5oKM0gKls5XgFw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-bold": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.4.0.tgz", + "integrity": "sha512-csnW6hMDEHoRfxcPRLSqeJn+j35Lgtt1YRiOwn7DlS66sAECGRuoGfCvQSPij0TCDp4VCR9if5Sf8EymhnQumQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-bullet-list": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.4.0.tgz", + "integrity": "sha512-9S5DLIvFRBoExvmZ+/ErpTvs4Wf1yOEs8WXlKYUCcZssK7brTFj99XDwpHFA29HKDwma5q9UHhr2OB2o0JYAdw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-code": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.4.0.tgz", + "integrity": "sha512-wjhBukuiyJMq4cTcK3RBTzUPV24k5n1eEPlpmzku6ThwwkMdwynnMGMAmSF3fErh3AOyOUPoTTjgMYN2d10SJA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-code-block": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.4.0.tgz", + "integrity": "sha512-QWGdv1D56TBGbbJSj2cIiXGJEKguPiAl9ONzJ/Ql1ZksiQsYwx0YHriXX6TOC//T4VIf6NSClHEtwtxWBQ/Csg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0", + "@tiptap/pm": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-color": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-color/-/extension-color-2.4.0.tgz", + "integrity": "sha512-aVuqGtzTIZO93niADdu+Hx8g03X0pS7wjrJcCcYkkDEbC/siC03zlxKZIYBW1Jiabe99Z7/s2KdtLoK6DW2A2g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0", + "@tiptap/extension-text-style": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-document": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.4.0.tgz", + "integrity": "sha512-3jRodQJZDGbXlRPERaloS+IERg/VwzpC1IO6YSJR9jVIsBO6xC29P3cKTQlg1XO7p6ZH/0ksK73VC5BzzTwoHg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-dropcursor": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.4.0.tgz", + "integrity": "sha512-c46HoG2PEEpSZv5rmS5UX/lJ6/kP1iVO0Ax+6JrNfLEIiDULUoi20NqdjolEa38La2VhWvs+o20OviiTOKEE9g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0", + "@tiptap/pm": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-gapcursor": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.4.0.tgz", + "integrity": "sha512-F4y/0J2lseohkFUw9P2OpKhrJ6dHz69ZScABUvcHxjznJLd6+0Zt7014Lw5PA8/m2d/w0fX8LZQ88pZr4quZPQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0", + "@tiptap/pm": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-hard-break": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.4.0.tgz", + "integrity": "sha512-3+Z6zxevtHza5IsDBZ4lZqvNR3Kvdqwxq/QKCKu9UhJN1DUjsg/l1Jn2NilSQ3NYkBYh2yJjT8CMo9pQIu776g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-heading": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.4.0.tgz", + "integrity": "sha512-fYkyP/VMo7YHO76YVrUjd95Qeo0cubWn/Spavmwm1gLTHH/q7xMtbod2Z/F0wd6QHnc7+HGhO7XAjjKWDjldaw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-highlight": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-highlight/-/extension-highlight-2.4.0.tgz", + "integrity": "sha512-p2I/CaMrs6hzpj/dSw6UNobOWTV38yTjPK+B4ShJQ7IN2u/C82KOTOeFfJoFd9KykmpVOVW3w3nKG3ad0HXPuQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-history": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.4.0.tgz", + "integrity": "sha512-gr5qsKAXEVGr1Lyk1598F7drTaEtAxqZiuuSwTCzZzkiwgEQsWMWTWc9F8FlneCEaqe1aIYg6WKWlmYPaFwr0w==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0", + "@tiptap/pm": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-horizontal-rule": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.4.0.tgz", + "integrity": "sha512-yDgxy+YxagcEsBbdWvbQiXYxsv3noS1VTuGwc9G7ZK9xPmBHJ5y0agOkB7HskwsZvJHoaSqNRsh7oZTkf0VR3g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0", + "@tiptap/pm": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-image": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-2.4.0.tgz", + "integrity": "sha512-NIVhRPMO/ONo8OywEd+8zh0Q6Q7EbFHtBxVsvfOKj9KtZkaXQfUO4MzONTyptkvAchTpj9pIzeaEY5fyU87gFA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-italic": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.4.0.tgz", + "integrity": "sha512-aaW/L9q+KNHHK+X73MPloHeIsT191n3VLd3xm6uUcFDnUNvzYJ/q65/1ZicdtCaOLvTutxdrEvhbkrVREX6a8g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-link": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-2.4.0.tgz", + "integrity": "sha512-r3PjT0bjSKAorHAEBPA0icSMOlqALbxVlWU9vAc+Q3ndzt7ht0CTPNewzFF9kjzARABVt1cblXP/2+c0qGzcsg==", "dependencies": { - "tinymce": "^6.0.0 || ^5.5.0", - "tslib": "^2.3.0" + "linkifyjs": "^4.1.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@angular/common": ">=14.0.0", - "@angular/core": ">=14.0.0", - "@angular/forms": ">=14.0.0" + "@tiptap/core": "^2.0.0", + "@tiptap/pm": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-list-item": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.4.0.tgz", + "integrity": "sha512-reUVUx+2cI2NIAqMZhlJ9uK/+zvRzm1GTmlU2Wvzwc7AwLN4yemj6mBDsmBLEXAKPvitfLh6EkeHaruOGymQtg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-ordered-list": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.4.0.tgz", + "integrity": "sha512-Zo0c9M0aowv+2+jExZiAvhCB83GZMjZsxywmuOrdUbq5EGYKb7q8hDyN3hkrktVHr9UPXdPAYTmLAHztTOHYRA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-paragraph": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.4.0.tgz", + "integrity": "sha512-+yse0Ow67IRwcACd9K/CzBcxlpr9OFnmf0x9uqpaWt1eHck1sJnti6jrw5DVVkyEBHDh/cnkkV49gvctT/NyCw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-strike": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.4.0.tgz", + "integrity": "sha512-pE1uN/fQPOMS3i+zxPYMmPmI3keubnR6ivwM+KdXWOMnBiHl9N4cNpJgq1n2eUUGKLurC2qrQHpnVyGAwBS6Vg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-subscript": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-subscript/-/extension-subscript-2.4.0.tgz", + "integrity": "sha512-exLSmSFmYN6AVww5oyroFL3KCwstT0U+ojvVhRD6DQ+Hc81d++lBKANfsWAcllXjZVGPWeMNdE66bV7oFCtQcQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-superscript": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-superscript/-/extension-superscript-2.4.0.tgz", + "integrity": "sha512-s+GsbbERNQCn/hyaw5/82y3wHQ7o5byc/eFAKYo1p3p5eESlDaHY/xVYPt3CGOX2TJWZalgSFEFqBVdTSI8mUQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-table": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-table/-/extension-table-2.4.0.tgz", + "integrity": "sha512-ceIUnPSqVCb+qC0XZSgApoG3dL3MRvWrGl1nIMxEqPgMsD/MP6MsYV1Lx/GmtdUlEEsV1624cGTBiRzeCuWkZA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0", + "@tiptap/pm": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-table-cell": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-table-cell/-/extension-table-cell-2.4.0.tgz", + "integrity": "sha512-zylResMWLvV17Z6+GEDjvvl+YpJqJhNMyJsZPZNx/72OcNCDN3p2d6RGFwhpnCpdzZDD6LGaIgWaTj9oeg53SA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-table-header": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-table-header/-/extension-table-header-2.4.0.tgz", + "integrity": "sha512-FZCOyJHSFsMTCfBh49J1DlwgpUIM5Ivpr57Za8FVvUkk8RKUIOKpNsZqxE+Wrw+2Bvy5H4X7Azb588x0NDqfOQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-table-row": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-table-row/-/extension-table-row-2.4.0.tgz", + "integrity": "sha512-K4FDI4YzyLWZbhIZYYL15uqs6M3QsPZGTpTdkSaxcKMLholcskDSHhJmySxnrjI0+JNAtyIiqlWBfA1/9Zyhng==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-text": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.4.0.tgz", + "integrity": "sha512-LV0bvE+VowE8IgLca7pM8ll7quNH+AgEHRbSrsI3SHKDCYB9gTHMjWaAkgkUVaO1u0IfCrjnCLym/PqFKa+vvg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-text-align": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-2.4.0.tgz", + "integrity": "sha512-wpRe2OiLXTK4kTy4RZEPnPjFbK16kYHPAx1552hLXrOdyxbS7Sdbo+w4x7aGLLZZqZdudCFfkdtnqrc7PDVZdA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-text-style": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.4.0.tgz", + "integrity": "sha512-H0uPWeZ4sXz3o836TDWnpd38qClqzEM2d6QJ9TK+cQ1vE5Gp8wQ5W4fwUV1KAHzpJKE/15+BXBjLyVYQdmXDaQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/extension-underline": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-2.4.0.tgz", + "integrity": "sha512-guWojb7JxUwLz4OKzwNExJwOkhZjgw/ttkXCMBT0PVe55k998MMYe1nvN0m2SeTW9IxurEPtScH4kYJ0XuSm8Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.0.0" + } + }, + "node_modules/@tiptap/pm": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.4.0.tgz", + "integrity": "sha512-B1HMEqGS4MzIVXnpgRZDLm30mxDWj51LkBT/if1XD+hj5gm8B9Q0c84bhvODX6KIs+c6z+zsY9VkVu8w9Yfgxg==", + "dependencies": { + "prosemirror-changeset": "^2.2.1", + "prosemirror-collab": "^1.3.1", + "prosemirror-commands": "^1.5.2", + "prosemirror-dropcursor": "^1.8.1", + "prosemirror-gapcursor": "^1.3.2", + "prosemirror-history": "^1.3.2", + "prosemirror-inputrules": "^1.3.0", + "prosemirror-keymap": "^1.2.2", + "prosemirror-markdown": "^1.12.0", + "prosemirror-menu": "^1.2.4", + "prosemirror-model": "^1.19.4", + "prosemirror-schema-basic": "^1.2.2", + "prosemirror-schema-list": "^1.3.0", + "prosemirror-state": "^1.4.3", + "prosemirror-tables": "^1.3.5", + "prosemirror-trailing-node": "^2.0.7", + "prosemirror-transform": "^1.8.0", + "prosemirror-view": "^1.32.7" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, + "node_modules/@tiptap/starter-kit": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.4.0.tgz", + "integrity": "sha512-DYYzMZdTEnRn9oZhKOeRCcB+TjhNz5icLlvJKoHoOGL9kCbuUyEf8WRR2OSPckI0+KUIPJL3oHRqO4SqSdTjfg==", + "dependencies": { + "@tiptap/core": "^2.4.0", + "@tiptap/extension-blockquote": "^2.4.0", + "@tiptap/extension-bold": "^2.4.0", + "@tiptap/extension-bullet-list": "^2.4.0", + "@tiptap/extension-code": "^2.4.0", + "@tiptap/extension-code-block": "^2.4.0", + "@tiptap/extension-document": "^2.4.0", + "@tiptap/extension-dropcursor": "^2.4.0", + "@tiptap/extension-gapcursor": "^2.4.0", + "@tiptap/extension-hard-break": "^2.4.0", + "@tiptap/extension-heading": "^2.4.0", + "@tiptap/extension-history": "^2.4.0", + "@tiptap/extension-horizontal-rule": "^2.4.0", + "@tiptap/extension-italic": "^2.4.0", + "@tiptap/extension-list-item": "^2.4.0", + "@tiptap/extension-ordered-list": "^2.4.0", + "@tiptap/extension-paragraph": "^2.4.0", + "@tiptap/extension-strike": "^2.4.0", + "@tiptap/extension-text": "^2.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" } }, "node_modules/@ts-morph/common": { @@ -7977,8 +8436,7 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/aria-query": { "version": "5.3.0", @@ -9447,6 +9905,11 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==" + }, "node_modules/critters": { "version": "0.0.22", "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.22.tgz", @@ -10224,7 +10687,6 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "devOptional": true, "engines": { "node": ">=0.12" }, @@ -13669,6 +14131,19 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/linkifyjs": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.1.3.tgz", + "integrity": "sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg==" + }, "node_modules/listenercount": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", @@ -13997,11 +14472,32 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, "node_modules/material-design-icons-iconfont": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/material-design-icons-iconfont/-/material-design-icons-iconfont-6.7.0.tgz", "integrity": "sha512-lSj71DgVv20kO0kGbs42icDzbRot61gEDBLQACzkUuznRQBUYmbxzEkGU6dNBb5fRWHMaScYlAXX96HQ4/cJWA==" }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -15480,6 +15976,11 @@ "node": ">=8" } }, + "node_modules/orderedmap": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz", + "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==" + }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -16267,6 +16768,193 @@ "node": ">= 6" } }, + "node_modules/prosemirror-changeset": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.2.1.tgz", + "integrity": "sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==", + "dependencies": { + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-collab": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz", + "integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==", + "dependencies": { + "prosemirror-state": "^1.0.0" + } + }, + "node_modules/prosemirror-commands": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.5.2.tgz", + "integrity": "sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ==", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-dropcursor": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.1.tgz", + "integrity": "sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0", + "prosemirror-view": "^1.1.0" + } + }, + "node_modules/prosemirror-gapcursor": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.3.2.tgz", + "integrity": "sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==", + "dependencies": { + "prosemirror-keymap": "^1.0.0", + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-view": "^1.0.0" + } + }, + "node_modules/prosemirror-history": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.4.1.tgz", + "integrity": "sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==", + "dependencies": { + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.31.0", + "rope-sequence": "^1.3.0" + } + }, + "node_modules/prosemirror-inputrules": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.4.0.tgz", + "integrity": "sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==", + "dependencies": { + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.0.0" + } + }, + "node_modules/prosemirror-keymap": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.2.tgz", + "integrity": "sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==", + "dependencies": { + "prosemirror-state": "^1.0.0", + "w3c-keyname": "^2.2.0" + } + }, + "node_modules/prosemirror-markdown": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.0.tgz", + "integrity": "sha512-UziddX3ZYSYibgx8042hfGKmukq5Aljp2qoBiJRejD/8MH70siQNz5RB1TrdTPheqLMy4aCe4GYNF10/3lQS5g==", + "dependencies": { + "markdown-it": "^14.0.0", + "prosemirror-model": "^1.20.0" + } + }, + "node_modules/prosemirror-menu": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.2.4.tgz", + "integrity": "sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==", + "dependencies": { + "crelt": "^1.0.0", + "prosemirror-commands": "^1.0.0", + "prosemirror-history": "^1.0.0", + "prosemirror-state": "^1.0.0" + } + }, + "node_modules/prosemirror-model": { + "version": "1.21.3", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.21.3.tgz", + "integrity": "sha512-nt2Xs/RNGepD9hrrkzXvtCm1mpGJoQfFSPktGa0BF/aav6XsnmVGZ9sTXNWRLupAz5SCLa3EyKlFeK7zJWROKg==", + "dependencies": { + "orderedmap": "^2.0.0" + } + }, + "node_modules/prosemirror-schema-basic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.2.tgz", + "integrity": "sha512-/dT4JFEGyO7QnNTe9UaKUhjDXbTNkiWTq/N4VpKaF79bBjSExVV2NXmJpcM7z/gD7mbqNjxbmWW5nf1iNSSGnw==", + "dependencies": { + "prosemirror-model": "^1.19.0" + } + }, + "node_modules/prosemirror-schema-list": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.4.0.tgz", + "integrity": "sha512-nZOIq/AkBSzCENxUyLm5ltWE53e2PLk65ghMN8qLQptOmDVixZlPqtMeQdiNw0odL9vNpalEjl3upgRkuJ/Jyw==", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.7.3" + } + }, + "node_modules/prosemirror-state": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.3.tgz", + "integrity": "sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==", + "dependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-transform": "^1.0.0", + "prosemirror-view": "^1.27.0" + } + }, + "node_modules/prosemirror-tables": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.3.7.tgz", + "integrity": "sha512-oEwX1wrziuxMtwFvdDWSFHVUWrFJWt929kVVfHvtTi8yvw+5ppxjXZkMG/fuTdFo+3DXyIPSKfid+Be1npKXDA==", + "dependencies": { + "prosemirror-keymap": "^1.1.2", + "prosemirror-model": "^1.8.1", + "prosemirror-state": "^1.3.1", + "prosemirror-transform": "^1.2.1", + "prosemirror-view": "^1.13.3" + } + }, + "node_modules/prosemirror-trailing-node": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-2.0.8.tgz", + "integrity": "sha512-ujRYhSuhQb1Jsarh1IHqb2KoSnRiD7wAMDGucP35DN7j5af6X7B18PfdPIrbwsPTqIAj0fyOvxbuPsWhNvylmA==", + "dependencies": { + "@remirror/core-constants": "^2.0.2", + "escape-string-regexp": "^4.0.0" + }, + "peerDependencies": { + "prosemirror-model": "^1.19.0", + "prosemirror-state": "^1.4.2", + "prosemirror-view": "^1.31.2" + } + }, + "node_modules/prosemirror-trailing-node/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prosemirror-transform": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.9.0.tgz", + "integrity": "sha512-5UXkr1LIRx3jmpXXNKDhv8OyAOeLTGuXNwdVfg8x27uASna/wQkr9p6fD3eupGOi4PLJfbezxTyi/7fSJypXHg==", + "dependencies": { + "prosemirror-model": "^1.21.0" + } + }, + "node_modules/prosemirror-view": { + "version": "1.33.8", + "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.33.8.tgz", + "integrity": "sha512-4PhMr/ufz2cdvFgpUAnZfs+0xij3RsFysreeG9V/utpwX7AJtYCDVyuRxzWoMJIEf4C7wVihuBNMPpFLPCiLQw==", + "dependencies": { + "prosemirror-model": "^1.20.0", + "prosemirror-state": "^1.0.0", + "prosemirror-transform": "^1.1.0" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -16311,6 +16999,14 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "engines": { + "node": ">=6" + } + }, "node_modules/qjobs": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", @@ -17080,6 +17776,11 @@ "fsevents": "~2.3.2" } }, + "node_modules/rope-sequence": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", + "integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==" + }, "node_modules/run-async": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", @@ -18531,11 +19232,6 @@ "node": "*" } }, - "node_modules/tinymce": { - "version": "5.10.9", - "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-5.10.9.tgz", - "integrity": "sha512-5bkrors87X9LhYX2xq8GgPHrIgJYHl87YNs+kBcjQ5I3CiUgzo/vFcGvT3MZQ9QHsEeYMhYO6a5CLGGffR8hMg==" - }, "node_modules/tmp": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", @@ -18889,6 +19585,11 @@ "node": "*" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==" + }, "node_modules/undici": { "version": "6.11.1", "resolved": "https://registry.npmjs.org/undici/-/undici-6.11.1.tgz", @@ -19226,6 +19927,11 @@ "node": ">=0.10.0" } }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==" + }, "node_modules/watchpack": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", diff --git a/client/package.json b/client/package.json index 82bb4556bd..292bbb2c52 100644 --- a/client/package.json +++ b/client/package.json @@ -52,7 +52,22 @@ "@ngx-pwa/local-storage": "^17.0.0", "@ngx-translate/core": "^15.0.0", "@ngx-translate/http-loader": "^8.0.0", - "@tinymce/tinymce-angular": "^7.0.0", + "@tiptap/core": "^2.4.0", + "@tiptap/extension-color": "^2.4.0", + "@tiptap/extension-highlight": "^2.4.0", + "@tiptap/extension-image": "^2.4.0", + "@tiptap/extension-link": "^2.4.0", + "@tiptap/extension-subscript": "^2.4.0", + "@tiptap/extension-superscript": "^2.4.0", + "@tiptap/extension-table": "^2.4.0", + "@tiptap/extension-table-cell": "^2.4.0", + "@tiptap/extension-table-header": "^2.4.0", + "@tiptap/extension-table-row": "^2.4.0", + "@tiptap/extension-text-align": "^2.4.0", + "@tiptap/extension-text-style": "^2.4.0", + "@tiptap/extension-underline": "^2.4.0", + "@tiptap/pm": "^2.4.0", + "@tiptap/starter-kit": "^2.4.0", "@types/pdfmake": "^0.2.2", "@videojs/http-streaming": "^2.15.0", "acorn": "^8.8.0", @@ -82,7 +97,6 @@ "qrcode": "^1.5.3", "rxjs": "^7.8.1", "tinycolor2": "1.4.2", - "tinymce": "^5.10.9", "ts-dedent": "^2.2.0", "tslib": "^2.3.0", "tsparticles": "~1.42.4", diff --git a/client/src/app/infrastructure/utils/dom-helpers.spec.ts b/client/src/app/infrastructure/utils/dom-helpers.spec.ts index bba7f12795..58da63d54b 100644 --- a/client/src/app/infrastructure/utils/dom-helpers.spec.ts +++ b/client/src/app/infrastructure/utils/dom-helpers.spec.ts @@ -16,7 +16,8 @@ import { removeCSSClass, replaceHtmlEntities, serializeTag, - sortHtmlAttributes + sortHtmlAttributes, + unwrapNode } from './dom-helpers'; describe(`utils: dom helpers`, () => { @@ -196,6 +197,29 @@ describe(`utils: dom helpers`, () => { }); }); + describe(`unwrapNode function`, () => { + it(`unwrapNode removes sourrounding node`, () => { + const el = document.createElement(`body`); + el.innerHTML = `
`; + unwrapNode(el.querySelector(`.outer`)); + expect(el.outerHTML).toBe(`
`); + }); + + it(`unwrapNode preserves multiple inner nodes`, () => { + const el = document.createElement(`body`); + el.innerHTML = `
`; + unwrapNode(el.querySelector(`.outer`)); + expect(el.outerHTML).toBe(`
`); + }); + + it(`unwrapNode removes empty node`, () => { + const el = document.createElement(`body`); + el.innerHTML = `
`; + unwrapNode(el.querySelector(`.outer`)); + expect(el.outerHTML).toBe(``); + }); + }); + describe(`addCSSClass function`, () => { it(`adds a class`, () => { const el = document.createElement(`div`); diff --git a/client/src/app/infrastructure/utils/dom-helpers.ts b/client/src/app/infrastructure/utils/dom-helpers.ts index 08aeacf12c..26a5a0dd8f 100644 --- a/client/src/app/infrastructure/utils/dom-helpers.ts +++ b/client/src/app/infrastructure/utils/dom-helpers.ts @@ -201,6 +201,20 @@ export function findNextAuntNode(node: Node): Node | null { return null; } +/** + * Removes the sourounding tag of a node + * + * @param {Node} node + * @returns {Node} + */ +export function unwrapNode(node: Node): void { + const parent = node.parentNode; + while (node.firstChild) { + parent.insertBefore(node.firstChild, node); + } + parent.removeChild(node); +} + /** * This method adds a CSS class name to a given node. * @@ -439,7 +453,8 @@ export function isInlineElement(element: Element): boolean { `TT`, `INS`, `DEL`, - `STRIKE` + `STRIKE`, + `MARK` ]; if (element) { return inlineElements.indexOf(element.nodeName) > -1; diff --git a/client/src/app/infrastructure/utils/functions.spec.ts b/client/src/app/infrastructure/utils/functions.spec.ts index cfaca4907c..f6f06a30f4 100644 --- a/client/src/app/infrastructure/utils/functions.spec.ts +++ b/client/src/app/infrastructure/utils/functions.spec.ts @@ -15,6 +15,8 @@ import { ListUpdateData, mmToPoints, objectToFormattedString, + parseLetterNumber, + parseRomanNumber, partitionModelsForUpdate, reconvertChars, replaceObjectKeys, @@ -67,6 +69,62 @@ describe(`utils: functions`, () => { }); }); + describe(`parseLetterNumber function`, () => { + it(`test one digit numbers`, () => { + expect(parseLetterNumber(`a`)).toBe(1); + expect(parseLetterNumber(`b`)).toBe(2); + expect(parseLetterNumber(`g`)).toBe(7); + expect(parseLetterNumber(`n`)).toBe(14); + }); + + it(`test two digit numbers`, () => { + expect(parseLetterNumber(`aa`)).toBe(27); + expect(parseLetterNumber(`be`)).toBe(57); + expect(parseLetterNumber(`gt`)).toBe(202); + expect(parseLetterNumber(`no`)).toBe(379); + }); + + it(`test big numbers`, () => { + expect(parseLetterNumber(`popeye`)).toBe(197241907); + expect(parseLetterNumber(`openslides`)).toBe(84828503480493); + expect(parseLetterNumber(`magma`)).toBe(5963335); + }); + + it(`test case irrelevant`, () => { + expect(parseLetterNumber(`scHwaRzteE`)).toBe(103858431216103); + }); + }); + + describe(`parseRomanNumber function`, () => { + it(`test simple one digit roman numbers`, () => { + expect(parseRomanNumber(`I`)).toBe(1); + expect(parseRomanNumber(`L`)).toBe(50); + expect(parseRomanNumber(`M`)).toBe(1000); + }); + + it(`test summation`, () => { + expect(parseRomanNumber(`III`)).toBe(3); + expect(parseRomanNumber(`XII`)).toBe(12); + expect(parseRomanNumber(`CV`)).toBe(105); + expect(parseRomanNumber(`DX`)).toBe(510); + }); + + it(`test subtraction`, () => { + expect(parseRomanNumber(`XL`)).toBe(40); + expect(parseRomanNumber(`VX`)).toBe(5); + expect(parseRomanNumber(`ICD`)).toBe(399); + }); + + it(`test complex operations`, () => { + expect(parseRomanNumber(`IDC`)).toBe(599); + expect(parseRomanNumber(`CMVI`)).toBe(906); + }); + + it(`test case irrelevant`, () => { + expect(parseRomanNumber(`cMvI`)).toBe(906); + }); + }); + describe(`toBoolean function`, () => { it(`test with various values`, () => { expect(toBoolean(`1`)).toBe(true); diff --git a/client/src/app/infrastructure/utils/functions.ts b/client/src/app/infrastructure/utils/functions.ts index 10d76d000b..5378655194 100644 --- a/client/src/app/infrastructure/utils/functions.ts +++ b/client/src/app/infrastructure/utils/functions.ts @@ -36,6 +36,45 @@ export function reconvertChars(text: string): string { .replace(/ß|ß/g, `ß`); } +/** + * Parses a roman number string into a number + * + * Example: a -> 1, ab -> 28, ... + */ +export function parseRomanNumber(roman: string): number { + roman = roman.toUpperCase(); + let value = 0; + const values = { I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000 }; + let i = roman.length; + let lastVal = 0; + while (i--) { + if (values[roman.charAt(i)] >= lastVal) { + value += values[roman.charAt(i)]; + } else { + value -= values[roman.charAt(i)]; + } + lastVal = values[roman.charAt(i)]; + } + + return value; +} + +/** + * Parses a list item index of letters. + * + * Example: a -> 1, ab -> 28, ... + */ +export function parseLetterNumber(str: string): number { + const alphaVal = (s: string): number => s.toLowerCase().charCodeAt(0) - 97 + 1; + let value = 0; + let i = str.length; + while (i--) { + const factor = Math.pow(26, str.length - i - 1); + value += alphaVal(str.charAt(i)) * factor; + } + return value; +} + /** * Helper to remove html tags from a string. * CAUTION: It is just a basic "don't show distracting html tags in a diff --git a/client/src/app/site/base/base.component.ts b/client/src/app/site/base/base.component.ts index bc511898d6..7f8bcd2bab 100644 --- a/client/src/app/site/base/base.component.ts +++ b/client/src/app/site/base/base.component.ts @@ -159,20 +159,4 @@ export abstract class BaseComponent extends BaseUiComponent implements OnDestroy * Should be overwritten by children which need swipe gestures */ protected swipe(_e: TouchEvent, _when: string): void {} - - /** - * TinyMCE Init callback. Used for certain mobile editors - * @param event - */ - public onInitTinyMce(event: any): void { - if (event.event.target.settings.theme === `mobile`) { - this.saveHint = true; - } else { - event.editor.focus(); - } - } - - public onLeaveTinyMce(_event: any): void { - this.saveHint = false; - } } diff --git a/client/src/app/site/pages/meetings/pages/agenda/modules/topics/pages/topic-detail/components/topic-detail/topic-detail.component.html b/client/src/app/site/pages/meetings/pages/agenda/modules/topics/pages/topic-detail/components/topic-detail/topic-detail.component.html index 66b8531d09..32a03864eb 100644 --- a/client/src/app/site/pages/meetings/pages/agenda/modules/topics/pages/topic-detail/components/topic-detail/topic-detail.component.html +++ b/client/src/app/site/pages/meetings/pages/agenda/modules/topics/pages/topic-detail/components/topic-detail/topic-detail.component.html @@ -72,6 +72,7 @@

} + @if (topic.hasAttachments()) {

@@ -88,6 +89,7 @@

} } + @if (editTopic && topicForm) {
@@ -99,13 +101,16 @@

}

+

{{ 'Text' | translate }}

- +
+ + @if (newTopic) {
@@ -121,6 +126,7 @@

{{ 'Text' | translate }}

+
@@ -139,6 +145,7 @@

{{ 'Text' | translate }}

} + @if (!editTopic) { } diff --git a/client/src/app/site/pages/meetings/pages/assignments/pages/assignment-detail/components/assignment-detail/assignment-detail.component.html b/client/src/app/site/pages/meetings/pages/assignments/pages/assignment-detail/components/assignment-detail/assignment-detail.component.html index 56f4a24619..0acf743b6d 100644 --- a/client/src/app/site/pages/meetings/pages/assignments/pages/assignment-detail/components/assignment-detail/assignment-detail.component.html +++ b/client/src/app/site/pages/meetings/pages/assignments/pages/assignment-detail/components/assignment-detail/assignment-detail.component.html @@ -256,7 +256,7 @@

{{ 'Candidates' | translate }}

{{ 'Description' | translate }}:

- + @if (tagsAvailable) { diff --git a/client/src/app/site/pages/meetings/pages/home/pages/start/components/start/start.component.html b/client/src/app/site/pages/meetings/pages/home/pages/start/components/start/start.component.html index dc8f43e409..2ec59c56b4 100644 --- a/client/src/app/site/pages/meetings/pages/home/pages/start/components/start/start.component.html +++ b/client/src/app/site/pages/meetings/pages/home/pages/start/components/start/start.component.html @@ -32,7 +32,7 @@

{{ welcomeTitle }}

{{ 'The title is required' | translate }}
- + } diff --git a/client/src/app/site/pages/meetings/pages/home/pages/start/start.module.ts b/client/src/app/site/pages/meetings/pages/home/pages/start/start.module.ts index 7970ea88c8..338ef017e0 100644 --- a/client/src/app/site/pages/meetings/pages/home/pages/start/start.module.ts +++ b/client/src/app/site/pages/meetings/pages/home/pages/start/start.module.ts @@ -5,7 +5,7 @@ import { MatCardModule } from '@angular/material/card'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { OpenSlidesTranslationModule } from 'src/app/site/modules/translations'; -import { EditorModule } from 'src/app/ui/modules/editor/editor.module'; +import { EditorModule } from 'src/app/ui/modules/editor'; import { HeadBarModule } from 'src/app/ui/modules/head-bar'; import { PipesModule } from 'src/app/ui/pipes/pipes.module'; diff --git a/client/src/app/site/pages/meetings/pages/meeting-settings/pages/meeting-settings-group-detail/components/meeting-settings-group-detail-field/meeting-settings-group-detail-field.component.html b/client/src/app/site/pages/meetings/pages/meeting-settings/pages/meeting-settings-group-detail/components/meeting-settings-group-detail-field/meeting-settings-group-detail-field.component.html index 957f94463d..ec88cf6b87 100644 --- a/client/src/app/site/pages/meetings/pages/meeting-settings/pages/meeting-settings-group-detail/components/meeting-settings-group-detail-field/meeting-settings-group-detail-field.component.html +++ b/client/src/app/site/pages/meetings/pages/meeting-settings/pages/meeting-settings-group-detail/components/meeting-settings-group-detail-field/meeting-settings-group-detail-field.component.html @@ -8,6 +8,7 @@ @if (!isExcludedType(setting.type!)) { + @switch (setting.type) { @case ('choice') { @@ -19,6 +20,7 @@ } } + {{ setting.label | translate }} @if (error) { @@ -29,7 +31,9 @@ @if (error) { {{ error }} } + + @if (getRestrictedValue(setting.choices)) { @@ -44,6 +48,7 @@ } + + @if (setting.type === 'email') { } + @if (setting.helpText) { {{ setting.helpText | translate }} } } + @if (isExcludedType(setting.type!)) {
@if (setting.type === 'boolean') { @@ -94,6 +102,7 @@ }
} + @if (setting.type === 'text') {
@@ -107,6 +116,7 @@
} + @if (setting.type === 'datetime' || setting.type === 'date') {
@@ -143,6 +153,7 @@
} + @if (setting.type === 'daterange') {
@@ -155,11 +166,12 @@ >
} + @if (setting.type === 'markupText') {

{{ setting.label | translate }}

- + @if (updateSuccessIcon) { error @@ -167,6 +179,7 @@

{{ setting.label | translate }}

} + @if (setting.type === 'translations' || setting.type === 'ranking') {
diff --git a/client/src/app/site/pages/meetings/pages/meeting-settings/pages/meeting-settings-group-detail/components/meeting-settings-group-detail-field/meeting-settings-group-detail-field.component.ts b/client/src/app/site/pages/meetings/pages/meeting-settings/pages/meeting-settings-group-detail/components/meeting-settings-group-detail-field/meeting-settings-group-detail-field.component.ts index 2b544b1623..480b7a216e 100644 --- a/client/src/app/site/pages/meetings/pages/meeting-settings/pages/meeting-settings-group-detail/components/meeting-settings-group-detail-field/meeting-settings-group-detail-field.component.ts +++ b/client/src/app/site/pages/meetings/pages/meeting-settings/pages/meeting-settings-group-detail/components/meeting-settings-group-detail-field/meeting-settings-group-detail-field.component.ts @@ -437,22 +437,10 @@ export class MeetingSettingsGroupDetailFieldComponent extends BaseComponent impl return excluded.includes(type); } - /** - * Amends the application-wide tinyMCE settings with update triggers that - * send updated values only after leaving focus (Blur) or closing the editor (Remove) - * - * @returns an instance of tinyMCE settings with additional setup definitions - */ - public getTinyMceSettings(): object { - return { - setup: (editor: any): void => { - editor.on(`Blur`, (ev: any) => { - if (ev.target.getContent() !== this.internalValue) { - this.sendUpdate(ev.target.getContent()); - } - }); - } - }; + public onEditorBlur(): void { + if (this.value !== this.internalValue) { + this.sendUpdate(this.value); + } } /** diff --git a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.html b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.html index a42af6e854..e8dc739138 100644 --- a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.html +++ b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.html @@ -107,10 +107,7 @@

}

- + } @@ -131,11 +128,7 @@

}

- + @if ( reasonRequired && contentForm.get('reason')?.invalid && diff --git a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.ts b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.ts index c0267e7600..aa382f8ee4 100644 --- a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.ts +++ b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/amendment-create-wizard/amendment-create-wizard.component.ts @@ -17,7 +17,6 @@ import { MotionLineNumberingService, ParagraphToChoose } from '../../../../services/common/motion-line-numbering.service/motion-line-numbering.service'; -import { MotionTinyMceConfig } from '../../definitions/tinymce-config'; @Component({ selector: `os-amendment-create-wizard`, @@ -69,8 +68,6 @@ export class AmendmentCreateWizardComponent extends BaseMeetingComponent impleme */ public multipleParagraphsAllowed = false; - public tinyMceConfig = MotionTinyMceConfig; - private _parentMotionId: Id | null = null; public constructor( diff --git a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/motion-content/motion-content.component.html b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/motion-content/motion-content.component.html index 2e8be0c903..c2a05668ae 100644 --- a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/motion-content/motion-content.component.html +++ b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/motion-content/motion-content.component.html @@ -43,7 +43,7 @@ } } -
+ @if (newMotion) {
@@ -103,11 +103,7 @@

{{ preamble }}

} - + @if (contentForm.get('text')?.invalid && (contentForm.get('text')?.dirty || contentForm.get('text')?.touched)) {
{{ 'This field is required.' | translate }} @@ -150,13 +146,10 @@

@if (!editMotion) { } + @if (editMotion) { - + } @if ( reasonRequired && @@ -212,12 +205,14 @@

} + @if (canChangeMetadata) { @if (newMotion) {
} + @if (editMotion && minSupporters) {
@@ -239,6 +234,7 @@

} + @if (editMotion) {
diff --git a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/motion-content/motion-content.component.ts b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/motion-content/motion-content.component.ts index 1b54bbca9f..31fe855e28 100644 --- a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/motion-content/motion-content.component.ts +++ b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/motion-content/motion-content.component.ts @@ -20,7 +20,6 @@ import { getParticipantMinimalSubscriptionConfig } from '../../../../../particip import { MotionControllerService } from '../../../../services/common/motion-controller.service'; import { MotionPermissionService } from '../../../../services/common/motion-permission.service/motion-permission.service'; import { BaseMotionDetailChildComponent } from '../../base/base-motion-detail-child.component'; -import { MotionTinyMceConfig } from '../../definitions/tinymce-config'; import { MotionContentChangeRecommendationDialogComponentData } from '../../modules/motion-change-recommendation-dialog/components/motion-content-change-recommendation-dialog/motion-content-change-recommendation-dialog.component'; import { MotionChangeRecommendationDialogService } from '../../modules/motion-change-recommendation-dialog/services/motion-change-recommendation-dialog.service'; @@ -59,8 +58,6 @@ export class MotionContentComponent extends BaseMotionDetailChildComponent { @Output() public validStateChanged = new EventEmitter(); - public tinyMceConfig = MotionTinyMceConfig; - private finalEditMode = false; public get showPreamble(): boolean { @@ -161,18 +158,6 @@ export class MotionContentComponent extends BaseMotionDetailChildComponent { .subscribe(motions => this.updateMotionNumbersSubject(motions)); } - /** - * clicking Shift and Enter will save automatically - * - * @param event has the code - */ - public onKeyDown(event: KeyboardEvent): void { - if (event.key === `Enter` && event.shiftKey) { - this.save.emit(this.contentForm.value); - this.updateMotionNumbersSubject(); - } - } - /** * Click handler for attachments * diff --git a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/motion-detail-original-change-recommendations/motion-detail-original-change-recommendations.component.html b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/motion-detail-original-change-recommendations/motion-detail-original-change-recommendations.component.html index 3da8c1abe8..2ab7a424b5 100644 --- a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/motion-detail-original-change-recommendations/motion-detail-original-change-recommendations.component.html +++ b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/components/motion-detail-original-change-recommendations/motion-detail-original-change-recommendations.component.html @@ -1,4 +1,4 @@ -
+
@if (!textLoaded) {

diff --git a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/definitions/tinymce-config.ts b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/definitions/tinymce-config.ts deleted file mode 100644 index 91f23f1cd1..0000000000 --- a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/definitions/tinymce-config.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { marker as _ } from '@colsen1991/ngx-translate-extract-marker'; - -export const MotionTinyMceConfig = { - style_formats: [ - { - title: _(`Headers`), - items: [ - { title: _(`Header 1`), format: `h1` }, - { title: _(`Header 2`), format: `h2` }, - { title: _(`Header 3`), format: `h3` }, - { title: _(`Header 4`), format: `h4` }, - { title: _(`Header 5`), format: `h5` }, - { title: _(`Header 6`), format: `h6` } - ] - }, - { - title: _(`Inline`), - items: [ - { title: _(`Bold`), icon: `bold`, format: `bold` }, - { title: _(`Italic`), icon: `italic`, format: `italic` }, - { title: _(`Underline`), icon: `underline`, format: `underline` }, - { title: _(`Strikethrough`), format: `strikethrough` }, - { title: _(`Superscript`), icon: `superscript`, format: `superscript` }, - { title: _(`Subscript`), icon: `subscript`, format: `subscript` }, - { title: _(`Code`), format: `code` } - ] - }, - { - title: _(`Blocks`), - items: [ - { title: _(`Paragraph`), format: `p` }, - { title: _(`Div`), format: `div` }, - { title: _(`Pre`), format: `pre` } - ] - }, - { - title: _(`Alignment`), - items: [ - { title: _(`Left`), format: `alignleft` }, - { title: _(`Center`), format: `aligncenter` }, - { title: _(`Right`), format: `alignright` } - ] - } - ] -}; diff --git a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/modules/motion-change-recommendation-dialog/components/motion-content-change-recommendation-dialog/motion-content-change-recommendation-dialog.component.html b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/modules/motion-change-recommendation-dialog/components/motion-content-change-recommendation-dialog/motion-content-change-recommendation-dialog.component.html index f9348dbabd..ee7fcb5c02 100644 --- a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/modules/motion-change-recommendation-dialog/components/motion-content-change-recommendation-dialog/motion-content-change-recommendation-dialog.component.html +++ b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/modules/motion-change-recommendation-dialog/components/motion-content-change-recommendation-dialog/motion-content-change-recommendation-dialog.component.html @@ -25,7 +25,7 @@

}
- +
{{ 'Public' | translate }} diff --git a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/modules/motion-change-recommendation-dialog/components/motion-content-change-recommendation-dialog/motion-content-change-recommendation-dialog.component.ts b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/modules/motion-change-recommendation-dialog/components/motion-content-change-recommendation-dialog/motion-content-change-recommendation-dialog.component.ts index ffce200208..355cc07b7e 100644 --- a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/modules/motion-change-recommendation-dialog/components/motion-content-change-recommendation-dialog/motion-content-change-recommendation-dialog.component.ts +++ b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/modules/motion-change-recommendation-dialog/components/motion-content-change-recommendation-dialog/motion-content-change-recommendation-dialog.component.ts @@ -66,13 +66,6 @@ export class MotionContentChangeRecommendationDialogComponent extends BaseChange */ public lineRange!: LineRange; - public getTinyMceSettings(): object { - return { - toolbar: `undo redo | bold italic underline strikethrough - | removeformat | bullist numlist | outdent indent | link charmap code` - }; - } - /** * Creates the forms for the Motion and the MotionVersion */ diff --git a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/modules/motion-change-recommendation-dialog/motion-change-recommendation-dialog.module.ts b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/modules/motion-change-recommendation-dialog/motion-change-recommendation-dialog.module.ts index d220937249..3c90b8d314 100644 --- a/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/modules/motion-change-recommendation-dialog/motion-change-recommendation-dialog.module.ts +++ b/client/src/app/site/pages/meetings/pages/motions/pages/motion-detail/modules/motion-change-recommendation-dialog/motion-change-recommendation-dialog.module.ts @@ -23,9 +23,9 @@ import { MotionTitleChangeRecommendationDialogComponent } from './components/mot MatFormFieldModule, MatRadioModule, MatButtonModule, + EditorModule, ReactiveFormsModule, - OpenSlidesTranslationModule.forChild(), - EditorModule + OpenSlidesTranslationModule.forChild() ] }) export class MotionChangeRecommendationDialogModule { diff --git a/client/src/app/site/pages/meetings/pages/motions/styles/motion-common-styles.scss b/client/src/app/site/pages/meetings/pages/motions/styles/motion-common-styles.scss index 1542e978df..5b29e64e27 100644 --- a/client/src/app/site/pages/meetings/pages/motions/styles/motion-common-styles.scss +++ b/client/src/app/site/pages/meetings/pages/motions/styles/motion-common-styles.scss @@ -42,6 +42,7 @@ height: 22px; position: absolute; left: 0; + text-align: left; padding-right: 18px; &:after { diff --git a/client/src/app/ui/base/base-form-control.ts b/client/src/app/ui/base/base-form-control.ts index c2933135ca..f10ece9fac 100644 --- a/client/src/app/ui/base/base-form-control.ts +++ b/client/src/app/ui/base/base-form-control.ts @@ -57,7 +57,8 @@ export abstract class BaseFormControlComponent implements ControlValueAccesso private readonly _id: number; private _disabled = false; - protected fb = inject(UntypedFormBuilder); + protected fb: UntypedFormBuilder = inject(UntypedFormBuilder); + public constructor() { this._id = ++BaseFormControlComponent.formControlId; this.contentForm = this.createForm(); diff --git a/client/src/app/ui/modules/editor/components/editor-embed-dialog/editor-embed-dialog.component.html b/client/src/app/ui/modules/editor/components/editor-embed-dialog/editor-embed-dialog.component.html new file mode 100644 index 0000000000..310c63ca0d --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor-embed-dialog/editor-embed-dialog.component.html @@ -0,0 +1,20 @@ +

Insert/Edit Link

+
+
+ + Source + + +
+ +
+ + Title + + +
+
+
+ + +
diff --git a/client/src/app/ui/modules/editor/components/editor-embed-dialog/editor-embed-dialog.component.scss b/client/src/app/ui/modules/editor/components/editor-embed-dialog/editor-embed-dialog.component.scss new file mode 100644 index 0000000000..bc76a27e25 --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor-embed-dialog/editor-embed-dialog.component.scss @@ -0,0 +1,3 @@ +mat-form-field { + width: 100%; +} diff --git a/client/src/app/ui/modules/editor/components/editor-embed-dialog/editor-embed-dialog.component.ts b/client/src/app/ui/modules/editor/components/editor-embed-dialog/editor-embed-dialog.component.ts new file mode 100644 index 0000000000..261adb505a --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor-embed-dialog/editor-embed-dialog.component.ts @@ -0,0 +1,40 @@ +import { Component, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; + +interface EditorEmbedData { + src: string; + title: string; +} + +interface EditorEmbedDialogInput { + embed?: EditorEmbedData; +} + +export interface EditorEmbedDialogOutput { + action: `cancel` | `set-embed`; + embed?: EditorEmbedData; +} + +@Component({ + selector: `os-editor-image-dialog`, + templateUrl: `./editor-embed-dialog.component.html`, + styleUrls: [`editor-embed-dialog.component.scss`] +}) +export class EditorEmbedDialogComponent { + public embed: EditorEmbedData; + + public constructor( + @Inject(MAT_DIALOG_DATA) public data: EditorEmbedDialogInput, + private dialogRef: MatDialogRef + ) { + this.embed = data.embed; + } + + public cancel(): void { + this.dialogRef.close({ action: `cancel` }); + } + + public save(): void { + this.dialogRef.close({ action: `set-embed`, embed: this.embed }); + } +} diff --git a/client/src/app/ui/modules/editor/components/editor-html-dialog/editor-html-dialog.component.html b/client/src/app/ui/modules/editor/components/editor-html-dialog/editor-html-dialog.component.html new file mode 100644 index 0000000000..29dbf9143e --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor-html-dialog/editor-html-dialog.component.html @@ -0,0 +1,8 @@ +

Edit HTML content

+
+ +
+
+ + +
diff --git a/client/src/app/ui/modules/editor/components/editor-html-dialog/editor-html-dialog.component.scss b/client/src/app/ui/modules/editor/components/editor-html-dialog/editor-html-dialog.component.scss new file mode 100644 index 0000000000..b8f7dd5262 --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor-html-dialog/editor-html-dialog.component.scss @@ -0,0 +1,3 @@ +textarea { + font-size: 16px; +} diff --git a/client/src/app/ui/modules/editor/components/editor-html-dialog/editor-html-dialog.component.ts b/client/src/app/ui/modules/editor/components/editor-html-dialog/editor-html-dialog.component.ts new file mode 100644 index 0000000000..c5b6150f78 --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor-html-dialog/editor-html-dialog.component.ts @@ -0,0 +1,52 @@ +import { Component, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; + +export interface EditorHtmlDialogOutput { + action: `cancel` | `set`; + html?: string; +} + +@Component({ + selector: `os-editor-html-dialog`, + templateUrl: `./editor-html-dialog.component.html`, + styleUrls: [`./editor-html-dialog.component.scss`] +}) +export class EditorHtmlDialogComponent { + public isUpdate: boolean; + + public constructor( + @Inject(MAT_DIALOG_DATA) public data: string, + private dialogRef: MatDialogRef + ) { + this.data = this.formatHtml(this.data); + } + + // https://stackoverflow.com/a/60338028 + public formatHtml(html: string): string { + const tab = `\t`; + let result = ``; + let indent = ``; + + html.split(/>\s*\r\n`; + + if (element.match(/^]*[^\/]$/) && !element.startsWith(`input`)) { + indent += tab; + } + }); + + return result.substring(1, result.length - 3); + } + + public cancel(): void { + this.dialogRef.close({ action: `cancel` }); + } + + public save(): void { + this.dialogRef.close({ action: `set`, html: this.data }); + } +} diff --git a/client/src/app/ui/modules/editor/components/editor-image-dialog/editor-image-dialog.component.html b/client/src/app/ui/modules/editor/components/editor-image-dialog/editor-image-dialog.component.html new file mode 100644 index 0000000000..086e12447a --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor-image-dialog/editor-image-dialog.component.html @@ -0,0 +1,27 @@ +

Insert/Edit Link

+
+
+ + Source + + +
+ +
+ + Title + + +
+ +
+ + Image description + + +
+
+
+ + +
diff --git a/client/src/app/ui/modules/editor/components/editor-image-dialog/editor-image-dialog.component.scss b/client/src/app/ui/modules/editor/components/editor-image-dialog/editor-image-dialog.component.scss new file mode 100644 index 0000000000..bc76a27e25 --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor-image-dialog/editor-image-dialog.component.scss @@ -0,0 +1,3 @@ +mat-form-field { + width: 100%; +} diff --git a/client/src/app/ui/modules/editor/components/editor-image-dialog/editor-image-dialog.component.ts b/client/src/app/ui/modules/editor/components/editor-image-dialog/editor-image-dialog.component.ts new file mode 100644 index 0000000000..17d8b77dd5 --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor-image-dialog/editor-image-dialog.component.ts @@ -0,0 +1,41 @@ +import { Component, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; + +interface EditorImageData { + src: string; + alt: string; + title: string; +} + +interface EditorImageDialogInput { + image?: EditorImageData; +} + +export interface EditorImageDialogOutput { + action: `cancel` | `set-image`; + image?: EditorImageData; +} + +@Component({ + selector: `os-editor-image-dialog`, + templateUrl: `./editor-image-dialog.component.html`, + styleUrls: [`editor-image-dialog.component.scss`] +}) +export class EditorImageDialogComponent { + public image: EditorImageData; + + public constructor( + @Inject(MAT_DIALOG_DATA) public data: EditorImageDialogInput, + private dialogRef: MatDialogRef + ) { + this.image = data.image; + } + + public cancel(): void { + this.dialogRef.close({ action: `cancel` }); + } + + public save(): void { + this.dialogRef.close({ action: `set-image`, image: this.image }); + } +} diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html new file mode 100644 index 0000000000..f24dc1d19a --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.html @@ -0,0 +1,35 @@ +

Insert/Edit Link

+
+
+ + URL + + +
+ +
+ @if (data.needsText) { + + Text to display + + + } +
+ +
+ + Open link in + + +
+
+
+ + @if (isUpdate) { + + } + +
diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss new file mode 100644 index 0000000000..bc76a27e25 --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.scss @@ -0,0 +1,3 @@ +mat-form-field { + width: 100%; +} diff --git a/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts new file mode 100644 index 0000000000..e3d2c7e113 --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor-link-dialog/editor-link-dialog.component.ts @@ -0,0 +1,57 @@ +import { Component, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; + +interface EditorLinkDialogInput { + link?: { href: string; target?: string }; + needsText?: boolean; +} + +export interface EditorLinkDialogOutput { + action: `remove-link` | `cancel` | `set-link`; + link?: { href: string; target?: string }; + text?: string; +} + +@Component({ + selector: `os-editor-link-dialog`, + templateUrl: `./editor-link-dialog.component.html`, + styleUrls: [`editor-link-dialog.component.scss`] +}) +export class EditorLinkDialogComponent { + public isUpdate: boolean; + + public link: { href: string; target?: string }; + + public text = ``; + + public constructor( + @Inject(MAT_DIALOG_DATA) public data: EditorLinkDialogInput, + private dialogRef: MatDialogRef + ) { + this.link = data.link; + this.isUpdate = !!data.link && !!data.link.href; + if (!this.link.target) { + this.link.target = `_self`; + } + } + + public removeLink(): void { + this.dialogRef.close({ action: `remove-link` }); + } + + public cancel(): void { + this.dialogRef.close({ action: `cancel` }); + } + + public save(): void { + if (this.link.href && !/^[a-zA-Z]+:\/\//.test(this.link.href)) { + this.link.href = `http://` + this.link.href; + } + + if (this.data.needsText) { + this.dialogRef.close({ action: `set-link`, link: this.link, text: this.text || this.link }); + } else { + this.dialogRef.close({ action: `set-link`, link: this.link }); + } + } +} diff --git a/client/src/app/ui/modules/editor/components/editor/editor.component.html b/client/src/app/ui/modules/editor/components/editor/editor.component.html index 1a8d066eb0..9f3e609147 100644 --- a/client/src/app/ui/modules/editor/components/editor/editor.component.html +++ b/client/src/app/ui/modules/editor/components/editor/editor.component.html @@ -1,3 +1,287 @@ -@if (hasInitialized | async) { - -} +
+ @if (editorReady) { +
+
+ + + +
+ + + + + + + + + @for (level of headingLevels; track level) { + + } + + + + + + + + + + + + + + + +
+ + + + +
+ +
+ + +
+
+ + +
+ + +
+ + +
+ +
+ + + +
+ +
+ + + +
+ + +
+ } + +
+
+ + + @for (color of textColorSet; track color) { + + } + + + + @for (color of backgroundColorSet; track color) { + + } + diff --git a/client/src/app/ui/modules/editor/components/editor/editor.component.scss b/client/src/app/ui/modules/editor/components/editor/editor.component.scss index e69de29bb2..7b30fbdc98 100644 --- a/client/src/app/ui/modules/editor/components/editor/editor.component.scss +++ b/client/src/app/ui/modules/editor/components/editor/editor.component.scss @@ -0,0 +1,94 @@ +.editor { + .editor-menu { + display: flex; + flex-wrap: wrap; + > button, + > .button-group > button { + cursor: pointer; + background: none; + border: 1px solid rgba(0, 0, 0, 0.42); + display: inline-flex; + height: 34px; + align-items: center; + margin-right: 4px; + margin-bottom: 4px; + border-radius: 4px; + color: var(--mdc-text-button-label-text-color, inherit); + &.text { + padding: 0 10px; + } + &.more { + padding: 0; + } + &.color-selection { + position: relative; + } + &:disabled { + cursor: default; + } + &:disabled, + &.active { + background: rgba(0, 0, 0, 0.32); + } + input[type='color'] { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0; + cursor: pointer; + } + } + > .button-group { + display: flex; + border: 1px solid rgba(0, 0, 0, 0.42); + border-radius: 4px; + margin-right: 4px; + margin-bottom: 4px; + > button { + border: none; + border-radius: 0; + margin-right: 0; + margin-bottom: 0; + height: 32px; + &:not(:last-of-type) { + border-right: 1px solid rgba(0, 0, 0, 0.42); + } + } + } + } + + .editor-content { + border-bottom: solid 1px; + border-bottom-color: var(--mdc-filled-text-field-active-indicator-color); + border-top-left-radius: 4px; + border-top-right-radius: 4px; + background-color: var(--mdc-filled-text-field-container-color); + color: var(--mat-toolbar-container-text-color); + caret-color: var(--mdc-filled-text-field-caret-color); + padding: 0 16px 1px; + margin-top: 8px; + min-height: 100px; + height: 232px; + overflow-y: auto; + resize: vertical; + ::ng-deep .tiptap { + outline: none; + min-height: calc(100% - 32px); + table { + border-collapse: collapse; + &, + th, + td { + border: 1px dashed #bbb; + } + } + } + &:focus-within { + border-bottom-color: var(--mdc-filled-text-field-focus-active-indicator-color); + border-bottom-width: 2px; + padding-bottom: 0; + } + } +} diff --git a/client/src/app/ui/modules/editor/components/editor/editor.component.ts b/client/src/app/ui/modules/editor/components/editor/editor.component.ts index 3058f4399e..441c7b3917 100644 --- a/client/src/app/ui/modules/editor/components/editor/editor.component.ts +++ b/client/src/app/ui/modules/editor/components/editor/editor.component.ts @@ -1,9 +1,92 @@ -import { AfterViewInit, Component, forwardRef, Input } from '@angular/core'; +import { + AfterViewInit, + ChangeDetectorRef, + Component, + ElementRef, + EventEmitter, + forwardRef, + inject, + Input, + OnDestroy, + Output, + ViewChild +} from '@angular/core'; import { NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms'; +import { MatDialog } from '@angular/material/dialog'; import { TranslateService } from '@ngx-translate/core'; -import { Deferred } from 'src/app/infrastructure/utils/promises'; +import { Editor, Extension } from '@tiptap/core'; +import Blockquote from '@tiptap/extension-blockquote'; +import Bold from '@tiptap/extension-bold'; +import BulletList from '@tiptap/extension-bullet-list'; +import Color from '@tiptap/extension-color'; +import Document from '@tiptap/extension-document'; +import HardBreak from '@tiptap/extension-hard-break'; +import Heading from '@tiptap/extension-heading'; +import { Level as HeadingLevel } from '@tiptap/extension-heading'; +import History from '@tiptap/extension-history'; +import Image from '@tiptap/extension-image'; +import Italic from '@tiptap/extension-italic'; +import Link from '@tiptap/extension-link'; +import ListItem from '@tiptap/extension-list-item'; +import Paragraph from '@tiptap/extension-paragraph'; +import Strike from '@tiptap/extension-strike'; +import Subscript from '@tiptap/extension-subscript'; +import Superscript from '@tiptap/extension-superscript'; +import Table from '@tiptap/extension-table'; +import TableCell from '@tiptap/extension-table-cell'; +import TableHeader from '@tiptap/extension-table-header'; +import TableRow from '@tiptap/extension-table-row'; +import Text from '@tiptap/extension-text'; +import TextAlign from '@tiptap/extension-text-align'; +import TextStyle from '@tiptap/extension-text-style'; +import Underline from '@tiptap/extension-underline'; import { BaseFormControlComponent } from 'src/app/ui/base/base-form-control'; -import { RawEditorSettings } from 'tinymce'; +import tinycolor from 'tinycolor2'; + +import { + EditorEmbedDialogComponent, + EditorEmbedDialogOutput +} from '../editor-embed-dialog/editor-embed-dialog.component'; +import { EditorHtmlDialogComponent, EditorHtmlDialogOutput } from '../editor-html-dialog/editor-html-dialog.component'; +import { + EditorImageDialogComponent, + EditorImageDialogOutput +} from '../editor-image-dialog/editor-image-dialog.component'; +import { EditorLinkDialogComponent, EditorLinkDialogOutput } from '../editor-link-dialog/editor-link-dialog.component'; +import { ClearTextcolorPaste } from './extensions/clear-textcolor'; +import { Highlight } from './extensions/highlight'; +import IFrame from './extensions/iframe'; +import { ImageResize } from './extensions/image-resize'; +import { MSOfficePaste } from './extensions/office'; +import { OrderedList } from './extensions/ordered-list'; + +const DEFAULT_COLOR_PALETE = [ + `#BFEDD2`, + `#FBEEB8`, + `#F8CAC6`, + `#ECCAFA`, + `#C2E0F4`, + `#2DC26B`, + `#F1C40F`, + `#E03E2D`, + `#B96AD9`, + `#3598DB`, + `#169179`, + `#E67E23`, + `#BA372A`, + `#843FA1`, + `#236FA1`, + `#ECF0F1`, + `#CED4D9`, + `#95A5A6`, + `#7E8C8D`, + `#34495E`, + `#000000`, + `#FFFFFF`, + `#A918BF`, + `#CE4040`, + `#44C8AC` +]; @Component({ selector: `os-editor`, @@ -11,74 +94,323 @@ import { RawEditorSettings } from 'tinymce'; styleUrls: [`./editor.component.scss`], providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => EditorComponent), multi: true }] }) -export class EditorComponent extends BaseFormControlComponent implements AfterViewInit { +export class EditorComponent extends BaseFormControlComponent implements AfterViewInit, OnDestroy { + @ViewChild(`editorEl`) private editorEl: ElementRef; + @Input() public customSettings: object = {}; - public readonly hasInitialized = new Deferred(); + @Input() + public allowEmbeds = false; + + @Output() + public leaveFocus = new EventEmitter(); public override contentForm!: UntypedFormControl; - /** - * Settings for the TinyMCE editor selector - */ - public tinyMceSettings: RawEditorSettings = { - base_url: `/tinymce`, // Root for resources - suffix: `.min`, // Suffix to use when loading resources - theme: `silver`, - language: ``, - language_url: ``, - inline: false, - statusbar: false, - browser_spellcheck: true, - image_advtab: true, - image_description: false, - relative_urls: false, - link_title: false, - height: 320, - plugins: `autolink charmap code fullscreen image imagetools - lists link paste searchreplace`, - menubar: false, - contextmenu: false, - setup: editor => { - editor.on(`FullscreenStateChanged`, event => { - this.onFullscreenChanged(event); - }); - }, - toolbar: `styleselect | bold italic underline strikethrough | - forecolor backcolor removeformat | bullist numlist | - link image charmap | code fullscreen`, - mobile: { - theme: `mobile`, - plugins: [`autosave`, `lists`, `autolink`] - }, - paste_preprocess: this.onPastePreprocess - }; - - public constructor(translate: TranslateService) { + public editor: Editor; + + public editorReady = false; + + public headingLevels: HeadingLevel[] = [1, 2, 3, 4, 5, 6]; + + public textColorSet = new Set(DEFAULT_COLOR_PALETE); + public backgroundColorSet = new Set(DEFAULT_COLOR_PALETE); + + public get selectedHeadingLevel(): HeadingLevel { + if (this.editor.isActive(`heading`)) { + return this.editor.getAttributes(`heading`)[`level`]; + } + + return 1; + } + + public get isGodButtonActive(): boolean { + return ( + this.editor.isActive(`subscript`) || + this.editor.isActive(`superscript`) || + this.editor.isActive(`heading`) || + this.editor.isActive(`blockquote`) + ); + } + + public get godButtonText(): string { + if (this.editor.isActive(`subscript`)) { + return this.translate.instant(`Subscript`); + } else if (this.editor.isActive(`superscript`)) { + return this.translate.instant(`Superscript`); + } else if (this.editor.isActive(`heading`)) { + return this.translate.instant(`Heading`) + ` ${this.selectedHeadingLevel}`; + } else if (this.editor.isActive(`blockquote`)) { + return this.translate.instant(`Blockquote`); + } + + return this.translate.instant(`Paragraph`); + } + + private cd: ChangeDetectorRef = inject(ChangeDetectorRef); + + public constructor( + private dialog: MatDialog, + private translate: TranslateService + ) { super(); - this.tinyMceSettings.language_url = `/assets/tinymce/langs/` + translate.currentLang + `.js`; - this.tinyMceSettings.language = translate.currentLang; } public ngAfterViewInit(): void { - this.hasInitialized.resolve(true); - } + const editorConfig = { + element: this.editorEl.nativeElement, + extensions: [ + MSOfficePaste, + ClearTextcolorPaste, + // Nodes + Document, + Blockquote, + BulletList, + HardBreak, + Heading, + Image.configure({ + inline: true + }), + ImageResize.configure({ + inline: true + }), + ListItem, + OrderedList, + Paragraph, + Text, + Table, + TableRow, + TableHeader, + TableCell, - public getEditorSettings(): object { - return { - ...this.tinyMceSettings, - ...this.customSettings + //Marks + Bold, + Highlight.configure({ + multicolor: true + }), + Italic, + Link.extend({ + inclusive: false + }), + Strike, + Subscript, + Superscript, + TextStyle, + Underline, + + // Extensions + Color, + History, + TextAlign.configure({ + types: [`heading`, `paragraph`] + }), + Extension.create({ + onCreate: () => { + this.editorReady = true; + this.cd.detectChanges(); + }, + onDestroy: () => { + this.editorReady = false; + this.leaveFocus.emit(); + }, + onBlur: () => { + this.leaveFocus.emit(); + }, + onSelectionUpdate: () => { + this.cd.detectChanges(); + }, + onUpdate: () => { + const content = this.editor.getHTML(); + if (this.value != content) { + this.updateForm(content); + } + } + }) + ], + content: this.value }; + + if (this.allowEmbeds) { + editorConfig.extensions.push(IFrame); + } + + this.editor = new Editor(editorConfig); + this.updateColorSets(); } - public onFullscreenChanged(event: any): void { - const element = document.querySelector(`mat-sidenav`) as HTMLElement; - if (event[`state`]) { - element.style.zIndex = `0`; - } else { - element.style.zIndex = null; + public override ngOnDestroy(): void { + super.ngOnDestroy(); + this.editor.destroy(); + } + + public updateColorSets(): void { + // Safari and Firefox have their own color paletes so no presets necessary + if (navigator.userAgent.search(`Firefox`) > -1 || /^((?!chrome|android).)*safari/i.test(navigator.userAgent)) { + this.textColorSet.clear(); + this.backgroundColorSet.clear(); } + + // Add colors used in text to color palete + if (this.value) { + const parser = new DOMParser(); + const doc = parser.parseFromString(this.value, `text/html`); + const elements = doc.getElementsByTagName(`*`); + for (let i = 0; i < elements.length; i++) { + const el = elements[i]; + if (el.style.color) { + this.textColorSet.add(tinycolor(el.style.color).toHexString()); + } + + if (el.style.backgroundColor) { + this.backgroundColorSet.add(tinycolor(el.style.backgroundColor).toHexString()); + } + } + } + } + + public godButtonAction(): void { + if (this.editor.isActive(`subscript`)) { + this.editor.chain().focus().toggleSubscript().run(); + } else if (this.editor.isActive(`superscript`)) { + this.editor.chain().focus().toggleSuperscript().run(); + } else if (this.editor.isActive(`heading`)) { + this.editor.chain().focus().toggleHeading({ level: this.selectedHeadingLevel }).run(); + } else if (this.editor.isActive(`blockquote`)) { + this.editor.chain().focus().toggleBlockquote().run(); + } + } + + public updateFontColor(e: Event): void { + const val = (e.target)?.value; + if (val) { + this.editor.chain().focus().setColor(val).run(); + } + } + + public updateHighlightColor(e: Event): void { + const val = (e.target)?.value; + if (val) { + this.editor.chain().focus().setHighlight({ color: val }).run(); + } + } + + public clearSelectedFormat(): void { + this.editor + .chain() + .focus() + .unsetBold() + .unsetStrike() + .unsetItalic() + .unsetUnderline() + .unsetColor() + .unsetHighlight() + .removeEmptyTextStyle() + .run(); + } + + public async setLinkDialog(): Promise { + this.dialog + .open(EditorLinkDialogComponent, { + width: `400px`, + data: { + link: this.editor.getAttributes(`link`), + needsText: this.editor.state.selection.empty && !this.editor.isActive(`link`) + } + }) + .afterClosed() + .subscribe((result: EditorLinkDialogOutput) => { + if (!result) { + return; + } + + const chain = this.editor.chain().focus().extendMarkRange(`link`); + if (result.action === `remove-link`) { + chain.unsetLink().run(); + } else if (result.action === `set-link`) { + if (result.link) { + if (result.text) { + chain + .insertContent({ + type: `text`, + text: result.text, + marks: [ + { + type: `link`, + attrs: result.link + } + ] + }) + .run(); + } else { + chain.setLink(result.link).run(); + } + } + + this.editor.chain().focus(this.editor.state.selection.to).unsetMark(`link`).run(); + } + }); + } + + public async setImageDialog(): Promise { + this.dialog + .open(EditorImageDialogComponent, { + width: `400px`, + data: { + image: { + src: this.editor.getAttributes(`image`)[`src`], + alt: this.editor.getAttributes(`image`)[`alt`], + title: this.editor.getAttributes(`image`)[`title`] + } + } + }) + .afterClosed() + .subscribe((result?: EditorImageDialogOutput) => { + if (result?.action === `set-image`) { + this.editor.commands.setImage( + Object.assign({}, this.editor.getAttributes(`image`), { + src: result.image.src, + title: result.image.title, + alt: result.image.alt + }) + ); + } + }); + } + + public async setEmbedDialog(): Promise { + this.dialog + .open(EditorEmbedDialogComponent, { + width: `400px`, + data: { + embed: { + src: this.editor.getAttributes(`iframe`)[`src`], + title: this.editor.getAttributes(`iframe`)[`title`] + } + } + }) + .afterClosed() + .subscribe((result?: EditorEmbedDialogOutput) => { + if (result?.action === `set-embed`) { + this.editor.commands.setIframe({ + src: result.embed.src, + title: result.embed.title + }); + } + }); + } + + public editCode(): void { + this.dialog + .open(EditorHtmlDialogComponent, { + data: this.editor.getHTML() + }) + .afterClosed() + .subscribe((result: EditorHtmlDialogOutput) => { + if (result.action === `set`) { + this.editor.commands.setContent(result.html, true); + } + }); } protected createForm(): UntypedFormControl { @@ -86,29 +418,20 @@ export class EditorComponent extends BaseFormControlComponent implements } protected updateForm(value: string | null): void { - this.contentForm.setValue(value); - } - - /** - * Clean pasted HTML. - * If the user decides to copy-paste HTML (like from another OpenSlides motion detail) - * - remove all classes - * - remove data-line-number="X" - * - remove contenteditable="false" - * - * Not doing so would save control sequences from diff/linenumbering into the - * model which will open pandoras pox during PDF generation (and potentially web view) - * @param _ - * @param args - */ - private onPastePreprocess(_: any, args: any): void { - const getClassesRe = new RegExp(/\s*class\=\"[\w\W]*?\"/, `gi`); - const getDataLineNumberRe = new RegExp(/\s*data-line-number\=\"\d+\"/, `gi`); - const getContentEditableRe = new RegExp(/\s*contenteditable\=\"\w+\"/, `gi`); - const cleanedContent = (args.content as string) - .replace(getClassesRe, ``) - .replace(getDataLineNumberRe, ``) - .replace(getContentEditableRe, ``); - args.content = cleanedContent; + const html = value?.replace(/(]*>)(.*?)(<\/ul>)||(]*>)(.*?)(<\/li>)/g, res => { + if (res) { + return res.replace(/(]*>)(.*?)(<\/li[^>]*>)/g, response => { + if (response.match(/<\/?p[^>]*>/g)?.length == 2) { + return response.replace(/<\/?p[^>]*>/g, ``); + } else if (response) { + return response; + } + return ``; + }); + } + return ``; + }); + + this.contentForm.setValue(html); } } diff --git a/client/src/app/ui/modules/editor/components/editor/extensions/clear-textcolor.ts b/client/src/app/ui/modules/editor/components/editor/extensions/clear-textcolor.ts new file mode 100644 index 0000000000..d3232f0602 --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor/extensions/clear-textcolor.ts @@ -0,0 +1,27 @@ +import { Extension } from '@tiptap/core'; +import { Plugin } from '@tiptap/pm/state'; +import tinycolor from 'tinycolor2'; + +export const ClearTextcolorPaste = Extension.create({ + addProseMirrorPlugins() { + return [ClearTextcolorPastePlugin]; + } +}); + +const ClearTextcolorPastePlugin = new Plugin({ + props: { + transformPastedHTML(html: string): string { + const parser = new DOMParser(); + const doc = parser.parseFromString(html, `text/html`); + const elements = doc.getElementsByTagName(`*`); + for (let i = 0; i < elements.length; i++) { + const el = elements.item(i); + if (el.style && el.style.color && tinycolor(el.style.color).toHex() === `000000`) { + el.style.color = ``; + } + } + + return doc.documentElement.outerHTML; + } + } +}); diff --git a/client/src/app/ui/modules/editor/components/editor/extensions/highlight.ts b/client/src/app/ui/modules/editor/components/editor/extensions/highlight.ts new file mode 100644 index 0000000000..6aee957c8d --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor/extensions/highlight.ts @@ -0,0 +1,13 @@ +import OriginalHighlight from '@tiptap/extension-highlight'; + +export const Highlight = OriginalHighlight.extend({ + parseHTML() { + return [ + ...this.parent(), + { + tag: `span`, + getAttrs: (node): false | Attr => !!(node as HTMLElement).style?.backgroundColor && null + } + ]; + } +}); diff --git a/client/src/app/ui/modules/editor/components/editor/extensions/iframe.ts b/client/src/app/ui/modules/editor/components/editor/extensions/iframe.ts new file mode 100644 index 0000000000..e46476c4a4 --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor/extensions/iframe.ts @@ -0,0 +1,96 @@ +import { mergeAttributes, Node } from '@tiptap/core'; + +export interface IframeOptions { + inline: boolean; + HTMLAttributes: { + [key: string]: any; + }; +} + +declare module '@tiptap/core' { + interface Commands { + iframe: { + /** + * Add an iframe + */ + setIframe: (options: { src: string; title?: string }) => ReturnType; + }; + } +} + +export default Node.create({ + name: `iframe`, + + group() { + return this.options.inline ? `inline` : `block`; + }, + + inline() { + return this.options.inline; + }, + + draggable: true, + + addOptions() { + return { + inline: true, + HTMLAttributes: {} + }; + }, + + addAttributes() { + return { + src: { + default: null + }, + title: { + default: null + }, + frameborder: { + default: 0 + }, + width: { + default: null + }, + height: { + default: null + }, + sandbox: { + default: `allow-scripts allow-same-origin` + } + }; + }, + + parseHTML() { + return [ + { + tag: `iframe` + } + ]; + }, + + renderHTML({ HTMLAttributes }) { + if (!this.options.inline) { + return [`div`, this.options.HTMLAttributes, [`iframe`, HTMLAttributes]]; + } + + return [`iframe`, mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)]; + }, + + addCommands() { + return { + setIframe: + (options: { src: string; title?: string }) => + ({ tr, dispatch }): boolean => { + const { selection } = tr; + const node = this.type.create(options); + + if (dispatch) { + tr.replaceRangeWith(selection.from, selection.to, node); + } + + return true; + } + }; + } +}); diff --git a/client/src/app/ui/modules/editor/components/editor/extensions/image-resize.ts b/client/src/app/ui/modules/editor/components/editor/extensions/image-resize.ts new file mode 100644 index 0000000000..0c1eeb361c --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor/extensions/image-resize.ts @@ -0,0 +1,117 @@ +import Image from '@tiptap/extension-image'; +import { Node } from '@tiptap/pm/model'; + +function createImageFromNode(node: Node): HTMLElement { + const img = document.createElement(`img`); + img.src = node.attrs[`src`]; + img.alt = node.attrs[`alt`]; + img.title = node.attrs[`title`]; + if (node.attrs[`width`]) { + img.style.width = node.attrs[`width`] + `px`; + } + + return img; +} + +const lastDotPos = [true, false, false, true]; +function getNextDot(): HTMLElement { + const dot = document.createElement(`div`); + lastDotPos.push(lastDotPos.shift()); + const cursor = (lastDotPos[0] && lastDotPos[1]) || (lastDotPos[2] && lastDotPos[3]) ? `nwse` : `nesw`; + dot.setAttribute( + `style`, + `position: absolute; width: 9px; height: 9px; border: 1.5px solid #6C6C6C; border-radius: 50%; + cursor: ${cursor}-resize; + top: ${lastDotPos[0] ? `-4px` : `auto`}; + left: ${lastDotPos[1] ? `-4px` : `auto`}; + bottom: ${lastDotPos[2] ? `-4px` : `auto`}; + right: ${lastDotPos[3] ? `-4px` : `auto`};` + ); + + return dot; +} + +export const ImageResize = Image.extend({ + addAttributes() { + return { + ...this.parent?.(), + width: { + default: null + }, + height: { + default: null + } + }; + }, + addNodeView() { + return ({ node, editor, getPos }): { dom: HTMLElement } => { + const container = document.createElement(`div`); + container.style.position = `relative`; + container.style.display = `inline-flex`; + + const img = createImageFromNode(node); + if (!editor.options.editable) return { dom: img }; + + let isResizing = false; + let startX: number, startWidth: number; + + container.addEventListener(`click`, _ => { + for (let i = 0; i < 4; i++) { + const dot = getNextDot(); + + dot.addEventListener(`mousedown`, e => { + e.preventDefault(); + isResizing = true; + startX = e.clientX; + startWidth = container.offsetWidth; + + const onMouseMove = (e: MouseEvent): void => { + if (!isResizing) return; + const deltaX = i === 1 || i === 2 ? -(e.clientX - startX) : e.clientX - startX; + const newWidth = startWidth + deltaX; + container.style.width = newWidth + `px`; + img.style.width = newWidth + `px`; + }; + + const onMouseUp = (): void => { + if (isResizing) { + isResizing = false; + } + + if (typeof getPos === `function`) { + const newAttrs = { + ...node.attrs, + width: `${img.style.width}`.substring(0, img.style.width.length - 2) + }; + editor.view.dispatch(editor.view.state.tr.setNodeMarkup(getPos(), null, newAttrs)); + } + + document.removeEventListener(`mousemove`, onMouseMove); + document.removeEventListener(`mouseup`, onMouseUp); + }; + + document.addEventListener(`mousemove`, onMouseMove); + document.addEventListener(`mouseup`, onMouseUp); + }); + + container.appendChild(dot); + } + }); + + document.addEventListener(`click`, (e: MouseEvent) => { + if (!container.contains(e.target as HTMLElement)) { + const dots = container.querySelectorAll(`div`); + for (let i = 0; i < dots.length; i++) { + container.removeChild(dots.item(i)); + } + } + }); + + container.append(img); + + return { + dom: container + }; + }; + } +}); diff --git a/client/src/app/ui/modules/editor/components/editor/extensions/office.ts b/client/src/app/ui/modules/editor/components/editor/extensions/office.ts new file mode 100644 index 0000000000..084d637bbd --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor/extensions/office.ts @@ -0,0 +1,203 @@ +import { Extension } from '@tiptap/core'; +import { Plugin } from '@tiptap/pm/state'; +import { parseLetterNumber, parseRomanNumber } from 'src/app/infrastructure/utils'; +import { unwrapNode } from 'src/app/infrastructure/utils/dom-helpers'; + +export const MSOfficePaste = Extension.create({ + priority: 99999, + + addProseMirrorPlugins() { + return [OfficePastePlugin]; + } +}); + +const OfficePastePlugin = new Plugin({ + props: { + transformPastedHTML(html: string): string { + console.log([html]); + if (html.indexOf(`microsoft-com`) !== -1 && html.indexOf(`office`) !== -1) { + html = transformLists(html); + html = transformRemoveBookmarks(html); + html = transformMsoStyles(html); + } + console.log([html]); + return html; + } + } +}); + +function transformMsoStyles(html: string): string { + html = html.replace(/(.*)<\/o:p>/g, ``); + + const parser = new DOMParser(); + const doc = parser.parseFromString(html, `text/html`); + doc.querySelectorAll(`[style*="mso-"]`).forEach(node => { + const styles = parseStyleAttribute(node); + const newStyles = []; + for (const prop of Object.keys(styles)) { + if (prop && !prop.startsWith(`mso-`)) { + newStyles.push(`${prop}: ${styles[prop]}`); + } + } + node.setAttribute(`style`, newStyles.join(`;`)); + }); + + doc.querySelectorAll(`[style*="color: black"]`).forEach(node => { + (node as HTMLElement).style.removeProperty(`color`); + }); + + return doc.documentElement.outerHTML; +} + +function transformRemoveBookmarks(html: string): string { + const parser = new DOMParser(); + const doc = parser.parseFromString(html, `text/html`); + const bookmarks = doc.querySelectorAll(`[style*="mso-bookmark:"]`); + bookmarks.forEach(node => { + const bookmark = parseStyleAttribute(node)[`mso-bookmark`]; + const bookmarkLink = doc.querySelector(`a[name="${bookmark}"]`); + if (bookmarkLink) { + bookmarkLink.parentNode.removeChild(bookmarkLink); + } + unwrapNode(node as HTMLElement); + }); + + return doc.documentElement.outerHTML; +} + +function transformLists(html: string): string { + if (html.indexOf(`mso-list:`) === -1) { + return html; + } + + const parser = new DOMParser(); + const doc = parser.parseFromString(html, `text/html`); + + let listStack: HTMLElement[] = []; + let currentListId: string; + const listElements = doc.querySelectorAll(`p[style*="mso-list:"]`); + listElements.forEach(node => { + const el = node; + const [msoListId, msoListLevel] = parseMsoListAttribute(parseStyleAttribute(el)[`mso-list`]); + + // Check for start of a new list + if (currentListId !== msoListId && (hasNonListItemSibling(el) || msoListLevel === 1)) { + currentListId = msoListId; + listStack = []; + } + + while (msoListLevel > listStack.length) { + const newList = createListElement(el); + + if (listStack.length > 0) { + listStack[listStack.length - 1].appendChild(newList); + } else { + el.before(newList); + } + listStack.push(newList); + } + + while (msoListLevel < listStack.length) { + listStack.pop(); + } + + // Remove list item numbers and create li + listStack[listStack.length - 1].appendChild(getListItemFromParagraph(el)); + el.remove(); + }); + + return doc.documentElement.outerHTML; +} + +function hasNonListItemSibling(el: HTMLElement): boolean { + return ( + !el.previousElementSibling || + !(el.previousElementSibling.nodeName === `OL` || el.previousElementSibling.nodeName === `UL`) + ); +} + +function getListItemFromParagraph(el: HTMLElement): HTMLElement { + const li = document.createElement(`li`); + li.innerHTML = el.innerHTML.replace(listTypeRegex, ``); + + return li; +} + +// Parses `mso-list` style attribute +function parseMsoListAttribute(attr: string): [id: string, level: number] { + const msoListValue: string = attr; + const msoListInfos = msoListValue.split(` `); + const msoListId = msoListInfos.find(e => /l[0-9]+/.test(e)); + const msoListLevel = +msoListInfos.find((e: string) => e.startsWith(`level`))?.substring(5) || 1; + + return [msoListId, msoListLevel]; +} + +const listTypeRegex = /((.|\n)*)/m; +function getListPrefix(el: HTMLElement): string { + const matches = el.innerHTML.match(listTypeRegex); + if (matches?.length) { + const parser = new DOMParser(); + const doc = parser.parseFromString(matches[0], `text/html`); + return doc.body.querySelector(`span`).textContent; + } + + return ``; +} + +function parseStyleAttribute(el: Element): { [prop: string]: string } { + const styleRaw: string = el?.attributes[`style`]?.value || ``; + return Object.fromEntries(styleRaw.split(`;`).map(line => line.split(`:`).map(v => v.trim()))); +} + +function createListElement(el: HTMLElement): HTMLElement { + const listInfo = getListInfo(getListPrefix(el)); + const list = document.createElement(listInfo.type); + if (listInfo.countType) { + list.setAttribute(`type`, listInfo.countType); + } + if (listInfo.start > 1) { + list.setAttribute(`start`, listInfo.start.toString()); + } + return list; +} + +const listOrderRegex = { + number: /[0-9]+\./, + romanLower: /(?=[mdclxvi])m*(c[md]|d?c*)(x[cl]|l?x*)(i[xv]|v?i*)\./, + romanUpper: /(?=[MDCLXVI])M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)\./, + letterLower: /[a-z]+\./, + letterUpper: /[A-Z]+\./ +}; + +function getListInfo(prefix: string): { type: string; start: number; countType: string } { + let type = `ul`; + let countType: string | null = null; + let start = 1; + if (listOrderRegex.number.test(prefix)) { + type = `ol`; + start = +prefix.match(listOrderRegex.number)[0].replace(`.`, ``); + } else if (listOrderRegex.romanLower.test(prefix)) { + type = `ol`; + countType = `i`; + start = +parseRomanNumber(prefix.match(listOrderRegex.romanLower)[0].replace(`.`, ``)); + } else if (listOrderRegex.romanUpper.test(prefix)) { + type = `ol`; + countType = `I`; + start = +parseRomanNumber(prefix.match(listOrderRegex.romanUpper)[0].replace(`.`, ``)); + } else if (listOrderRegex.letterLower.test(prefix)) { + type = `ol`; + countType = `a`; + start = +parseLetterNumber(prefix.match(listOrderRegex.letterLower)[0].replace(`.`, ``)); + } else if (listOrderRegex.letterUpper.test(prefix)) { + type = `ol`; + countType = `A`; + start = +parseLetterNumber(prefix.match(listOrderRegex.letterUpper)[0].replace(`.`, ``)); + } + + return { + type, + start, + countType + }; +} diff --git a/client/src/app/ui/modules/editor/components/editor/extensions/ordered-list.ts b/client/src/app/ui/modules/editor/components/editor/extensions/ordered-list.ts new file mode 100644 index 0000000000..eb63f500a2 --- /dev/null +++ b/client/src/app/ui/modules/editor/components/editor/extensions/ordered-list.ts @@ -0,0 +1,15 @@ +import OriginalOrderedList from '@tiptap/extension-ordered-list'; + +export const OrderedList = OriginalOrderedList.extend({ + addAttributes() { + return { + ...this.parent(), + type: { + default: null, + parseHTML: (element): string => { + return element.getAttribute(`type`); + } + } + }; + } +}); diff --git a/client/src/app/ui/modules/editor/editor.module.ts b/client/src/app/ui/modules/editor/editor.module.ts index 4bb01bf927..0f59fcaf4d 100644 --- a/client/src/app/ui/modules/editor/editor.module.ts +++ b/client/src/app/ui/modules/editor/editor.module.ts @@ -1,21 +1,46 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { ReactiveFormsModule } from '@angular/forms'; -import { EditorModule as TinyMce, TINYMCE_SCRIPT_SRC } from '@tinymce/tinymce-angular'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatRippleModule } from '@angular/material/core'; +import { MatDialogModule } from '@angular/material/dialog'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { OpenSlidesTranslationModule } from 'src/app/site/modules/translations'; import { EditorComponent } from './components/editor/editor.component'; +import { EditorEmbedDialogComponent } from './components/editor-embed-dialog/editor-embed-dialog.component'; +import { EditorHtmlDialogComponent } from './components/editor-html-dialog/editor-html-dialog.component'; +import { EditorImageDialogComponent } from './components/editor-image-dialog/editor-image-dialog.component'; +import { EditorLinkDialogComponent } from './components/editor-link-dialog/editor-link-dialog.component'; -const DECLARATIONS = [EditorComponent]; +const DECLARATIONS = [ + EditorComponent, + EditorImageDialogComponent, + EditorEmbedDialogComponent, + EditorLinkDialogComponent, + EditorHtmlDialogComponent +]; @NgModule({ declarations: DECLARATIONS, - imports: [CommonModule, TinyMce, ReactiveFormsModule], - exports: DECLARATIONS, - providers: [ - { - provide: TINYMCE_SCRIPT_SRC, - useValue: `tinymce/tinymce.min.js` - } - ] + imports: [ + CommonModule, + ReactiveFormsModule, + MatIconModule, + MatRippleModule, + MatFormFieldModule, + MatDialogModule, + MatInputModule, + MatButtonModule, + MatMenuModule, + MatTooltipModule, + FormsModule, + OpenSlidesTranslationModule.forChild() + ], + exports: DECLARATIONS }) export class EditorModule {} diff --git a/client/src/assets/styles/tiptap.scss b/client/src/assets/styles/tiptap.scss new file mode 100644 index 0000000000..c8d57aa250 --- /dev/null +++ b/client/src/assets/styles/tiptap.scss @@ -0,0 +1,10 @@ +.tiptap, +.tiptap-view, +.motion-text { + & li > p:first-of-type { + margin-top: 0; + } + & li > p:last-of-type { + margin-bottom: 0; + } +} diff --git a/client/src/assets/tinymce/langs/cs.js b/client/src/assets/tinymce/langs/cs.js deleted file mode 100644 index 264b32fcd0..0000000000 --- a/client/src/assets/tinymce/langs/cs.js +++ /dev/null @@ -1,261 +0,0 @@ -tinymce.addI18n('cs',{ -"Redo": "Znovu", -"Undo": "Zp\u011bt", -"Cut": "Vyjmout", -"Copy": "Kop\u00edrovat", -"Paste": "Vlo\u017eit", -"Select all": "Vybrat v\u0161e", -"New document": "Nov\u00fd dokument", -"Ok": "OK", -"Cancel": "Zru\u0161it", -"Visual aids": "Vizu\u00e1ln\u00ed pom\u016fcky", -"Bold": "Tu\u010dn\u00e9", -"Italic": "Kurz\u00edva", -"Underline": "Podtr\u017een\u00e9", -"Strikethrough": "P\u0159e\u0161rktnut\u00e9", -"Superscript": "Horn\u00ed index", -"Subscript": "Doln\u00ed index", -"Clear formatting": "Vymazat form\u00e1tov\u00e1n\u00ed", -"Align left": "Zarovnat vlevo", -"Align center": "Zarovnat na st\u0159ed", -"Align right": "Zarovnat vpravo", -"Justify": "Zarovnat do bloku", -"Bullet list": "Odr\u00e1\u017eky", -"Numbered list": "\u010c\u00edslov\u00e1n\u00ed", -"Decrease indent": "Zmen\u0161it odsazen\u00ed", -"Increase indent": "Zv\u011bt\u0161it odsazen\u00ed", -"Close": "Zav\u0159\u00edt", -"Formats": "Form\u00e1ty", -"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "V\u00e1\u0161 prohl\u00ed\u017ee\u010d nepodporuje p\u0159\u00edm\u00fd p\u0159\u00edstup do schr\u00e1nky. Pou\u017eijte pros\u00edm kl\u00e1vesov\u00e9 zkratky Ctrl+X\/C\/V.", -"Headers": "Nadpisy", -"Header 1": "Nadpis 1", -"Header 2": "Nadpis 2", -"Header 3": "Nadpis 3", -"Header 4": "Nadpis 4", -"Header 5": "Nadpis 5", -"Header 6": "Nadpis 6", -"Headings": "Nadpisy", -"Heading 1": "Nadpis 1", -"Heading 2": "Nadpis 2", -"Heading 3": "Nadpis 3", -"Heading 4": "Nadpis 4", -"Heading 5": "Nadpis 5", -"Heading 6": "Nadpis 6", -"Preformatted": "P\u0159edform\u00e1tov\u00e1no", -"Div": "Div (blok)", -"Pre": "Pre (p\u0159edform\u00e1tov\u00e1no)", -"Code": "Code (k\u00f3d)", -"Paragraph": "Odstavec", -"Blockquote": "Citace", -"Inline": "\u0158\u00e1dkov\u00e9 zobrazen\u00ed (inline)", -"Blocks": "Blokov\u00e9 zobrazen\u00ed (block)", -"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Je zapnuto vkl\u00e1d\u00e1n\u00ed \u010dist\u00e9ho textu. Dokud nebude tato volba vypnuta, bude ve\u0161ker\u00fd obsah vlo\u017een jako \u010dist\u00fd text.", -"Font Family": "Typ p\u00edsma", -"Font Sizes": "Velikost p\u00edsma", -"Class": "T\u0159\u00edda", -"Browse for an image": "Vyhledat obr\u00e1zek", -"OR": "nebo", -"Drop an image here": "Nahr\u00e1t obr\u00e1zek", -"Upload": "Nahr\u00e1t", -"Block": "Blok", -"Align": "Zarovnat", -"Default": "V\u00fdchoz\u00ed", -"Circle": "Kole\u010dko", -"Disc": "Punt\u00edk", -"Square": "\u010ctvere\u010dek", -"Lower Alpha": "Norm\u00e1ln\u00ed \u010d\u00edslov\u00e1n\u00ed", -"Lower Greek": "Mal\u00e9 p\u00edsmenkov\u00e1n\u00ed", -"Lower Roman": "Mal\u00e9 \u0159\u00edmsk\u00e9 \u010d\u00edslice", -"Upper Alpha": "velk\u00e9 p\u00edsmenkov\u00e1n\u00ed", -"Upper Roman": "\u0158\u00edmsk\u00e9 \u010d\u00edslice", -"Anchor": "Kotva", -"Name": "N\u00e1zev", -"Id": "Id", -"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "Id by m\u011blo za\u010d\u00ednat p\u00edsmenem a d\u00e1le obsahovat pouze p\u00edsmena, \u010d\u00edsla, poml\u010dky, te\u010dky, dvojte\u010dky, nebo podtr\u017e\u00edtka.", -"You have unsaved changes are you sure you want to navigate away?": "M\u00e1te neulo\u017een\u00e9 zm\u011bny. Opravdu chcete opustit str\u00e1nku?", -"Restore last draft": "Obnovit posledn\u00ed koncept", -"Special character": "Speci\u00e1ln\u00ed znak", -"Source code": "Zdrojov\u00fd k\u00f3d", -"Insert\/Edit code sample": "Vlo\u017eit \/ Upravit uk\u00e1zkov\u00fd k\u00f3d", -"Language": "Jazyk", -"Code sample": "Uk\u00e1zkov\u00fd k\u00f3d", -"Color": "Barva", -"R": "R", -"G": "G", -"B": "B", -"Left to right": "Zleva doprava", -"Right to left": "Zprava doleva", -"Emoticons": "Emotikony", -"Document properties": "Vlastnosti dokumentu", -"Title": "Titulek", -"Keywords": "Kl\u00ed\u010dov\u00e1 slova", -"Description": "Popis", -"Robots": "Roboti", -"Author": "Autor", -"Encoding": "K\u00f3dov\u00e1n\u00ed", -"Fullscreen": "Na celou obrazovku", -"Action": "Akce", -"Shortcut": "Kl\u00e1vesov\u00e1 zkratka", -"Help": "N\u00e1pov\u011bda", -"Address": "Blok s po\u0161tovn\u00ed adresou", -"Focus to menubar": "P\u0159ej\u00edt do menu", -"Focus to toolbar": "P\u0159ej\u00edt na panel n\u00e1stroj\u016f", -"Focus to element path": "P\u0159ej\u00edt na element path", -"Focus to contextual toolbar": "P\u0159ej\u00edt na kontextov\u00fd panel n\u00e1stroj\u016f", -"Insert link (if link plugin activated)": "Vlo\u017eit odkaz (pokud je aktivn\u00ed link plugin)", -"Save (if save plugin activated)": "Ulo\u017eit (pokud je aktivni save plugin)", -"Find (if searchreplace plugin activated)": "Hledat (pokud je aktivn\u00ed plugin searchreplace)", -"Plugins installed ({0}):": "Instalovan\u00e9 pluginy ({0}):", -"Premium plugins:": "Pr\u00e9miov\u00e9 pluginy:", -"Learn more...": "Zjistit v\u00edce...", -"You are using {0}": "Pou\u017e\u00edv\u00e1te {0}", -"Plugins": "Pluginy", -"Handy Shortcuts": "U\u017eite\u010dn\u00e9 kl\u00e1vesov\u00e9 zkratky", -"Horizontal line": "Vodorovn\u00e1 \u010d\u00e1ra", -"Insert\/edit image": "Vlo\u017eit \/ upravit obr\u00e1zek", -"Image description": "Popis obr\u00e1zku", -"Source": "URL", -"Dimensions": "Rozm\u011bry", -"Constrain proportions": "Zachovat proporce", -"General": "Obecn\u00e9", -"Advanced": "Pokro\u010dil\u00e9", -"Style": "Styl", -"Vertical space": "Vertik\u00e1ln\u00ed mezera", -"Horizontal space": "Horizont\u00e1ln\u00ed mezera", -"Border": "R\u00e1me\u010dek", -"Insert image": "Vlo\u017eit obr\u00e1zek", -"Image": "Obr\u00e1zek", -"Image list": "Seznam obr\u00e1zk\u016f", -"Rotate counterclockwise": "Oto\u010dit doleva", -"Rotate clockwise": "Oto\u010dit doprava", -"Flip vertically": "P\u0159evr\u00e1tit svisle", -"Flip horizontally": "P\u0159evr\u00e1tit vodorovn\u011b", -"Edit image": "Upravit obr\u00e1zek", -"Image options": "Vlastnosti obr\u00e1zku", -"Zoom in": "P\u0159ibl\u00ed\u017eit", -"Zoom out": "Odd\u00e1lit", -"Crop": "O\u0159\u00edznout", -"Resize": "Zm\u011bnit velikost", -"Orientation": "Transformovat", -"Brightness": "Jas", -"Sharpen": "Ostrost", -"Contrast": "Kontrast", -"Color levels": "\u00darovn\u011b barev", -"Gamma": "Gama", -"Invert": "Invertovat", -"Apply": "Pou\u017e\u00edt", -"Back": "Zp\u011bt", -"Insert date\/time": "Vlo\u017eit datum \/ \u010das", -"Date\/time": "Datum\/\u010das", -"Insert link": "Vlo\u017eit odkaz", -"Insert\/edit link": "Vlo\u017eit \/ upravit odkaz", -"Text to display": "Text k zobrazen\u00ed", -"Url": "URL", -"Target": "C\u00edl", -"None": "\u017d\u00e1dn\u00e9", -"New window": "Nov\u00e9 okno", -"Remove link": "Odstranit odkaz", -"Anchors": "Kotvy", -"Link": "Odkaz", -"Paste or type a link": "Vlo\u017eit nebo napsat odkaz", -"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "Zadan\u00e9 URL vypad\u00e1 jako e-mailov\u00e1 adresa. Chcete doplnit povinn\u00fd prefix mailto:?", -"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "Zadan\u00e9 URL vypad\u00e1 jako odkaz na jin\u00fd web. Chcete doplnit povinn\u00fd prefix http:\/\/?", -"Link list": "Seznam odkaz\u016f", -"Insert video": "Vlo\u017eit video", -"Insert\/edit video": "Vlo\u017eit \/ upravit video", -"Insert\/edit media": "Vlo\u017eit \/ upravit m\u00e9dia", -"Alternative source": "Alternativn\u00ed zdroj", -"Poster": "N\u00e1hled", -"Paste your embed code below:": "Vlo\u017ete k\u00f3d pro vlo\u017een\u00ed n\u00ed\u017ee:", -"Embed": "Vlo\u017eit", -"Media": "M\u00e9dia", -"Nonbreaking space": "Pevn\u00e1 mezera", -"Page break": "Konec str\u00e1nky", -"Paste as text": "Vlo\u017eit jako \u010dist\u00fd text", -"Preview": "N\u00e1hled", -"Print": "Tisk", -"Save": "Ulo\u017eit", -"Find": "Naj\u00edt", -"Replace with": "Nahradit za", -"Replace": "Nahradit", -"Replace all": "Nahradit v\u0161e", -"Prev": "P\u0159edchoz\u00ed", -"Next": "Dal\u0161\u00ed", -"Find and replace": "Naj\u00edt a nahradit", -"Could not find the specified string.": "Zadan\u00fd \u0159et\u011bzec nebyl nalezen.", -"Match case": "Rozli\u0161ovat mal\u00e1 a velk\u00e1 p\u00edsmena", -"Whole words": "Pouze cel\u00e1 slova", -"Spellcheck": "Kontrola pravopisu", -"Ignore": "Ignorovat", -"Ignore all": "Ignorovat v\u0161e", -"Finish": "Ukon\u010dit", -"Add to Dictionary": "P\u0159idat do slovn\u00edku", -"Insert table": "Vlo\u017eit tabulku", -"Table properties": "Vlastnosti tabulky", -"Delete table": "Smazat tabulku", -"Cell": "Bu\u0148ka", -"Row": "\u0158\u00e1dek", -"Column": "Sloupec", -"Cell properties": "Vlastnosti bu\u0148ky", -"Merge cells": "Slou\u010dit bu\u0148ky", -"Split cell": "Rozd\u011blit bu\u0148ky", -"Insert row before": "Vlo\u017eit \u0159\u00e1dek nad", -"Insert row after": "Vlo\u017eit \u0159\u00e1dek pod", -"Delete row": "Smazat \u0159\u00e1dek", -"Row properties": "Vlastnosti \u0159\u00e1dku", -"Cut row": "Vyjmout \u0159\u00e1dek", -"Copy row": "Kop\u00edrovat \u0159\u00e1dek", -"Paste row before": "Vlo\u017eit \u0159\u00e1dek nad", -"Paste row after": "Vlo\u017eit \u0159\u00e1dek pod", -"Insert column before": "Vlo\u017eit sloupec vlevo", -"Insert column after": "Vlo\u017eit sloupec vpravo", -"Delete column": "Smazat sloupec", -"Cols": "Sloupc\u016f", -"Rows": "\u0158\u00e1dek", -"Width": "\u0160\u00ed\u0159ka", -"Height": "V\u00fd\u0161ka", -"Cell spacing": "Vn\u011bj\u0161\u00ed okraj bun\u011bk", -"Cell padding": "Vnit\u0159n\u00ed okraj bun\u011bk", -"Caption": "Nadpis", -"Left": "Vlevo", -"Center": "Na st\u0159ed", -"Right": "Vpravo", -"Cell type": "Typ bu\u0148ky", -"Scope": "Rozsah", -"Alignment": "Zarovn\u00e1n\u00ed", -"H Align": "Horizont\u00e1ln\u00ed zarovn\u00e1n\u00ed", -"V Align": "Vertik\u00e1ln\u00ed zarovn\u00e1n\u00ed", -"Top": "Nahoru", -"Middle": "Uprost\u0159ed", -"Bottom": "Dol\u016f", -"Header cell": "Hlavi\u010dkov\u00e1 bu\u0148ka", -"Row group": "Skupina \u0159\u00e1dk\u016f", -"Column group": "Skupina sloupc\u016f", -"Row type": "Typ \u0159\u00e1dku", -"Header": "Hlavi\u010dka", -"Body": "T\u011blo", -"Footer": "Pati\u010dka", -"Border color": "Barva r\u00e1me\u010dku", -"Insert template": "Vlo\u017eit \u0161ablonu", -"Templates": "\u0160ablony", -"Template": "\u0160ablona", -"Text color": "Barva p\u00edsma", -"Background color": "Barva pozad\u00ed", -"Custom...": "Vlastn\u00ed...", -"Custom color": "Vlastn\u00ed barva", -"No color": "Bez barvy", -"Table of Contents": "Obsah", -"Show blocks": "Uk\u00e1zat bloky", -"Show invisible characters": "Zobrazit speci\u00e1ln\u00ed znaky", -"Words: {0}": "Po\u010det slov: {0}", -"{0} words": "Po\u010det slov: {0}", -"File": "Soubor", -"Edit": "\u00dapravy", -"Insert": "Vlo\u017eit", -"View": "Zobrazit", -"Format": "Form\u00e1t", -"Table": "Tabulka", -"Tools": "N\u00e1stroje", -"Powered by {0}": "Vytvo\u0159il {0}", -"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Editor. Stiskn\u011bte ALT-F9 pro menu, ALT-F10 pro n\u00e1strojovou li\u0161tu a ALT-0 pro n\u00e1pov\u011bdu." -}); \ No newline at end of file diff --git a/client/src/assets/tinymce/langs/de.js b/client/src/assets/tinymce/langs/de.js deleted file mode 100644 index 32a45747bc..0000000000 --- a/client/src/assets/tinymce/langs/de.js +++ /dev/null @@ -1,261 +0,0 @@ -tinymce.addI18n('de',{ -"Redo": "Wiederholen", -"Undo": "R\u00fcckg\u00e4ngig", -"Cut": "Ausschneiden", -"Copy": "Kopieren", -"Paste": "Einf\u00fcgen", -"Select all": "Alles ausw\u00e4hlen", -"New document": "Neues Dokument", -"Ok": "Ok", -"Cancel": "Abbrechen", -"Visual aids": "Visuelle Hilfen", -"Bold": "Fett", -"Italic": "Kursiv", -"Underline": "Unterstrichen", -"Strikethrough": "Durchgestrichen", -"Superscript": "Hochgestellt", -"Subscript": "Tiefgestellt", -"Clear formatting": "Formatierung entfernen", -"Align left": "Linksb\u00fcndig ausrichten", -"Align center": "Zentriert ausrichten", -"Align right": "Rechtsb\u00fcndig ausrichten", -"Justify": "Blocksatz", -"Bullet list": "Aufz\u00e4hlung", -"Numbered list": "Nummerierte Liste", -"Decrease indent": "Einzug verkleinern", -"Increase indent": "Einzug vergr\u00f6\u00dfern", -"Close": "Schlie\u00dfen", -"Formats": "Formate", -"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Ihr Browser unterst\u00fctzt leider keinen direkten Zugriff auf die Zwischenablage. Bitte benutzen Sie die Strg + X \/ C \/ V Tastenkombinationen.", -"Headers": "\u00dcberschriften", -"Header 1": "\u00dcberschrift 1", -"Header 2": "\u00dcberschrift 2", -"Header 3": "\u00dcberschrift 3", -"Header 4": "\u00dcberschrift 4", -"Header 5": "\u00dcberschrift 5", -"Header 6": "\u00dcberschrift 6", -"Headings": "\u00dcberschriften", -"Heading 1": "\u00dcberschrift 1", -"Heading 2": "\u00dcberschrift 2", -"Heading 3": "\u00dcberschrift 3", -"Heading 4": "\u00dcberschrift 4", -"Heading 5": "\u00dcberschrift 5", -"Heading 6": "\u00dcberschrift 6", -"Preformatted": "Preformatted", -"Div": "Textblock", -"Pre": "Vorformatierter Text", -"Code": "Quelltext", -"Paragraph": "Absatz", -"Blockquote": "Zitat", -"Inline": "Zeichenformate", -"Blocks": "Absatzformate", -"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Einf\u00fcgen ist nun im einfachen Textmodus. Inhalte werden ab jetzt als unformatierter Text eingef\u00fcgt, bis Sie diese Einstellung wieder ausschalten!", -"Font Family": "Schriftart", -"Font Sizes": "Schriftgr\u00f6\u00dfe", -"Class": "Klasse", -"Browse for an image": "Bild...", -"OR": "ODER", -"Drop an image here": "Bild hier ablegen", -"Upload": "Hochladen", -"Block": "Blocksatz", -"Align": "Ausrichtung", -"Default": "Standard", -"Circle": "Kreis", -"Disc": "Punkt", -"Square": "Quadrat", -"Lower Alpha": "Kleinbuchstaben", -"Lower Greek": "Griechische Kleinbuchstaben", -"Lower Roman": "R\u00f6mische Zahlen (Kleinbuchstaben)", -"Upper Alpha": "Gro\u00dfbuchstaben", -"Upper Roman": "R\u00f6mische Zahlen (Gro\u00dfbuchstaben)", -"Anchor": "Textmarke", -"Name": "Name", -"Id": "Kennung", -"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "Die Kennung sollte mit einem Buchstaben anfangen. Nachfolgend nur Buchstaben, Zahlen, Striche (Minus), Punkte, Kommas und Unterstriche.", -"You have unsaved changes are you sure you want to navigate away?": "Die \u00c4nderungen wurden noch nicht gespeichert, sind Sie sicher, dass Sie diese Seite verlassen wollen?", -"Restore last draft": "Letzten Entwurf wiederherstellen", -"Special character": "Sonderzeichen", -"Source code": "Quelltext", -"Insert\/Edit code sample": "Codebeispiel einf\u00fcgen\/bearbeiten", -"Language": "Sprache", -"Code sample": "Codebeispiel", -"Color": "Farbe", -"R": "R", -"G": "G", -"B": "B", -"Left to right": "Von links nach rechts", -"Right to left": "Von rechts nach links", -"Emoticons": "Emoticons", -"Document properties": "Dokumenteigenschaften", -"Title": "Titel", -"Keywords": "Sch\u00fcsselw\u00f6rter", -"Description": "Beschreibung", -"Robots": "Robots", -"Author": "Verfasser", -"Encoding": "Zeichenkodierung", -"Fullscreen": "Vollbild", -"Action": "Aktion", -"Shortcut": "Shortcut", -"Help": "Hilfe", -"Address": "Adresse", -"Focus to menubar": "Fokus auf Men\u00fcleiste", -"Focus to toolbar": "Fokus auf Werkzeugleiste", -"Focus to element path": "Fokus auf Elementpfad", -"Focus to contextual toolbar": "Fokus auf kontextbezogene Werkzeugleiste", -"Insert link (if link plugin activated)": "Link einf\u00fcgen (wenn Link-Plugin aktiviert ist)", -"Save (if save plugin activated)": "Speichern (wenn Save-Plugin aktiviert ist)", -"Find (if searchreplace plugin activated)": "Suchen einf\u00fcgen (wenn Suchen\/Ersetzen-Plugin aktiviert ist)", -"Plugins installed ({0}):": "installierte Plugins ({0}):", -"Premium plugins:": "Premium Plugins:", -"Learn more...": "Erfahren Sie mehr dazu...", -"You are using {0}": "Sie verwenden {0}", -"Plugins": "Plugins", -"Handy Shortcuts": "Praktische Tastenkombinationen", -"Horizontal line": "Horizontale Linie", -"Insert\/edit image": "Bild einf\u00fcgen\/bearbeiten", -"Image description": "Bildbeschreibung", -"Source": "Quelle", -"Dimensions": "Abmessungen", -"Constrain proportions": "Seitenverh\u00e4ltnis beibehalten", -"General": "Allgemein", -"Advanced": "Erweitert", -"Style": "Stil", -"Vertical space": "Vertikaler Abstand", -"Horizontal space": "Horizontaler Abstand", -"Border": "Rahmen", -"Insert image": "Bild einf\u00fcgen", -"Image": "Bild", -"Image list": "Bildliste", -"Rotate counterclockwise": "Gegen den Uhrzeigersinn drehen", -"Rotate clockwise": "Im Uhrzeigersinn drehen", -"Flip vertically": "Vertikal spiegeln", -"Flip horizontally": "Horizontal spiegeln", -"Edit image": "Bild bearbeiten", -"Image options": "Bildeigenschaften", -"Zoom in": "Ansicht vergr\u00f6\u00dfern", -"Zoom out": "Ansicht verkleinern", -"Crop": "Bescheiden", -"Resize": "Skalieren", -"Orientation": "Ausrichtung", -"Brightness": "Helligkeit", -"Sharpen": "Sch\u00e4rfen", -"Contrast": "Kontrast", -"Color levels": "Farbwerte", -"Gamma": "Gamma", -"Invert": "Invertieren", -"Apply": "Anwenden", -"Back": "Zur\u00fcck", -"Insert date\/time": "Datum\/Uhrzeit einf\u00fcgen ", -"Date\/time": "Datum\/Uhrzeit", -"Insert link": "Link einf\u00fcgen", -"Insert\/edit link": "Link einf\u00fcgen\/bearbeiten", -"Text to display": "Anzuzeigender Text", -"Url": "URL", -"Target": "Ziel", -"None": "Keine", -"New window": "Neues Fenster", -"Remove link": "Link entfernen", -"Anchors": "Textmarken", -"Link": "Link", -"Paste or type a link": "Link einf\u00fcgen oder eintippen", -"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "Diese Adresse scheint eine E-Mail-Adresse zu sein. M\u00f6chten Sie das dazu ben\u00f6tigte \"mailto:\" voranstellen?", -"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "Diese Adresse scheint ein externer Link zu sein. M\u00f6chten Sie das dazu ben\u00f6tigte \"http:\/\/\" voranstellen?", -"Link list": "Linkliste", -"Insert video": "Video einf\u00fcgen", -"Insert\/edit video": "Video einf\u00fcgen\/bearbeiten", -"Insert\/edit media": "Medien einf\u00fcgen\/bearbeiten", -"Alternative source": "Alternative Quelle", -"Poster": "Poster", -"Paste your embed code below:": "F\u00fcgen Sie Ihren Einbettungscode hier ein:", -"Embed": "Einbetten", -"Media": "Medium", -"Nonbreaking space": "Gesch\u00fctztes Leerzeichen", -"Page break": "Seitenumbruch", -"Paste as text": "Als Text einf\u00fcgen", -"Preview": "Vorschau", -"Print": "Drucken", -"Save": "Speichern", -"Find": "Suchen", -"Replace with": "Ersetzen durch", -"Replace": "Ersetzen", -"Replace all": "Alles ersetzen", -"Prev": "Zur\u00fcck", -"Next": "Weiter", -"Find and replace": "Suchen und ersetzen", -"Could not find the specified string.": "Die Zeichenfolge wurde nicht gefunden.", -"Match case": "Gro\u00df-\/Kleinschreibung beachten", -"Whole words": "Nur ganze W\u00f6rter", -"Spellcheck": "Rechtschreibpr\u00fcfung", -"Ignore": "Ignorieren", -"Ignore all": "Alles Ignorieren", -"Finish": "Ende", -"Add to Dictionary": "Zum W\u00f6rterbuch hinzuf\u00fcgen", -"Insert table": "Tabelle einf\u00fcgen", -"Table properties": "Tabelleneigenschaften", -"Delete table": "Tabelle l\u00f6schen", -"Cell": "Zelle", -"Row": "Zeile", -"Column": "Spalte", -"Cell properties": "Zelleneigenschaften", -"Merge cells": "Zellen verbinden", -"Split cell": "Zelle aufteilen", -"Insert row before": "Neue Zeile davor einf\u00fcgen ", -"Insert row after": "Neue Zeile danach einf\u00fcgen", -"Delete row": "Zeile l\u00f6schen", -"Row properties": "Zeileneigenschaften", -"Cut row": "Zeile ausschneiden", -"Copy row": "Zeile kopieren", -"Paste row before": "Zeile davor einf\u00fcgen", -"Paste row after": "Zeile danach einf\u00fcgen", -"Insert column before": "Neue Spalte davor einf\u00fcgen", -"Insert column after": "Neue Spalte danach einf\u00fcgen", -"Delete column": "Spalte l\u00f6schen", -"Cols": "Spalten", -"Rows": "Zeilen", -"Width": "Breite", -"Height": "H\u00f6he", -"Cell spacing": "Zellenabstand", -"Cell padding": "Zelleninnenabstand", -"Caption": "Beschriftung", -"Left": "Linksb\u00fcndig", -"Center": "Zentriert", -"Right": "Rechtsb\u00fcndig", -"Cell type": "Zellentyp", -"Scope": "G\u00fcltigkeitsbereich", -"Alignment": "Ausrichtung", -"H Align": "Horizontale Ausrichtung", -"V Align": "Vertikale Ausrichtung", -"Top": "Oben", -"Middle": "Mitte", -"Bottom": "Unten", -"Header cell": "Kopfzelle", -"Row group": "Zeilengruppe", -"Column group": "Spaltengruppe", -"Row type": "Zeilentyp", -"Header": "Kopfzeile", -"Body": "Inhalt", -"Footer": "Fu\u00dfzeile", -"Border color": "Rahmenfarbe", -"Insert template": "Vorlage einf\u00fcgen ", -"Templates": "Vorlagen", -"Template": "Vorlage", -"Text color": "Textfarbe", -"Background color": "Hintergrundfarbe", -"Custom...": "Benutzerdefiniert...", -"Custom color": "Benutzerdefinierte Farbe", -"No color": "Keine Farbe", -"Table of Contents": "Inhaltsverzeichnis", -"Show blocks": "Bl\u00f6cke anzeigen", -"Show invisible characters": "Unsichtbare Zeichen anzeigen", -"Words: {0}": "W\u00f6rter: {0}", -"{0} words": "{0} W\u00f6rter", -"File": "Datei", -"Edit": "Bearbeiten", -"Insert": "Einf\u00fcgen", -"View": "Ansicht", -"Format": "Format", -"Table": "Tabelle", -"Tools": "Werkzeuge", -"Powered by {0}": "Betrieben von {0}", -"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rich-Text- Area. Dr\u00fccken Sie ALT-F9 f\u00fcr das Men\u00fc. Dr\u00fccken Sie ALT-F10 f\u00fcr Symbolleiste. Dr\u00fccken Sie ALT-0 f\u00fcr Hilfe" -}); \ No newline at end of file diff --git a/client/src/assets/tinymce/langs/en.js b/client/src/assets/tinymce/langs/en.js deleted file mode 100644 index 312698a93b..0000000000 --- a/client/src/assets/tinymce/langs/en.js +++ /dev/null @@ -1,261 +0,0 @@ -tinymce.addI18n('en_GB',{ -"Redo": "Redo", -"Undo": "Undo", -"Cut": "Cut", -"Copy": "Copy", -"Paste": "Paste", -"Select all": "Select all", -"New document": "New document", -"Ok": "Ok", -"Cancel": "Cancel", -"Visual aids": "Visual aids", -"Bold": "Bold", -"Italic": "Italic", -"Underline": "Underline", -"Strikethrough": "Strike-through", -"Superscript": "Superscript", -"Subscript": "Subscript", -"Clear formatting": "Clear formatting", -"Align left": "Align left", -"Align center": "Align centre", -"Align right": "Align right", -"Justify": "Justify", -"Bullet list": "Bullet list", -"Numbered list": "Numbered list", -"Decrease indent": "Decrease indent", -"Increase indent": "Increase indent", -"Close": "Close", -"Formats": "Formats", -"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.", -"Headers": "Headers", -"Header 1": "Header 1", -"Header 2": "Header 2", -"Header 3": "Header 3", -"Header 4": "Header 4", -"Header 5": "Header 5", -"Header 6": "Header 6", -"Headings": "Headings", -"Heading 1": "Heading 1", -"Heading 2": "Heading 2", -"Heading 3": "Heading 3", -"Heading 4": "Heading 4", -"Heading 5": "Heading 5", -"Heading 6": "Heading 6", -"Preformatted": "Preformatted", -"Div": "Div", -"Pre": "Pre", -"Code": "Code", -"Paragraph": "Paragraph", -"Blockquote": "Blockquote", -"Inline": "Inline", -"Blocks": "Blocks", -"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.", -"Font Family": "Font Family", -"Font Sizes": "Font Sizes", -"Class": "Class", -"Browse for an image": "Browse for an image", -"OR": "OR", -"Drop an image here": "Drop an image here", -"Upload": "Upload", -"Block": "Block", -"Align": "Align", -"Default": "Default", -"Circle": "Circle", -"Disc": "Disc", -"Square": "Square", -"Lower Alpha": "Lower Alpha", -"Lower Greek": "Lower Greek", -"Lower Roman": "Lower Roman", -"Upper Alpha": "Upper Alpha", -"Upper Roman": "Upper Roman", -"Anchor": "Anchor", -"Name": "Name", -"Id": "ID", -"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.", -"You have unsaved changes are you sure you want to navigate away?": "You have unsaved changes are you sure you want to navigate away?", -"Restore last draft": "Restore last draft", -"Special character": "Special character", -"Source code": "Source code", -"Insert\/Edit code sample": "Insert\/Edit code sample", -"Language": "Language", -"Code sample": "Code sample", -"Color": "Colour", -"R": "R", -"G": "G", -"B": "B", -"Left to right": "Left to right", -"Right to left": "Right to left", -"Emoticons": "Emoticons", -"Document properties": "Document properties", -"Title": "Title", -"Keywords": "Keywords", -"Description": "Description", -"Robots": "Robots", -"Author": "Author", -"Encoding": "Encoding", -"Fullscreen": "Full-screen", -"Action": "Action", -"Shortcut": "Shortcut", -"Help": "Help", -"Address": "Address", -"Focus to menubar": "Focus to menubar", -"Focus to toolbar": "Focus to toolbar", -"Focus to element path": "Focus to element path", -"Focus to contextual toolbar": "Focus to contextual toolbar", -"Insert link (if link plugin activated)": "Insert link (if link plugin activated)", -"Save (if save plugin activated)": "Save (if save plugin activated)", -"Find (if searchreplace plugin activated)": "Find (if searchreplace plugin activated)", -"Plugins installed ({0}):": "Plugins installed ({0}):", -"Premium plugins:": "Premium plugins:", -"Learn more...": "Learn more...", -"You are using {0}": "You are using {0}", -"Plugins": "Plugins", -"Handy Shortcuts": "Handy Shortcuts", -"Horizontal line": "Horizontal line", -"Insert\/edit image": "Insert\/edit image", -"Image description": "Image description", -"Source": "Source", -"Dimensions": "Dimensions", -"Constrain proportions": "Constrain proportions", -"General": "General", -"Advanced": "Advanced", -"Style": "Style", -"Vertical space": "Vertical space", -"Horizontal space": "Horizontal space", -"Border": "Border", -"Insert image": "Insert image", -"Image": "Image", -"Image list": "Image list", -"Rotate counterclockwise": "Rotate counterclockwise", -"Rotate clockwise": "Rotate clockwise", -"Flip vertically": "Flip vertically", -"Flip horizontally": "Flip horizontally", -"Edit image": "Edit image", -"Image options": "Image options", -"Zoom in": "Zoom in", -"Zoom out": "Zoom out", -"Crop": "Crop", -"Resize": "Resize", -"Orientation": "Orientation", -"Brightness": "Brightness", -"Sharpen": "Sharpen", -"Contrast": "Contrast", -"Color levels": "Colour levels", -"Gamma": "Gamma", -"Invert": "Invert", -"Apply": "Apply", -"Back": "Back", -"Insert date\/time": "Insert date\/time", -"Date\/time": "Date\/time", -"Insert link": "Insert link", -"Insert\/edit link": "Insert\/edit link", -"Text to display": "Text to display", -"Url": "URL", -"Target": "Target", -"None": "None", -"New window": "New window", -"Remove link": "Remove link", -"Anchors": "Anchors", -"Link": "Link", -"Paste or type a link": "Paste or type a link", -"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?", -"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?", -"Link list": "Link list", -"Insert video": "Insert video", -"Insert\/edit video": "Insert\/edit video", -"Insert\/edit media": "Insert\/edit media", -"Alternative source": "Alternative source", -"Poster": "Poster", -"Paste your embed code below:": "Paste your embed code below:", -"Embed": "Embed", -"Media": "Media", -"Nonbreaking space": "Non-breaking space", -"Page break": "Page break", -"Paste as text": "Paste as text", -"Preview": "Preview", -"Print": "Print", -"Save": "Save", -"Find": "Find", -"Replace with": "Replace with", -"Replace": "Replace", -"Replace all": "Replace all", -"Prev": "Prev", -"Next": "Next", -"Find and replace": "Find and replace", -"Could not find the specified string.": "Could not find the specified string.", -"Match case": "Match case", -"Whole words": "Whole words", -"Spellcheck": "Spell-check", -"Ignore": "Ignore", -"Ignore all": "Ignore all", -"Finish": "Finish", -"Add to Dictionary": "Add to Dictionary", -"Insert table": "Insert table", -"Table properties": "Table properties", -"Delete table": "Delete table", -"Cell": "Cell", -"Row": "Row", -"Column": "Column", -"Cell properties": "Cell properties", -"Merge cells": "Merge cells", -"Split cell": "Split cell", -"Insert row before": "Insert row before", -"Insert row after": "Insert row after", -"Delete row": "Delete row", -"Row properties": "Row properties", -"Cut row": "Cut row", -"Copy row": "Copy row", -"Paste row before": "Paste row before", -"Paste row after": "Paste row after", -"Insert column before": "Insert column before", -"Insert column after": "Insert column after", -"Delete column": "Delete column", -"Cols": "Cols", -"Rows": "Rows", -"Width": "Width", -"Height": "Height", -"Cell spacing": "Cell spacing", -"Cell padding": "Cell padding", -"Caption": "Caption", -"Left": "Left", -"Center": "Centre", -"Right": "Right", -"Cell type": "Cell type", -"Scope": "Scope", -"Alignment": "Alignment", -"H Align": "H Align", -"V Align": "V Align", -"Top": "Top", -"Middle": "Middle", -"Bottom": "Bottom", -"Header cell": "Header cell", -"Row group": "Row group", -"Column group": "Column group", -"Row type": "Row type", -"Header": "Header", -"Body": "Body", -"Footer": "Footer", -"Border color": "Border colour", -"Insert template": "Insert template", -"Templates": "Templates", -"Template": "Template", -"Text color": "Text colour", -"Background color": "Background colour", -"Custom...": "Custom...", -"Custom color": "Custom colour", -"No color": "No colour", -"Table of Contents": "Table of Contents", -"Show blocks": "Show blocks", -"Show invisible characters": "Show invisible characters", -"Words: {0}": "Words: {0}", -"{0} words": "{0} words", -"File": "File", -"Edit": "Edit", -"Insert": "Insert", -"View": "View", -"Format": "Format", -"Table": "Table", -"Tools": "Tools", -"Powered by {0}": "Powered by {0}", -"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help" -}); \ No newline at end of file diff --git a/client/src/assets/tinymce/langs/ru.js b/client/src/assets/tinymce/langs/ru.js deleted file mode 100644 index 3aed9bf7be..0000000000 --- a/client/src/assets/tinymce/langs/ru.js +++ /dev/null @@ -1,389 +0,0 @@ -tinymce.addI18n('ru',{ -"Redo": "\u0412\u0435\u0440\u043d\u0443\u0442\u044c", -"Undo": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c", -"Cut": "\u0412\u044b\u0440\u0435\u0437\u0430\u0442\u044c", -"Copy": "\u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c", -"Paste": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c", -"Select all": "\u0412\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u0432\u0441\u0435", -"New document": "\u041d\u043e\u0432\u044b\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442", -"Ok": "OK", -"Cancel": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c", -"Visual aids": "\u0412\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438", -"Bold": "\u0416\u0438\u0440\u043d\u044b\u0439 \u0448\u0440\u0438\u0444\u0442", -"Italic": "\u041a\u0443\u0440\u0441\u0438\u0432", -"Underline": "\u041f\u043e\u0434\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0435", -"Strikethrough": "\u0417\u0430\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0435", -"Superscript": "\u041d\u0430\u0434\u0441\u0442\u0440\u043e\u0447\u043d\u044b\u0439", -"Subscript": "\u041f\u043e\u0434\u0441\u0442\u0440\u043e\u0447\u043d\u044b\u0439", -"Clear formatting": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435", -"Align left": "\u0412\u044b\u0440\u043e\u0432\u043d\u044f\u0442\u044c \u043f\u043e \u043b\u0435\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e", -"Align center": "\u0412\u044b\u0440\u043e\u0432\u043d\u044f\u0442\u044c \u043f\u043e \u0446\u0435\u043d\u0442\u0440\u0443", -"Align right": "\u0412\u044b\u0440\u043e\u0432\u043d\u044f\u0442\u044c \u043f\u043e \u043f\u0440\u0430\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e", -"Justify": "\u0412\u044b\u0440\u043e\u0432\u043d\u044f\u0442\u044c \u0442\u0435\u0441\u0442 \u043f\u043e \u0448\u0438\u0440\u0438\u043d\u0435", -"Bullet list": "\u041c\u0430\u0440\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a", -"Numbered list": "\u041d\u0443\u043c\u0435\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a", -"Decrease indent": "\u0423\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u043e\u0442\u0441\u0442\u0443\u043f", -"Increase indent": "\u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c \u043e\u0442\u0441\u0442\u0443\u043f", -"Close": "\u0417\u0430\u043a\u0440\u044b\u0442\u044c", -"Formats": "\u0424\u043e\u0440\u043c\u0430\u0442\u044b", -"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u0412\u0430\u0448 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043f\u0440\u044f\u043c\u043e\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0431\u0443\u0444\u0435\u0440\u0443 \u043e\u0431\u043c\u0435\u043d\u0430. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u044f \u043a\u043b\u0430\u0432\u0438\u0448: Ctrl+X\/C\/V.", -"Headers": "\u0412\u0435\u0440\u0445\u043d\u0438\u0435 \u043a\u043e\u043b\u043e\u043d\u0442\u0438\u0442\u0443\u043b\u044b", -"Header 1": "\u0412\u0435\u0440\u0445\u043d\u0438\u0439 \u043a\u043e\u043b\u043e\u043d\u0442\u0438\u0442\u0443\u043b 1", -"Header 2": "\u0412\u0435\u0440\u0445\u043d\u0438\u0439 \u043a\u043e\u043b\u043e\u043d\u0442\u0438\u0442\u0443\u043b 2", -"Header 3": "\u0412\u0435\u0440\u0445\u043d\u0438\u0439 \u043a\u043e\u043b\u043e\u043d\u0442\u0438\u0442\u0443\u043b 3", -"Header 4": "\u0412\u0435\u0440\u0445\u043d\u0438\u0439 \u043a\u043e\u043b\u043e\u043d\u0442\u0438\u0442\u0443\u043b 4", -"Header 5": "\u0412\u0435\u0440\u0445\u043d\u0438\u0439 \u043a\u043e\u043b\u043e\u043d\u0442\u0438\u0442\u0443\u043b 5", -"Header 6": "\u0412\u0435\u0440\u0445\u043d\u0438\u0439 \u043a\u043e\u043b\u043e\u043d\u0442\u0438\u0442\u0443\u043b 6", -"Headings": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438", -"Heading 1": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 1", -"Heading 2": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 2", -"Heading 3": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 3", -"Heading 4": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 4", -"Heading 5": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 5", -"Heading 6": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a 6", -"Preformatted": "\u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439", -"Div": "Div", -"Pre": "Pre", -"Code": "\u041a\u043e\u0434", -"Paragraph": "\u0410\u0431\u0437\u0430\u0446", -"Blockquote": "\u0411\u043b\u043e\u043a \u0446\u0438\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f", -"Inline": "\u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439", -"Blocks": "\u0411\u043b\u043e\u043a\u0438", -"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u0412\u0441\u0442\u0430\u0432\u043a\u0430 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430, \u043f\u043e\u043a\u0430 \u043d\u0435 \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u0443\u044e \u043e\u043f\u0446\u0438\u044e.", -"Fonts": "\u0428\u0440\u0438\u0444\u0442\u044b", -"Font Sizes": "\u0420\u0430\u0437\u043c\u0435\u0440 \u0448\u0440\u0438\u0444\u0442\u0430", -"Class": "\u041a\u043b\u0430\u0441\u0441", -"Browse for an image": "\u0412\u044b\u0431\u043e\u0440 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f", -"OR": "\u0418\u041b\u0418", -"Drop an image here": "\u041f\u0435\u0440\u0435\u0442\u0430\u0449\u0438\u0442\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0441\u044e\u0434\u0430", -"Upload": "\u041f\u0435\u0440\u0435\u0434\u0430\u0442\u044c", -"Block": "\u0411\u043b\u043e\u043a", -"Align": "\u0412\u044b\u0440\u043e\u0432\u043d\u044f\u0442\u044c", -"Default": "\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439", -"Circle": "\u041e\u043a\u0440\u0443\u0436\u043d\u043e\u0441\u0442\u0438", -"Disc": "\u041a\u0440\u0443\u0433\u0438", -"Square": "\u041a\u0432\u0430\u0434\u0440\u0430\u0442\u044b", -"Lower Alpha": "\u0421\u0442\u0440\u043e\u0447\u043d\u044b\u0435 \u043b\u0430\u0442\u0438\u043d\u0441\u043a\u0438\u0435 \u0431\u0443\u043a\u0432\u044b", -"Lower Greek": "\u0421\u0442\u0440\u043e\u0447\u043d\u044b\u0435 \u0433\u0440\u0435\u0447\u0435\u0441\u043a\u0438\u0435 \u0431\u0443\u043a\u0432\u044b", -"Lower Roman": "\u0421\u0442\u0440\u043e\u0447\u043d\u044b\u0435 \u0440\u0438\u043c\u0441\u043a\u0438\u0435 \u0446\u0438\u0444\u0440\u044b", -"Upper Alpha": "\u0417\u0430\u0433\u043b\u0430\u0432\u043d\u044b\u0435 \u043b\u0430\u0442\u0438\u043d\u0441\u043a\u0438\u0435 \u0431\u0443\u043a\u0432\u044b", -"Upper Roman": "\u0417\u0430\u0433\u043b\u0430\u0432\u043d\u044b\u0435 \u0440\u0438\u043c\u0441\u043a\u0438\u0435 \u0446\u0438\u0444\u0440\u044b", -"Anchor...": "\u042f\u043a\u043e\u0440\u044c...", -"Name": "\u0418\u043c\u044f", -"Id": "Id", -"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "Id \u0434\u043e\u043b\u0436\u0435\u043d \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c\u0441\u044f \u0441 \u0431\u0443\u043a\u0432\u044b, \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \u0431\u0443\u043a\u0432\u044b, \u0446\u0438\u0444\u0440\u044b, \u0442\u0438\u0440\u0435, \u0442\u043e\u0447\u043a\u0438, \u0434\u0432\u043e\u0435\u0442\u043e\u0447\u0438\u044f \u0438\u043b\u0438 \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u044f.", -"You have unsaved changes are you sure you want to navigate away?": "\u0423 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u043d\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f. \u0412\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0447\u0442\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0439\u0442\u0438?", -"Restore last draft": "\u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430", -"Special characters...": "\u0421\u043f\u0435\u0446. \u0441\u0438\u043c\u0432\u043e\u043b\u044b...", -"Source code": "\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434", -"Insert\/Edit code sample": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c\/\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u0434\u0430", -"Language": "\u042f\u0437\u044b\u043a", -"Code sample...": "\u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u0434\u0430...", -"Color Picker": "\u041f\u0438\u043f\u0435\u0442\u043a\u0430 \u0446\u0432\u0435\u0442\u0430", -"R": "R", -"G": "G", -"B": "B", -"Left to right": "\u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043b\u0435\u0432\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043e", -"Right to left": "\u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043f\u0440\u0430\u0432\u0430 \u043d\u0430\u043b\u0435\u0432\u043e", -"Emoticons...": "\u0421\u043c\u0430\u0439\u043b\u0438\u043a\u0438...", -"Metadata and Document Properties": "\u041c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430", -"Title": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a", -"Keywords": "\u041a\u043b\u044e\u0447\u0438\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430", -"Description": "\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435", -"Robots": "\u0420\u043e\u0431\u043e\u0442\u044b", -"Author": "\u0410\u0432\u0442\u043e\u0440", -"Encoding": "\u041a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430", -"Fullscreen": "\u041f\u043e\u043b\u043d\u043e\u044d\u043a\u0440\u0430\u043d\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c", -"Action": "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435", -"Shortcut": "\u042f\u0440\u043b\u044b\u043a", -"Help": "\u041f\u043e\u043c\u043e\u0449\u044c", -"Address": "\u0410\u0434\u0440\u0435\u0441", -"Focus to menubar": "\u0424\u043e\u043a\u0443\u0441 \u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 \u043c\u0435\u043d\u044e", -"Focus to toolbar": "\u0424\u043e\u043a\u0443\u0441 \u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432", -"Focus to element path": "\u0424\u043e\u043a\u0443\u0441 \u043d\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0435 \u043f\u0443\u0442\u0438", -"Focus to contextual toolbar": "\u0424\u043e\u043a\u0443\u0441 \u043d\u0430 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0439 \u043f\u0430\u043d\u0435\u043b\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432", -"Insert link (if link plugin activated)": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 (\u0435\u0441\u043b\u0438 \u043f\u043b\u0430\u0433\u0438\u043d link \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043d)", -"Save (if save plugin activated)": "\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c (\u0435\u0441\u043b\u0438 \u043f\u043b\u0430\u0433\u0438\u043d save \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043d)", -"Find (if searchreplace plugin activated)": "\u041d\u0430\u0439\u0442\u0438 (\u0435\u0441\u043b\u0438 \u043f\u043b\u0430\u0433\u0438\u043d searchreplace \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043d)", -"Plugins installed ({0}):": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u043f\u043b\u0430\u0433\u0438\u043d\u044b ({0}):", -"Premium plugins:": "\u041f\u0440\u0435\u043c\u0438\u0443\u043c \u043f\u043b\u0430\u0433\u0438\u043d\u044b:", -"Learn more...": "\u0423\u0437\u043d\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435...", -"You are using {0}": "\u0412\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 {0}", -"Plugins": "\u041f\u043b\u0430\u0433\u0438\u043d\u044b", -"Handy Shortcuts": "\u0413\u043e\u0440\u044f\u0447\u0438\u0435 \u043a\u043b\u0430\u0432\u0438\u0448\u0438", -"Horizontal line": "\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u043b\u0438\u043d\u0438\u044f", -"Insert\/edit image": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c\/\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435", -"Image description": "\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f", -"Source": "\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a", -"Dimensions": "\u0420\u0430\u0437\u043c\u0435\u0440", -"Constrain proportions": "\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u043f\u0440\u043e\u043f\u043e\u0440\u0446\u0438\u0438", -"General": "\u041e\u0431\u0449\u0435\u0435", -"Advanced": "\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u0435", -"Style": "\u0421\u0442\u0438\u043b\u044c", -"Vertical space": "\u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b", -"Horizontal space": "\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b", -"Border": "\u0420\u0430\u043c\u043a\u0430", -"Insert image": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435", -"Image...": "\u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435...", -"Image list": "\u0421\u043f\u0438\u0441\u043e\u043a \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439", -"Rotate counterclockwise": "\u041f\u043e\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043f\u0440\u043e\u0442\u0438\u0432 \u0447\u0430\u0441\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u0435\u043b\u043a\u0438", -"Rotate clockwise": "\u041f\u043e\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043f\u043e \u0447\u0430\u0441\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u0435\u043b\u043a\u0435", -"Flip vertically": "\u041e\u0442\u0440\u0430\u0437\u0438\u0442\u044c \u043f\u043e \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u0438", -"Flip horizontally": "\u041e\u0442\u0440\u0430\u0437\u0438\u0442\u044c \u043f\u043e \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u0438", -"Edit image": "\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435", -"Image options": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f", -"Zoom in": "\u041f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u044c", -"Zoom out": "\u041e\u0442\u0434\u0430\u043b\u0438\u0442\u044c", -"Crop": "\u041e\u0431\u0440\u0435\u0437\u0430\u0442\u044c", -"Resize": "\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440", -"Orientation": "\u041e\u0440\u0438\u0435\u043d\u0442\u0430\u0446\u0438\u044f", -"Brightness": "\u042f\u0440\u043a\u043e\u0441\u0442\u044c", -"Sharpen": "\u0427\u0435\u0442\u043a\u043e\u0441\u0442\u044c", -"Contrast": "\u041a\u043e\u043d\u0442\u0440\u0430\u0441\u0442", -"Color levels": "\u0426\u0432\u0435\u0442\u043e\u0432\u044b\u0435 \u0443\u0440\u043e\u0432\u043d\u0438", -"Gamma": "\u0413\u0430\u043c\u043c\u0430", -"Invert": "\u0418\u043d\u0432\u0435\u0440\u0441\u0438\u044f", -"Apply": "\u041f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c", -"Back": "\u041d\u0430\u0437\u0430\u0434", -"Insert date\/time": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0434\u0430\u0442\u0443\/\u0432\u0440\u0435\u043c\u044f", -"Date\/time": "\u0414\u0430\u0442\u0430\/\u0432\u0440\u0435\u043c\u044f", -"Insert\/Edit Link": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c\/\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443", -"Insert\/edit link": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c\/\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443", -"Text to display": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c\u044b\u0439 \u0442\u0435\u043a\u0441\u0442", -"Url": "\u0410\u0434\u0440\u0435\u0441 \u0441\u0441\u044b\u043b\u043a\u0438", -"Open link in...": "\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 \u0432...", -"Current window": "\u0422\u0435\u043a\u0443\u0449\u0435\u0435 \u043e\u043a\u043d\u043e", -"None": "\u041d\u0435\u0442", -"New window": "\u0412 \u043d\u043e\u0432\u043e\u043c \u043e\u043a\u043d\u0435", -"Remove link": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443", -"Anchors": "\u042f\u043a\u043e\u0440\u044f", -"Link...": "\u0421\u0441\u044b\u043b\u043a\u0430...", -"Paste or type a link": "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0438\u043b\u0438 \u0432\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u0441\u0441\u044b\u043b\u043a\u0443", -"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\u0412\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0439 URL \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u043c \u0430\u0434\u0440\u0435\u0441\u043e\u043c \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b. \u0412\u044b \u0436\u0435\u043b\u0430\u0435\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u0435\u0444\u0438\u043a\u0441 \u00abmailto:\u00bb?", -"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "\u0412\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0439 URL \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u0441\u0441\u044b\u043b\u043a\u043e\u0439. \u0412\u044b \u0436\u0435\u043b\u0430\u0435\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u0435\u0444\u0438\u043a\u0441 \u00abhttp:\/\/\u00bb?", -"Link list": "\u0421\u043f\u0438\u0441\u043e\u043a \u0441\u0441\u044b\u043b\u043e\u043a", -"Insert video": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u0438\u0434\u0435\u043e", -"Insert\/edit video": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c\/\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0438\u0434\u0435\u043e", -"Insert\/edit media": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c\/\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0438\u0434\u0435\u043e", -"Alternative source": "\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a", -"Alternative source URL": "URL \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430", -"Media poster (Image URL)": "\u041f\u043e\u0441\u0442\u0435\u0440 \u043c\u0443\u043b\u044c\u0442\u0438\u043c\u0435\u0434\u0438\u0430 (URL \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f)", -"Paste your embed code below:": "\u0412\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u0432\u0430\u0448 \u043a\u043e\u0434 \u043d\u0438\u0436\u0435:", -"Embed": "\u041a\u043e\u0434 \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438", -"Media...": "\u041c\u0443\u043b\u044c\u0442\u0438\u043c\u0435\u0434\u0438\u0430...", -"Nonbreaking space": "\u041d\u0435\u0440\u0430\u0437\u0440\u044b\u0432\u043d\u044b\u0439 \u043f\u0440\u043e\u0431\u0435\u043b", -"Page break": "\u0420\u0430\u0437\u0440\u044b\u0432 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b", -"Paste as text": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u0430\u043a \u0442\u0435\u043a\u0441\u0442", -"Preview": "\u041f\u0440\u0435\u0434\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440", -"Print...": "\u041d\u0430\u043f\u0435\u0447\u0430\u0442\u0430\u0442\u044c...", -"Save": "\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c", -"Find": "\u041d\u0430\u0439\u0442\u0438", -"Replace with": "\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430", -"Replace": "\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c", -"Replace all": "\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u0441\u0435", -"Previous": "\u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439", -"Next": "\u0412\u043d\u0438\u0437", -"Find and replace...": "\u041d\u0430\u0439\u0442\u0438 \u0438 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c...", -"Could not find the specified string.": "\u0417\u0430\u0434\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430", -"Match case": "\u0423\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0440\u0435\u0433\u0438\u0441\u0442\u0440", -"Find whole words only": "\u041d\u0430\u0439\u0442\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0446\u0435\u043b\u044b\u0435 \u0441\u043b\u043e\u0432\u0430", -"Spell check": "\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u0438", -"Ignore": "\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c", -"Ignore all": "\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435", -"Finish": "\u0417\u0430\u043a\u043e\u043d\u0447\u0438\u0442\u044c", -"Add to Dictionary": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u044c", -"Insert table": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443", -"Table properties": "\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u044b", -"Delete table": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443", -"Cell": "\u042f\u0447\u0435\u0439\u043a\u0430", -"Row": "\u0421\u0442\u0440\u043e\u043a\u0430", -"Column": "\u0421\u0442\u043e\u043b\u0431\u0435\u0446", -"Cell properties": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u044f\u0447\u0435\u0439\u043a\u0438", -"Merge cells": "\u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u044f\u0447\u0435\u0439\u043a\u0438", -"Split cell": "\u0420\u0430\u0437\u0431\u0438\u0442\u044c \u044f\u0447\u0435\u0439\u043a\u0443", -"Insert row before": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u0443\u0441\u0442\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u0441\u0432\u0435\u0440\u0445\u0443", -"Insert row after": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u0443\u0441\u0442\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u0441\u043d\u0438\u0437\u0443", -"Delete row": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443", -"Row properties": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u0442\u0440\u043e\u043a\u0438", -"Cut row": "\u0412\u044b\u0440\u0435\u0437\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443", -"Copy row": "\u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443", -"Paste row before": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0441\u0432\u0435\u0440\u0445\u0443", -"Paste row after": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0441\u043d\u0438\u0437\u0443", -"Insert column before": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u0431\u0435\u0446 \u0441\u043b\u0435\u0432\u0430", -"Insert column after": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u0431\u0435\u0446 \u0441\u043f\u0440\u0430\u0432\u0430", -"Delete column": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u0431\u0435\u0446", -"Cols": "\u0421\u0442\u043e\u043b\u0431\u0446\u044b", -"Rows": "\u0421\u0442\u0440\u043e\u043a\u0438", -"Width": "\u0428\u0438\u0440\u0438\u043d\u0430", -"Height": "\u0412\u044b\u0441\u043e\u0442\u0430", -"Cell spacing": "\u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u043e\u0442\u0441\u0442\u0443\u043f", -"Cell padding": "\u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u043e\u0442\u0441\u0442\u0443\u043f", -"Show caption": "\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u043e\u0434\u043f\u0438\u0441\u044c", -"Left": "\u041f\u043e \u043b\u0435\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e", -"Center": "\u041f\u043e \u0446\u0435\u043d\u0442\u0440\u0443", -"Right": "\u041f\u043e \u043f\u0440\u0430\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e", -"Cell type": "\u0422\u0438\u043f \u044f\u0447\u0435\u0439\u043a\u0438", -"Scope": "Scope", -"Alignment": "\u0412\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435", -"H Align": "\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435", -"V Align": "\u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435", -"Top": "\u041f\u043e \u0432\u0435\u0440\u0445\u0443", -"Middle": "\u041f\u043e \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435", -"Bottom": "\u041f\u043e \u043d\u0438\u0437\u0443", -"Header cell": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a", -"Row group": "\u0413\u0440\u0443\u043f\u043f\u0430 \u0441\u0442\u0440\u043e\u043a", -"Column group": "\u0413\u0440\u0443\u043f\u043f\u0430 \u043a\u043e\u043b\u043e\u043d\u043e\u043a", -"Row type": "\u0422\u0438\u043f \u0441\u0442\u0440\u043e\u043a\u0438", -"Header": "\u0428\u0430\u043f\u043a\u0430", -"Body": "\u0422\u0435\u043b\u043e", -"Footer": "\u041d\u0438\u0437", -"Border color": "\u0426\u0432\u0435\u0442 \u0440\u0430\u043c\u043a\u0438", -"Insert template...": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d...", -"Templates": "\u0428\u0430\u0431\u043b\u043e\u043d\u044b", -"Template": "\u0428\u0430\u0431\u043b\u043e\u043d", -"Text color": "\u0426\u0432\u0435\u0442 \u0442\u0435\u043a\u0441\u0442\u0430", -"Background color": "\u0426\u0432\u0435\u0442 \u0444\u043e\u043d\u0430", -"Custom...": "\u0412\u044b\u0431\u0440\u0430\u0442\u044c\u2026", -"Custom color": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0446\u0432\u0435\u0442", -"No color": "\u0411\u0435\u0437 \u0446\u0432\u0435\u0442\u0430", -"Remove color": "\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0446\u0432\u0435\u0442", -"Table of Contents": "\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435", -"Show blocks": "\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0431\u043b\u043e\u043a\u0438", -"Show invisible characters": "\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0435\u0432\u0438\u0434\u0438\u043c\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b", -"Word count": "\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u043b\u043e\u0432", -"Words: {0}": "\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u043b\u043e\u0432: {0}", -"{0} words": "\u0441\u043b\u043e\u0432: {0}", -"File": "\u0424\u0430\u0439\u043b", -"Edit": "\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c", -"Insert": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c", -"View": "\u0412\u0438\u0434", -"Format": "\u0424\u043e\u0440\u043c\u0430\u0442", -"Table": "\u0422\u0430\u0431\u043b\u0438\u0446\u0430", -"Tools": "\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b", -"Powered by {0}": "\u041f\u0440\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435 {0}", -"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u0422\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435. \u041d\u0430\u0436\u043c\u0438\u0442\u0435 ALT-F9 \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043c\u0435\u043d\u044e, ALT-F10 \u043f\u0430\u043d\u0435\u043b\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, ALT-0 \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u043f\u043e\u043c\u043e\u0449\u0438.", -"Image title": "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f", -"Border width": "\u0428\u0438\u0440\u0438\u043d\u0430 \u0440\u0430\u043c\u043a\u0438", -"Border style": "\u0421\u0442\u0438\u043b\u044c \u0440\u0430\u043c\u043a\u0438", -"Error": "\u041e\u0448\u0438\u0431\u043a\u0430", -"Warn": "\u041f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u0435", -"Valid": "\u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0439", -"To open the popup, press Shift+Enter": "\u0427\u0442\u043e\u0431\u044b \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0435\u0435 \u043e\u043a\u043d\u043e, \u043d\u0430\u0436\u043c\u0438\u0442\u0435 Shift+Enter", -"Rich Text Area. Press ALT-0 for help.": "\u041f\u043e\u043b\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430. \u041d\u0430\u0436\u043c\u0438\u0442\u0435 ALT-0, \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0441\u043f\u0440\u0430\u0432\u043a\u0443.", -"System Font": "\u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u0448\u0440\u0438\u0444\u0442", -"Failed to upload image: {0}": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f: {0}", -"Failed to load plugin: {0} from url {1}": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u043f\u043b\u0430\u0433\u0438\u043d\u0430: {0} \u0438\u0437 URL {1}", -"Failed to load plugin url: {0}": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 URL \u043f\u043b\u0430\u0433\u0438\u043d\u0430: {0}", -"Failed to initialize plugin: {0}": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043b\u0430\u0433\u0438\u043d\u0430: {0}", -"example": "\u043f\u0440\u0438\u043c\u0435\u0440", -"Search": "\u041f\u043e\u0438\u0441\u043a", -"All": "\u0412\u0441\u0435", -"Currency": "\u0412\u0430\u043b\u044e\u0442\u0430", -"Text": "\u0422\u0435\u043a\u0441\u0442", -"Quotations": "\u0426\u0438\u0442\u0430\u0442\u044b", -"Mathematical": "\u041c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435", -"Extended Latin": "\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f \u043b\u0430\u0442\u044b\u043d\u044c", -"Symbols": "\u0421\u0438\u043c\u0432\u043e\u043b\u044b", -"Arrows": "\u0421\u0442\u0440\u0435\u043b\u043a\u0438", -"User Defined": "\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c", -"dollar sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0434\u043e\u043b\u043b\u0430\u0440\u0430", -"currency sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0432\u0430\u043b\u044e\u0442\u044b", -"euro-currency sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0435\u0432\u0440\u043e", -"colon sign": "\u0414\u0432\u043e\u0435\u0442\u043e\u0447\u0438\u0435", -"cruzeiro sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u043a\u0440\u0443\u0437\u0435\u0439\u0440\u043e", -"french franc sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0444\u0440\u0430\u043d\u0446\u0443\u0437\u0441\u043a\u043e\u0433\u043e \u0444\u0440\u0430\u043d\u043a\u0430", -"lira sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u043b\u0438\u0440\u044b", -"mill sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0434\u0435\u0441\u044f\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0446\u0435\u043d\u0442\u0430", -"naira sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u043d\u0430\u0439\u0440\u044b", -"peseta sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u043f\u0435\u0441\u0435\u0442\u044b", -"rupee sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0440\u0443\u043f\u0438\u0438", -"won sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0432\u043e\u043d\u044b", -"new sheqel sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0448\u0435\u043a\u0435\u043b\u044f", -"dong sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0434\u043e\u043d\u0433\u0430", -"kip sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u043a\u0438\u043f\u044b", -"tugrik sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0442\u0443\u0433\u0440\u0438\u043a\u0430", -"drachma sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0434\u0440\u0430\u0445\u043c\u044b", -"german penny symbol": "\u0421\u0438\u043c\u0432\u043e\u043b \u043f\u0444\u0435\u043d\u043d\u0438\u0433\u0430", -"peso sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u043f\u0435\u0441\u043e", -"guarani sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0433\u0443\u0430\u0440\u0430\u043d\u0438", -"austral sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0430\u0443\u0441\u0442\u0440\u0430\u043b\u0430", -"hryvnia sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0433\u0440\u0438\u0432\u043d\u0438", -"cedi sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0441\u0435\u0434\u0438", -"livre tournois sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u043b\u0438\u0432\u0440\u044b", -"spesmilo sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0441\u043f\u0435\u0441\u043c\u0438\u043b\u043e", -"tenge sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0442\u0435\u043d\u044c\u0433\u0435", -"indian rupee sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0438\u043d\u0434\u0438\u0439\u0441\u043a\u043e\u0439 \u0440\u0443\u043f\u0438\u0438", -"turkish lira sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0442\u0443\u0440\u0435\u0446\u043a\u043e\u0439 \u043b\u0438\u0440\u044b", -"nordic mark sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u043c\u0430\u0440\u043a\u0438", -"manat sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u043c\u0430\u043d\u0430\u0442\u0430", -"ruble sign": "\u0421\u0438\u043c\u0432\u043e\u043b \u0440\u0443\u0431\u043b\u044f", -"yen character": "\u0421\u0438\u043c\u0432\u043e\u043b \u0438\u0435\u043d\u044b", -"yuan character": "\u0421\u0438\u043c\u0432\u043e\u043b \u044e\u0430\u043d\u044f", -"yuan character, in hong kong and taiwan": "\u0421\u0438\u043c\u0432\u043e\u043b \u044e\u0430\u043d\u044f, \u0413\u043e\u043d\u043a\u043e\u043d\u0433 \u0438 \u0422\u0430\u0439\u0432\u0430\u043d\u044c", -"yen\/yuan character variant one": "\u0421\u0438\u043c\u0432\u043e\u043b \u0438\u0435\u043d\u044b\/\u044e\u0430\u043d\u044f, \u0432\u0430\u0440\u0438\u0430\u043d\u0442 1", -"Loading emoticons...": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0441\u043c\u0430\u0439\u043b\u043e\u0432...", -"Could not load emoticons": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0441\u043c\u0430\u0439\u043b\u044b", -"People": "\u041b\u044e\u0434\u0438", -"Animals and Nature": "\u0416\u0438\u0432\u043e\u0442\u043d\u044b\u0435 \u0438 \u043f\u0440\u0438\u0440\u043e\u0434\u0430", -"Food and Drink": "\u0415\u0434\u0430 \u0438 \u043d\u0430\u043f\u0438\u0442\u043a\u0438", -"Activity": "\u0414\u0435\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c", -"Travel and Places": "\u041f\u0443\u0442\u0435\u0448\u0435\u0441\u0442\u0432\u0438\u044f \u0438 \u043c\u0435\u0441\u0442\u0430", -"Objects": "\u041e\u0431\u044a\u0435\u043a\u0442\u044b", -"Flags": "\u0424\u043b\u0430\u0433\u0438", -"Characters": "\u0421\u0438\u043c\u0432\u043e\u043b\u044b", -"Characters (no spaces)": "\u0421\u0438\u043c\u0432\u043e\u043b\u044b (\u0431\u0435\u0437 \u043f\u0440\u043e\u0431\u0435\u043b\u043e\u0432)", -"Error: Form submit field collision.": "\u041e\u0448\u0438\u0431\u043a\u0430: \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442 \u043f\u043e\u043b\u0435\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0444\u043e\u0440\u043c\u044b.", -"Error: No form element found.": "\u041e\u0448\u0438\u0431\u043a\u0430: \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0444\u043e\u0440\u043c\u044b.", -"Update": "\u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c", -"Color swatch": "\u041e\u0431\u0440\u0430\u0437\u0435\u0446 \u0446\u0432\u0435\u0442\u0430", -"Turquoise": "\u0411\u0438\u0440\u044e\u0437\u043e\u0432\u044b\u0439", -"Green": "\u0417\u0435\u043b\u0435\u043d\u044b\u0439", -"Blue": "\u0421\u0438\u043d\u0438\u0439", -"Purple": "\u0420\u043e\u0437\u043e\u0432\u044b\u0439", -"Navy Blue": "\u0422\u0435\u043c\u043d\u043e-\u0441\u0438\u043d\u0438\u0439", -"Dark Turquoise": "\u0422\u0435\u043c\u043d\u043e-\u0431\u0438\u0440\u044e\u0437\u043e\u0432\u044b\u0439", -"Dark Green": "\u0422\u0435\u043c\u043d\u043e-\u0437\u0435\u043b\u0435\u043d\u044b\u0439", -"Medium Blue": "\u0421\u0440\u0435\u0434\u043d\u0438\u0439 \u0441\u0438\u043d\u0438\u0439", -"Medium Purple": "\u0423\u043c\u0435\u0440\u0435\u043d\u043d\u043e \u043f\u0443\u0440\u043f\u0443\u0440\u043d\u044b\u0439", -"Midnight Blue": "\u0427\u0435\u0440\u043d\u043e-\u0441\u0438\u043d\u0438\u0439", -"Yellow": "\u0416\u0435\u043b\u0442\u044b\u0439", -"Orange": "\u041e\u0440\u0430\u043d\u0436\u0435\u0432\u044b\u0439", -"Red": "\u041a\u0440\u0430\u0441\u043d\u044b\u0439", -"Light Gray": "\u0421\u0432\u0435\u0442\u043b\u043e-\u0441\u0435\u0440\u044b\u0439", -"Gray": "\u0421\u0435\u0440\u044b\u0439", -"Dark Yellow": "\u0422\u0435\u043c\u043d\u043e-\u0436\u0435\u043b\u0442\u044b\u0439", -"Dark Orange": "\u0422\u0435\u043c\u043d\u043e-\u043e\u0440\u0430\u043d\u0436\u0435\u0432\u044b\u0439", -"Dark Red": "\u0422\u0435\u043c\u043d\u043e-\u043a\u0440\u0430\u0441\u043d\u044b\u0439", -"Medium Gray": "\u0423\u043c\u0435\u0440\u0435\u043d\u043d\u043e \u0441\u0435\u0440\u044b\u0439", -"Dark Gray": "\u0422\u0435\u043c\u043d\u043e-\u0441\u0435\u0440\u044b\u0439", -"Black": "\u0427\u0435\u0440\u043d\u044b\u0439", -"White": "\u0411\u0435\u043b\u044b\u0439", -"Switch to or from fullscreen mode": "\u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u044d\u043a\u0440\u0430\u043d\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c", -"Open help dialog": "\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u0441\u043f\u0440\u0430\u0432\u043a\u0443", -"history": "\u0438\u0441\u0442\u043e\u0440\u0438\u044f", -"styles": "\u0441\u0442\u0438\u043b\u0438", -"formatting": "\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435", -"alignment": "\u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435", -"indentation": "\u043e\u0442\u0441\u0442\u0443\u043f", -"permanent pen": "\u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0435 \u043f\u0435\u0440\u043e", -"comments": "\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438", -"Anchor": "\u042f\u043a\u043e\u0440\u044c", -"Special character": "\u0421\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b", -"Code sample": "\u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u0434\u0430", -"Color": "\u0426\u0432\u0435\u0442", -"Emoticons": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043c\u0430\u0439\u043b", -"Document properties": "\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430", -"Image": "\u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f", -"Insert link": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443", -"Target": "\u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443", -"Link": "\u0421\u0441\u044b\u043b\u043a\u0430", -"Poster": "\u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435", -"Media": "\u0412\u0438\u0434\u0435\u043e", -"Print": "\u041f\u0435\u0447\u0430\u0442\u044c", -"Prev": "\u0412\u0432\u0435\u0440\u0445", -"Find and replace": "\u041f\u043e\u0438\u0441\u043a \u0438 \u0437\u0430\u043c\u0435\u043d\u0430", -"Whole words": "\u0421\u043b\u043e\u0432\u043e \u0446\u0435\u043b\u0438\u043a\u043e\u043c", -"Spellcheck": "\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435", -"Caption": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a", -"Insert template": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d" -}); \ No newline at end of file diff --git a/client/src/styles.scss b/client/src/styles.scss index 51b95c9d19..41f529de76 100644 --- a/client/src/styles.scss +++ b/client/src/styles.scss @@ -32,6 +32,7 @@ @import 'assets/styles/components.scss'; @import 'assets/styles/material/icon.scss'; @import 'assets/styles/pbl.scss'; +@import 'assets/styles/tiptap.scss'; /** * Must be cleaned up diff --git a/client/tests/integration/page-objects/meeting/home/edit.ts b/client/tests/integration/page-objects/meeting/home/edit.ts index b05e747c1a..2c9dae9858 100644 --- a/client/tests/integration/page-objects/meeting/home/edit.ts +++ b/client/tests/integration/page-objects/meeting/home/edit.ts @@ -4,14 +4,14 @@ import { MeetingHomePage } from './detail'; export class MeetingHomeEditPage { private readonly page: Page; public readonly frontPageTitleInput: Locator; - public readonly welcomeTextTinyMce: Locator; + public readonly welcomeTextEditor: Locator; public readonly saveButton: Locator; public readonly closeButton: Locator; public constructor(page: Page) { this.page = page; this.frontPageTitleInput = page.locator(`[formcontrolname=welcome_title]`); - this.welcomeTextTinyMce = page.locator(`.tox-tinymce`); + this.welcomeTextEditor = page.locator(`.editor-content .tiptap`); this.saveButton = page.locator(`[data-cy=headbarSaveButton]`); this.closeButton = page.locator(`[data-cy=headbarCloseButton]`); }