aboutsummaryrefslogtreecommitdiff
path: root/resources/assets/javascripts/cke
diff options
context:
space:
mode:
authorMarcus Eibrink-Lunzenauer <lunzenauer@elan-ev.de>2022-08-30 03:06:50 +0000
committerMarcus Eibrink-Lunzenauer <lunzenauer@elan-ev.de>2022-08-30 03:06:50 +0000
commit4573c1c71b7c38cb5dfdb68222fa501109b262cf (patch)
treef82d10b7f7abe745426f2fc9754e2f9249bd77cf /resources/assets/javascripts/cke
parentb6e68eada103fd3a8eca55c3751a778da9d5f624 (diff)
StEP00368: Update des CKEditors auf v5
Closes #1083, #1226, #1154, and #1088 Merge request studip/studip!641
Diffstat (limited to 'resources/assets/javascripts/cke')
-rw-r--r--resources/assets/javascripts/cke/StudipSettings.js138
-rw-r--r--resources/assets/javascripts/cke/StudipUpload.js41
-rw-r--r--resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiFood.js129
-rw-r--r--resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiNature.js178
-rw-r--r--resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiObjects.js5
-rw-r--r--resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiPeople.js192
-rw-r--r--resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiSport.js5
-rw-r--r--resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiSymbols.js224
-rw-r--r--resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiTraffic.js214
-rw-r--r--resources/assets/javascripts/cke/special_characters/SpecialCharactersGreek.js52
-rw-r--r--resources/assets/javascripts/cke/studip-a11y-dialog/a11y-dialog.js24
-rw-r--r--resources/assets/javascripts/cke/studip-a11y-dialog/command.js19
-rw-r--r--resources/assets/javascripts/cke/studip-a11y-dialog/editing.js16
-rw-r--r--resources/assets/javascripts/cke/studip-a11y-dialog/ui.js32
-rw-r--r--resources/assets/javascripts/cke/studip-quote/StudipBlockQuote.js127
-rw-r--r--resources/assets/javascripts/cke/wiki-link/editing.js16
-rw-r--r--resources/assets/javascripts/cke/wiki-link/formview.js185
-rw-r--r--resources/assets/javascripts/cke/wiki-link/insertcommand.js18
-rw-r--r--resources/assets/javascripts/cke/wiki-link/ui.js70
-rw-r--r--resources/assets/javascripts/cke/wiki-link/wiki-link.js28
20 files changed, 1713 insertions, 0 deletions
diff --git a/resources/assets/javascripts/cke/StudipSettings.js b/resources/assets/javascripts/cke/StudipSettings.js
new file mode 100644
index 0000000..db92c05
--- /dev/null
+++ b/resources/assets/javascripts/cke/StudipSettings.js
@@ -0,0 +1,138 @@
+import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
+import { createDropdown, ButtonView, View } from 'ckeditor5/src/ui';
+import { $gettext } from '../lib/gettext.js';
+
+const settings = {
+ url: STUDIP.URLHelper.resolveURL('dispatch.php/wysiwyg/settings/users/current'),
+ save: function (data) {
+ return $.ajax({
+ url: this.url,
+ type: 'PUT',
+ contentType: 'application/json',
+ data: JSON.stringify(data),
+ });
+ },
+};
+
+const gearsIcon =
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 54"><path d="M50.58,22.76l-.95-.4a3.12,3.12,0,0,1,0-5.8l.95-.41h0a.69.69,0,0,0,.37-.89h0l-.7-1.69-1.13-2.75A.71.71,0,0,0,49,10.6a.67.67,0,0,0-.74-.15h0l-.95.39a3.05,3.05,0,0,1-3.43-.65,3.15,3.15,0,0,1-.65-3.45l.4-1a.69.69,0,0,0-.36-.89L38.82,3.05a.67.67,0,0,0-.88.37l-.41,1a3.08,3.08,0,0,1-5.75,0l-.41-1a.68.68,0,0,0-.89-.37L26.07,4.9a.68.68,0,0,0-.37.89l.39,1A3.1,3.1,0,0,1,22,10.85h0l-.95-.4a.68.68,0,0,0-.89.37l-1.83,4.44a.69.69,0,0,0,.37.89l1,.41a3.12,3.12,0,0,1,0,5.79l-.95.42a.69.69,0,0,0-.38.89l1.83,4.44a.7.7,0,0,0,.89.37l1-.4a3.05,3.05,0,0,1,3.42.65,3.12,3.12,0,0,1,.64,3.45h0l-.4,1a.68.68,0,0,0,.37.89l4.41,1.84a.68.68,0,0,0,.89-.36l.4-1a3.08,3.08,0,0,1,5.76,0l.4,1a.68.68,0,0,0,.89.36L43.23,34a.68.68,0,0,0,.37-.89l-.4-1h0a3.15,3.15,0,0,1,.65-3.45,3.06,3.06,0,0,1,3.42-.65h0l.95.4a.69.69,0,0,0,.89-.37L51,23.65A.69.69,0,0,0,50.58,22.76ZM36.89,24.9a5.84,5.84,0,0,1-7.65-3.19A5.91,5.91,0,0,1,32.41,14a5.84,5.84,0,0,1,7.65,3.18A5.91,5.91,0,0,1,36.89,24.9Z"/><path d="M25.82,37.11H25.1a2.14,2.14,0,0,1-2-1.33,2.21,2.21,0,0,1,.5-2.41l.51-.51a.5.5,0,0,0,0-.68l-2.36-2.38a.46.46,0,0,0-.67,0l-.52.52a2.16,2.16,0,0,1-2.39.5,2.19,2.19,0,0,1-1.33-2.06V28a.47.47,0,0,0-.47-.48H13a.48.48,0,0,0-.48.47v.73a2.16,2.16,0,0,1-3.72,1.56h0l-.51-.52a.46.46,0,0,0-.67,0L5.24,32.17a.48.48,0,0,0,0,.68l.5.51a2.19,2.19,0,0,1,.5,2.41,2.14,2.14,0,0,1-2,1.33H3.48a.48.48,0,0,0-.48.48V41a.48.48,0,0,0,.48.48H4.2a2.15,2.15,0,0,1,2,1.34,2.17,2.17,0,0,1-.5,2.4h0l-.51.52a.48.48,0,0,0,0,.67l2.36,2.38a.46.46,0,0,0,.67,0l.52-.51a2.16,2.16,0,0,1,2.39-.5A2.18,2.18,0,0,1,12.5,49.8v.72h0A.49.49,0,0,0,13,51h3.34a.47.47,0,0,0,.48-.48h0V49.8a2.18,2.18,0,0,1,1.33-2.06,2.16,2.16,0,0,1,2.39.5l.51.52a.46.46,0,0,0,.67,0l2.37-2.38a.48.48,0,0,0,0-.67l-.51-.53a2.19,2.19,0,0,1-.5-2.4,2.15,2.15,0,0,1,2-1.34h.72A.48.48,0,0,0,26.3,41V37.59A.47.47,0,0,0,25.82,37.11ZM14.65,43.39a4.12,4.12,0,1,1,4.09-4.12A4.1,4.1,0,0,1,14.65,43.39Z"/></svg>';
+
+export class StudipSettings extends Plugin {
+ init() {
+ this.editor.ui.componentFactory.add('studipSettings', (locale) => {
+ const dropdownView = createDropdown(locale);
+
+ dropdownView.buttonView.set({
+ label: $gettext('Stud.IP Einstellungen'),
+ icon: gearsIcon,
+ tooltip: true,
+ });
+
+ dropdownView.render();
+
+ const studipSettingsView = new StudipSettingsView(locale);
+ dropdownView.panelView.children.add(studipSettingsView);
+ studipSettingsView.on('wysiwyg:change', (eventInfo, disabled) => {
+ this._save(studipSettingsView, disabled).then(() => (dropdownView.isOpen = false));
+ });
+
+ return dropdownView;
+ });
+ }
+
+ _save(view, disabled) {
+ view.functional = false;
+
+ return settings
+ .save({ disabled })
+ .fail(function (xhr) {
+ console.error("couldn't save changes");
+ })
+ .always(() => {
+ view.functional = true;
+ });
+ }
+}
+
+class StudipSettingsView extends View {
+ constructor(locale) {
+ super(locale);
+
+ const bind = this.bindTemplate;
+ this.set({
+ checked: false,
+ functional: true,
+ });
+
+ const button = createButton();
+ this.button = button;
+ button.on('execute', () => {
+ this.fire('wysiwyg:change', this.checked);
+ });
+
+ this.on('checking', (...args) => {
+ this.checked = !this.checked;
+ });
+
+ this.setTemplate({
+ tag: 'form',
+ attributes: {
+ class: ['default ck-studip-settings-form'],
+ tabindex: '-1',
+ style: 'max-width: 20em; padding: 1em;',
+ },
+ children: [createCheckbox(), createHelpText(), button],
+ });
+
+ function createCheckbox() {
+ return {
+ tag: 'label',
+ children: [
+ {
+ tag: 'input',
+ attributes: {
+ id: 'disable',
+ type: 'checkbox',
+ checked: bind.to('checked'),
+ style: 'margin-right: 0.5em'
+ },
+ on: {
+ change: bind.to('checking'),
+ },
+ },
+ {
+ text: $gettext('WYSIWYG Editor ausschalten'),
+ },
+ ],
+ };
+ }
+
+ function createHelpText() {
+ return {
+ tag: 'p',
+ attributes: {
+ style: 'white-space: normal; font-size: 1em; line-height: 1.5em; margin-bottom: 1em;',
+ },
+ children: [
+ {
+ text: $gettext(
+ 'Mit dieser Einstellung kรถnnen Sie den WYSIWYG Editor ausschalten. Dadurch mรผssen Sie gegebenenfalls Texte in HTML schreiben. Der Editor wird erst vollstรคndig entfernt, wenn die Seite neu geladen wird.'
+ ),
+ },
+ ],
+ };
+ }
+
+ function createButton() {
+ const button = new ButtonView(locale);
+
+ button.set({
+ label: $gettext('Speichern'),
+ withText: true,
+ isEnabled: bind.to('functional'),
+ });
+
+ return button;
+ }
+ }
+}
diff --git a/resources/assets/javascripts/cke/StudipUpload.js b/resources/assets/javascripts/cke/StudipUpload.js
new file mode 100644
index 0000000..58297da
--- /dev/null
+++ b/resources/assets/javascripts/cke/StudipUpload.js
@@ -0,0 +1,41 @@
+class StudipUploadAdapter {
+ constructor(loader) {
+ this.loader = loader;
+ }
+
+ upload() {
+ return this.loader.file.then(
+ (file) =>
+ new Promise((resolve, reject) => {
+ var data = new FormData();
+ data.append('files[]', file);
+
+ $.ajax({
+ url: STUDIP.URLHelper.getURL('dispatch.php/wysiwyg/upload'),
+ type: 'POST',
+ data: data,
+ contentType: false,
+ async: false,
+ processData: false,
+ cache: false,
+ dataType: 'json',
+ error: function (err) {
+ reject(err);
+ },
+ success: function (data) {
+ resolve({ default: data.files[0].url });
+ },
+ });
+ })
+ );
+ }
+
+ // Aborts the upload process.
+ abort() {}
+}
+
+export default function StudipUpload(editor) {
+ editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
+ return new StudipUploadAdapter(loader);
+ };
+}
diff --git a/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiFood.js b/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiFood.js
new file mode 100644
index 0000000..eabb1c2
--- /dev/null
+++ b/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiFood.js
@@ -0,0 +1,129 @@
+export default function SpecialCharactersEmojiFood( editor ) {
+ editor.plugins.get( 'SpecialCharacters' ).addItems( 'Emoji Food', [
+ { title: 'grapes', character: '๐Ÿ‡' },
+ { title: 'melon', character: '๐Ÿˆ' },
+ { title: 'watermelon', character: '๐Ÿ‰' },
+ { title: 'tangerine', character: '๐ŸŠ' },
+ { title: 'lemon', character: '๐Ÿ‹' },
+ { title: 'banana', character: '๐ŸŒ' },
+ { title: 'pineapple', character: '๐Ÿ' },
+ { title: 'mango', character: '๐Ÿฅญ' },
+ { title: 'red apple', character: '๐ŸŽ' },
+ { title: 'green apple', character: '๐Ÿ' },
+ { title: 'pear', character: '๐Ÿ' },
+ { title: 'peach', character: '๐Ÿ‘' },
+ { title: 'cherries', character: '๐Ÿ’' },
+ { title: 'strawberry', character: '๐Ÿ“' },
+ { title: 'blueberries', character: '๐Ÿซ' },
+ { title: 'kiwi fruit', character: '๐Ÿฅ' },
+ { title: 'tomato', character: '๐Ÿ…' },
+ { title: 'olive', character: '๐Ÿซ’' },
+ { title: 'coconut', character: '๐Ÿฅฅ' },
+ { title: 'avocado', character: '๐Ÿฅ‘' },
+ { title: 'eggplant', character: '๐Ÿ†' },
+ { title: 'potato', character: '๐Ÿฅ”' },
+ { title: 'carrot', character: '๐Ÿฅ•' },
+ { title: 'ear of corn', character: '๐ŸŒฝ' },
+ { title: 'hot pepper', character: '๐ŸŒถ' },
+ { title: 'bell pepper', character: '๐Ÿซ‘' },
+ { title: 'cucumber', character: '๐Ÿฅ’' },
+ { title: 'leafy green', character: '๐Ÿฅฌ' },
+ { title: 'broccoli', character: '๐Ÿฅฆ' },
+ { title: 'garlic', character: '๐Ÿง„' },
+ { title: 'onion', character: '๐Ÿง…' },
+ { title: 'mushroom', character: '๐Ÿ„' },
+ { title: 'peanuts', character: '๐Ÿฅœ' },
+ { title: 'chestnut', character: '๐ŸŒฐ' },
+
+ { character: '๐Ÿž', title: 'bread' },
+ { character: '๐Ÿฅ', title: 'croissant' },
+ { character: '๐Ÿฅ–', title: 'baguette bread' },
+ { character: '๐Ÿซ“', title: 'flatbread' },
+ { character: '๐Ÿฅจ', title: 'pretzel' },
+ { character: '๐Ÿฅฏ', title: 'bagel' },
+ { character: '๐Ÿฅž', title: 'pancakes' },
+ { character: '๐Ÿง‡', title: 'waffle' },
+ { character: '๐Ÿง€', title: 'cheese wedge' },
+ { character: '๐Ÿ–', title: 'meat on bone' },
+ { character: '๐Ÿ—', title: 'poultry leg' },
+ { character: '๐Ÿฅฉ', title: 'cut of meat' },
+ { character: '๐Ÿฅ“', title: 'bacon' },
+ { character: '๐Ÿ”', title: 'hamburger' },
+ { character: '๐ŸŸ', title: 'french fries' },
+ { character: '๐Ÿ•', title: 'pizza' },
+ { character: '๐ŸŒญ', title: 'hot dog' },
+ { character: '๐Ÿฅช', title: 'sandwich' },
+ { character: '๐ŸŒฎ', title: 'taco' },
+ { character: '๐ŸŒฏ', title: 'burrito' },
+ { character: '๐Ÿซ”', title: 'tamale' },
+ { character: '๐Ÿฅ™', title: 'stuffed flatbread' },
+ { character: '๐Ÿง†', title: 'falafel' },
+ { character: '๐Ÿฅš', title: 'egg' },
+ { character: '๐Ÿณ', title: 'cooking' },
+ { character: '๐Ÿฅ˜', title: 'shallow pan of food' },
+ { character: '๐Ÿฒ', title: 'pot of food' },
+ { character: '๐Ÿซ•', title: 'fondue' },
+ { character: '๐Ÿฅฃ', title: 'bowl with spoon' },
+ { character: '๐Ÿฅ—', title: 'green salad' },
+ { character: '๐Ÿฟ', title: 'popcorn' },
+ { character: '๐Ÿงˆ', title: 'butter' },
+ { character: '๐Ÿง‚', title: 'salt' },
+ { character: '๐Ÿฅซ', title: 'canned food' },
+ { character: '๐Ÿฑ', title: 'bento box' },
+ { character: '๐Ÿ˜', title: 'rice cracker' },
+ { character: '๐Ÿ™', title: 'rice ball' },
+ { character: '๐Ÿš', title: 'cooked rice' },
+ { character: '๐Ÿ›', title: 'curry rice' },
+ { character: '๐Ÿœ', title: 'steaming bowl' },
+ { character: '๐Ÿ', title: 'spaghetti' },
+ { character: '๐Ÿ ', title: 'roasted sweet potato' },
+ { character: '๐Ÿข', title: 'oden' },
+ { character: '๐Ÿฃ', title: 'sushi' },
+ { character: '๐Ÿค', title: 'fried shrimp' },
+ { character: '๐Ÿฅ', title: 'fish cake with swirl' },
+ { character: '๐Ÿฅฎ', title: 'moon cake' },
+ { character: '๐Ÿก', title: 'dango' },
+ { character: '๐ŸฅŸ', title: 'dumpling' },
+ { character: '๐Ÿฅ ', title: 'fortune cookie' },
+ { character: '๐Ÿฅก', title: 'takeout box' },
+ { character: '๐Ÿฆ', title: 'soft ice cream' },
+ { character: '๐Ÿง', title: 'shaved ice' },
+ { character: '๐Ÿจ', title: 'ice cream' },
+ { character: '๐Ÿฉ', title: 'doughnut' },
+ { character: '๐Ÿช', title: 'cookie' },
+ { character: '๐ŸŽ‚', title: 'birthday cake' },
+ { character: '๐Ÿฐ', title: 'shortcake' },
+ { character: '๐Ÿง', title: 'cupcake' },
+ { character: '๐Ÿฅง', title: 'pie' },
+ { character: '๐Ÿซ', title: 'chocolate bar' },
+ { character: '๐Ÿฌ', title: 'candy' },
+ { character: '๐Ÿญ', title: 'lollipop' },
+ { character: '๐Ÿฎ', title: 'custard' },
+ { character: '๐Ÿฏ', title: 'honey pot' },
+ { character: '๐Ÿผ', title: 'baby bottle' },
+ { character: '๐Ÿฅ›', title: 'glass of milk' },
+ { character: 'โ˜•', title: 'hot beverage' },
+ { character: '๐Ÿซ–', title: 'teapot' },
+ { character: '๐Ÿต', title: 'teacup without handle' },
+ { character: '๐Ÿถ', title: 'sake' },
+ { character: '๐Ÿพ', title: 'bottle with popping cork' },
+ { character: '๐Ÿท', title: 'wine glass' },
+ { character: '๐Ÿธ', title: 'cocktail glass' },
+ { character: '๐Ÿน', title: 'tropical drink' },
+ { character: '๐Ÿบ', title: 'beer mug' },
+ { character: '๐Ÿป', title: 'clinking beer mugs' },
+ { character: '๐Ÿฅ‚', title: 'clinking glasses' },
+ { character: '๐Ÿฅƒ', title: 'tumbler glass' },
+ { character: '๐Ÿฅค', title: 'cup with straw' },
+ { character: '๐Ÿง‹', title: 'bubble tea' },
+ { character: '๐Ÿงƒ', title: 'beverage box' },
+ { character: '๐Ÿง‰', title: 'mate' },
+ { character: '๐ŸงŠ', title: 'ice' },
+ { character: '๐Ÿฅข', title: 'chopsticks' },
+ { character: '๐Ÿฝ', title: 'fork and knife with plate' },
+ { character: '๐Ÿด', title: 'fork and knife' },
+ { character: '๐Ÿฅ„', title: 'spoon' },
+ { character: '๐Ÿ”ช', title: 'kitchen knife' },
+ { character: '๐Ÿบ', title: 'amphora' },
+ ] );
+} \ No newline at end of file
diff --git a/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiNature.js b/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiNature.js
new file mode 100644
index 0000000..50ee133
--- /dev/null
+++ b/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiNature.js
@@ -0,0 +1,178 @@
+export default function SpecialCharactersEmojiNature( editor ) {
+ editor.plugins.get( 'SpecialCharacters' ).addItems( 'Emoji Nature', [
+ { title: 'dog face', character: '๐Ÿถ' },
+ { title: 'cat face', character: '๐Ÿฑ' },
+ { title: 'mouse face', character: '๐Ÿญ' },
+ { title: 'hamster', character: '๐Ÿน' },
+ { title: 'rabbit face', character: '๐Ÿฐ' },
+ { title: 'horse face', character: '๐Ÿด' },
+ { title: 'unicorn', character: '๐Ÿฆ„' },
+ { title: 'fox', character: '๐ŸฆŠ' },
+ { title: 'wolf', character: '๐Ÿบ' },
+ { title: 'raccoon', character: '๐Ÿฆ' },
+ { title: 'bear', character: '๐Ÿป' },
+ { title: 'panda', character: '๐Ÿผ' },
+ { title: 'polar bear', character: '๐Ÿปโ€โ„๏ธ' },
+ { title: 'koala', character: '๐Ÿจ' },
+ { title: 'tiger face', character: '๐Ÿฏ' },
+ { title: 'lion', character: '๐Ÿฆ' },
+ { title: 'cow face', character: '๐Ÿฎ' },
+ { title: 'pig face', character: '๐Ÿท' },
+ { title: 'frog', character: '๐Ÿธ' },
+ { title: 'dragon face', character: '๐Ÿฒ' },
+ { title: 'monkey face', character: '๐Ÿต' },
+ { title: 'see-no-evil monkey', character: '๐Ÿ™ˆ' },
+ { title: 'hear-no-evil monkey', character: '๐Ÿ™‰' },
+ { title: 'speak-no-evil monkey', character: '๐Ÿ™Š' },
+ { title: 'chicken', character: '๐Ÿ”' },
+ { title: 'rooster', character: '๐Ÿ“' },
+ { title: 'hatching chick', character: '๐Ÿฃ' },
+ { title: 'baby chick', character: '๐Ÿค' },
+ { title: 'front-facing baby chick', character: '๐Ÿฅ' },
+ { title: 'bird', character: '๐Ÿฆ' },
+ { title: 'penguin', character: '๐Ÿง' },
+ { title: 'dove', character: '๐Ÿ•Š' },
+ { title: 'eagle', character: '๐Ÿฆ…' },
+ { title: 'duck', character: '๐Ÿฆ†' },
+ { title: 'swan', character: '๐Ÿฆข' },
+ { title: 'owl', character: '๐Ÿฆ‰' },
+ { title: 'dodo', character: '๐Ÿฆค' },
+ { title: 'flamingo', character: '๐Ÿฆฉ' },
+ { title: 'peacock', character: '๐Ÿฆš' },
+ { title: 'parrot', character: '๐Ÿฆœ' },
+ { title: 'turkey', character: '๐Ÿฆƒ' },
+ { title: 'feather', character: '๐Ÿชถ' },
+ { title: 'snail', character: '๐ŸŒ' },
+ { title: 'butterfly', character: '๐Ÿฆ‹' },
+ { title: 'bug', character: '๐Ÿ›' },
+ { title: 'ant', character: '๐Ÿœ' },
+ { title: 'honeybee', character: '๐Ÿ' },
+ { title: 'beetle', character: '๐Ÿชฒ' },
+ { title: 'lady beetle', character: '๐Ÿž' },
+ { title: 'cricket', character: '๐Ÿฆ—' },
+ { title: 'cockroach', character: '๐Ÿชณ' },
+ { title: 'spider', character: '๐Ÿ•ท' },
+ { title: 'spider web', character: '๐Ÿ•ธ' },
+ { title: 'scorpion', character: '๐Ÿฆ‚' },
+ { title: 'mosquito', character: '๐ŸฆŸ' },
+ { title: 'fly', character: '๐Ÿชฐ' },
+ { title: 'worm', character: '๐Ÿชฑ' },
+ { title: 'microbe', character: '๐Ÿฆ ' },
+ { title: 'crocodile', character: '๐ŸŠ' },
+ { title: 'turtle', character: '๐Ÿข' },
+ { title: 'lizard', character: '๐ŸฆŽ' },
+ { title: 'snake', character: '๐Ÿ' },
+ { title: 'dragon', character: '๐Ÿ‰' },
+ { title: 'sauropod', character: '๐Ÿฆ•' },
+ { title: 'T-Rex', character: '๐Ÿฆ–' },
+ { title: 'spouting whale', character: '๐Ÿณ' },
+ { title: 'whale', character: '๐Ÿ‹' },
+ { title: 'dolphin', character: '๐Ÿฌ' },
+ { title: 'seal', character: '๐Ÿฆญ' },
+ { title: 'fish', character: '๐ŸŸ' },
+ { title: 'tropical fish', character: '๐Ÿ ' },
+ { title: 'blowfish', character: '๐Ÿก' },
+ { title: 'shark', character: '๐Ÿฆˆ' },
+ { title: 'octopus', character: '๐Ÿ™' },
+ { title: 'spiral shell', character: '๐Ÿš' },
+ { title: 'crab', character: '๐Ÿฆ€' },
+ { title: 'lobster', character: '๐Ÿฆž' },
+ { title: 'shrimp', character: '๐Ÿฆ' },
+ { title: 'squid', character: '๐Ÿฆ‘' },
+ { title: 'monkey', character: '๐Ÿ’' },
+ { title: 'gorilla', character: '๐Ÿฆ' },
+ { title: 'orangutan', character: '๐Ÿฆง' },
+ { title: 'dog', character: '๐Ÿ•' },
+ { title: 'cat', character: '๐Ÿˆ' },
+ { title: 'black cat', character: '๐Ÿˆโ€โฌ›' },
+ { title: 'tiger', character: '๐Ÿ…' },
+ { title: 'leopard', character: '๐Ÿ†' },
+ { title: 'horse', character: '๐ŸŽ' },
+ { title: 'zebra', character: '๐Ÿฆ“' },
+ { title: 'deer', character: '๐ŸฆŒ' },
+ { title: 'bison', character: '๐Ÿฆฌ' },
+ { title: 'ox', character: '๐Ÿ‚' },
+ { title: 'water buffalo', character: '๐Ÿƒ' },
+ { title: 'cow', character: '๐Ÿ„' },
+ { title: 'pig', character: '๐Ÿ–' },
+ { title: 'boar', character: '๐Ÿ—' },
+ { title: 'ram', character: '๐Ÿ' },
+ { title: 'ewe', character: '๐Ÿ‘' },
+ { title: 'goat', character: '๐Ÿ' },
+ { title: 'camel', character: '๐Ÿช' },
+ { title: 'two-hump camel', character: '๐Ÿซ' },
+ { title: 'llama', character: '๐Ÿฆ™' },
+ { title: 'giraffe', character: '๐Ÿฆ’' },
+ { title: 'elephant', character: '๐Ÿ˜' },
+ { title: 'mammoth', character: '๐Ÿฆฃ' },
+ { title: 'rhinoceros', character: '๐Ÿฆ' },
+ { title: 'hippopotamus', character: '๐Ÿฆ›' },
+ { title: 'mouse', character: '๐Ÿ' },
+ { title: 'rat', character: '๐Ÿ€' },
+ { title: 'rabbit', character: '๐Ÿ‡' },
+ { title: 'chipmunk', character: '๐Ÿฟ' },
+ { title: 'beaver', character: '๐Ÿฆซ' },
+ { title: 'hedgehog', character: '๐Ÿฆ”' },
+ { title: 'bat', character: '๐Ÿฆ‡' },
+ { title: 'sloth', character: '๐Ÿฆฅ' },
+ { title: 'otter', character: '๐Ÿฆฆ' },
+ { title: 'skunk', character: '๐Ÿฆจ' },
+ { title: 'kangaroo', character: '๐Ÿฆ˜' },
+ { title: 'badger', character: '๐Ÿฆก' },
+ { title: 'paw prints', character: '๐Ÿพ' },
+ { title: 'bouquet', character: '๐Ÿ’' },
+ { title: 'cherry blossom', character: '๐ŸŒธ' },
+ { title: 'white flower', character: '๐Ÿ’ฎ' },
+ { title: 'rosette', character: '๐Ÿต' },
+ { title: 'rose', character: '๐ŸŒน' },
+ { title: 'wilted flower', character: '๐Ÿฅ€' },
+ { title: 'hibiscus', character: '๐ŸŒบ' },
+ { title: 'sunflower', character: '๐ŸŒป' },
+ { title: 'blossom', character: '๐ŸŒผ' },
+ { title: 'tulip', character: '๐ŸŒท' },
+ { title: 'seedling', character: '๐ŸŒฑ' },
+ { title: 'potted plant', character: '๐Ÿชด' },
+ { title: 'evergreen tree', character: '๐ŸŒฒ' },
+ { title: 'Christmas tree', character: '๐ŸŽ„' },
+ { title: 'deciduous tree', character: '๐ŸŒณ' },
+ { title: 'palm tree', character: '๐ŸŒด' },
+ { title: 'cactus', character: '๐ŸŒต' },
+ { title: 'sheaf of rice', character: '๐ŸŒพ' },
+ { title: 'herb', character: '๐ŸŒฟ' },
+ { title: 'shamrock', character: 'โ˜˜๏ธ' },
+ { title: 'four leaf clover', character: '๐Ÿ€' },
+ { title: 'maple leaf', character: '๐Ÿ' },
+ { title: 'fallen leaf', character: '๐Ÿ‚' },
+ { title: 'leaf fluttering in wind', character: '๐Ÿƒ' },
+ { title: 'tanabata tree', character: '๐ŸŽ‹' },
+ { title: 'mushroom', character: '๐Ÿ„' },
+ { title: 'sun', character: 'โ˜€๏ธ' },
+ { title: 'sun with face', character: '๐ŸŒž' },
+ { title: 'full moon face', character: '๐ŸŒ' },
+ { title: 'first quarter moon face', character: '๐ŸŒ›' },
+ { title: 'last quarter moon face', character: '๐ŸŒœ' },
+ { title: 'globe showing Europe-Africa', character: '๐ŸŒ' },
+ { title: 'globe showing Americas', character: '๐ŸŒŽ' },
+ { title: 'globe showing Asia-Australia', character: '๐ŸŒ' },
+ { title: 'ringed planet', character: '๐Ÿช' },
+ { title: 'glowing star', character: 'โญ' },
+ { title: 'comet', character: 'โ˜„๏ธ' },
+ { title: 'shooting star', character: '๐ŸŒ ' },
+ { title: 'sun behind cloud', character: 'โ›…' },
+ { title: 'cloud with lightning and rain', character: 'โ›ˆ' },
+ { title: 'sun behind small cloud', character: '๐ŸŒค' },
+ { title: 'sun behind large cloud', character: '๐ŸŒฅ' },
+ { title: 'sun behind rain cloud', character: '๐ŸŒฆ' },
+ { title: 'cloud with rain', character: '๐ŸŒง' },
+ { title: 'cloud with snow', character: '๐ŸŒจ' },
+ { title: 'cloud with lightning', character: '๐ŸŒฉ' },
+ { title: 'fog', character: '๐ŸŒซ' },
+ { title: 'tornado', character: '๐ŸŒช' },
+ { title: 'rainbow', character: '๐ŸŒˆ' },
+ { title: 'snowflake', character: 'โ„๏ธ' },
+ { title: 'snowman', character: 'โ˜ƒ๏ธ' },
+ { title: 'snowman', character: 'โ›„' },
+ { title: 'fire', character: '๐Ÿ”ฅ' },
+ { title: 'water wave', character: '๐ŸŒŠ' },
+ ] );
+}
diff --git a/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiObjects.js b/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiObjects.js
new file mode 100644
index 0000000..69442cd
--- /dev/null
+++ b/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiObjects.js
@@ -0,0 +1,5 @@
+export default function SpecialCharactersEmojiObjects( editor ) {
+ editor.plugins.get( 'SpecialCharacters' ).addItems( 'Emoji Objects', [
+ { title: '', character: '' },
+ ] );
+} \ No newline at end of file
diff --git a/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiPeople.js b/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiPeople.js
new file mode 100644
index 0000000..45c6224
--- /dev/null
+++ b/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiPeople.js
@@ -0,0 +1,192 @@
+export default function SpecialCharactersEmojiPeople( editor ) {
+ editor.plugins.get( 'SpecialCharacters' ).addItems( 'Emoji People', [
+ { title: 'smiley grinning face', character: '๐Ÿ˜€' },
+ { title: 'smiley grinning face with big eyes', character: '๐Ÿ˜ƒ' },
+ { title: 'smiley grinning face with smiling eyes', character: '๐Ÿ˜„' },
+ { title: 'smiley beaming face with smiling eyes', character: '๐Ÿ˜' },
+ { title: 'smiley grinning squinting face', character: '๐Ÿ˜†' },
+ { title: 'smiley grinning face with sweat', character: '๐Ÿ˜…' },
+ { title: 'smiley face with tears of joy', character: '๐Ÿ˜‚' },
+ { title: 'smiley rolling on the floor laughing', character: '๐Ÿคฃ' },
+ { title: 'smiley slightly smiling face', character: '๐Ÿ™‚' },
+ { title: 'smiley upside-down face', character: '๐Ÿ™ƒ' },
+ { title: 'smiley winking face', character: '๐Ÿ˜‰' },
+ { title: 'smiley smiling face with smiling eyes', character: '๐Ÿ˜Š' },
+ { title: 'smiley smiling face with halo', character: '๐Ÿ˜‡' },
+ { title: 'smiley smiling face with hearts', character: '๐Ÿฅฐ' },
+ { title: 'smiley smiling face with heart-eyes', character: '๐Ÿ˜' },
+ { title: 'smiley star-struck', character: '๐Ÿคฉ' },
+ { title: 'smiley face blowing a kiss', character: '๐Ÿ˜˜' },
+ { title: 'smiley kissing face', character: '๐Ÿ˜—' },
+ { title: 'smiley kissing face with smiling eyes', character: '๐Ÿ˜™' },
+ { title: 'smiley kissing face with closed eyes', character: '๐Ÿ˜š' },
+ { title: 'smiley smiling face with tear', character: '๐Ÿฅฒ' },
+ { title: 'smiley face savoring food', character: '๐Ÿ˜‹' },
+ { title: 'smiley face with tongue', character: '๐Ÿ˜›' },
+ { title: 'smiley squinting face with tongue', character: '๐Ÿ˜' },
+ { title: 'smiley winking face with tongue', character: '๐Ÿ˜œ' },
+ { title: 'smiley zany face', character: '๐Ÿคช' },
+ { title: 'smiley money-mouth face', character: '๐Ÿค‘' },
+ { title: 'smiley smiling face with open hands', character: '๐Ÿค—' },
+ { title: 'smiley face with hand over mouth', character: '๐Ÿคญ' },
+ { title: 'smiley shushing face', character: '๐Ÿคซ' },
+ { title: 'smiley thinking face', character: '๐Ÿค”' },
+ { title: 'smiley zipper-mouth face', character: '๐Ÿค' },
+ { title: 'smiley face with raised eyebrow', character: '๐Ÿคจ' },
+ { title: 'smiley neutral face', character: '๐Ÿ˜' },
+ { title: 'smiley expressionless face', character: '๐Ÿ˜‘' },
+ { title: 'smiley face without mouth', character: '๐Ÿ˜ถ' },
+ { title: 'smiley face in clouds', character: '๐Ÿ˜ถโ€๐ŸŒซ๏ธ' },
+ { title: 'smiley smirking face', character: '๐Ÿ˜' },
+ { title: 'smiley unamused face', character: '๐Ÿ˜’' },
+ { title: 'smiley face with rolling eyes', character: '๐Ÿ™„' },
+ { title: 'smiley grimacing face', character: '๐Ÿ˜ฌ' },
+ { title: 'smiley face exhaling', character: '๐Ÿ˜ฎโ€๐Ÿ’จ' },
+ { title: 'smiley lying face', character: '๐Ÿคฅ' },
+ { title: 'smiley relieved face', character: '๐Ÿ˜Œ' },
+ { title: 'smiley pensive face', character: '๐Ÿ˜”' },
+ { title: 'smiley sleepy face', character: '๐Ÿ˜ช' },
+ { title: 'smiley drooling face', character: '๐Ÿคค' },
+ { title: 'smiley sleeping face', character: '๐Ÿ˜ด' },
+ { title: 'smiley face with medical mask', character: '๐Ÿ˜ท' },
+ { title: 'smiley face with thermometer', character: '๐Ÿค’' },
+ { title: 'smiley face with head-bandage', character: '๐Ÿค•' },
+ { title: 'smiley nauseated face', character: '๐Ÿคข' },
+ { title: 'smiley face vomiting', character: '๐Ÿคฎ' },
+ { title: 'smiley sneezing face', character: '๐Ÿคง' },
+ { title: 'smiley hot face', character: '๐Ÿฅต' },
+ { title: 'smiley cold face', character: '๐Ÿฅถ' },
+ { title: 'smiley woozy face', character: '๐Ÿฅด' },
+ { title: 'smiley face with crossed-out eyes', character: '๐Ÿ˜ต' },
+ { title: 'smiley face with spiral eyes', character: '๐Ÿ˜ตโ€๐Ÿ’ซ' },
+ { title: 'smiley exploding head', character: '๐Ÿคฏ' },
+ { title: 'smiley cowboy hat face', character: '๐Ÿค ' },
+ { title: 'smiley partying face', character: '๐Ÿฅณ' },
+ { title: 'smiley disguised face', character: '๐Ÿฅธ' },
+ { title: 'smiley smiling face with sunglasses', character: '๐Ÿ˜Ž' },
+ { title: 'smiley nerd face', character: '๐Ÿค“' },
+ { title: 'smiley face with monocle', character: '๐Ÿง' },
+ { title: 'smiley confused face', character: '๐Ÿ˜•' },
+ { title: 'smiley worried face', character: '๐Ÿ˜Ÿ' },
+ { title: 'smiley slightly frowning face', character: '๐Ÿ™' },
+ { title: 'smiley frowning face', character: 'โ˜น๏ธ' },
+ { title: 'smiley face with open mouth', character: '๐Ÿ˜ฎ' },
+ { title: 'smiley hushed face', character: '๐Ÿ˜ฏ' },
+ { title: 'smiley astonished face', character: '๐Ÿ˜ฒ' },
+ { title: 'smiley flushed face', character: '๐Ÿ˜ณ' },
+ { title: 'smiley pleading face', character: '๐Ÿฅบ' },
+ { title: 'smiley frowning face with open mouth', character: '๐Ÿ˜ฆ' },
+ { title: 'smiley anguished face', character: '๐Ÿ˜ง' },
+ { title: 'smiley fearful face', character: '๐Ÿ˜จ' },
+ { title: 'smiley anxious face with sweat', character: '๐Ÿ˜ฐ' },
+ { title: 'smiley sad but relieved face', character: '๐Ÿ˜ฅ' },
+ { title: 'smiley crying face', character: '๐Ÿ˜ข' },
+ { title: 'smiley loudly crying face', character: '๐Ÿ˜ญ' },
+ { title: 'smiley face screaming in fear', character: '๐Ÿ˜ฑ' },
+ { title: 'smiley confounded face', character: '๐Ÿ˜–' },
+ { title: 'smiley persevering face', character: '๐Ÿ˜ฃ' },
+ { title: 'smiley disappointed face', character: '๐Ÿ˜ž' },
+ { title: 'smiley downcast face with sweat', character: '๐Ÿ˜“' },
+ { title: 'smiley weary face', character: '๐Ÿ˜ฉ' },
+ { title: 'smiley tired face', character: '๐Ÿ˜ซ' },
+ { title: 'smiley yawning face', character: '๐Ÿฅฑ' },
+ { title: 'smiley face with steam from nose', character: '๐Ÿ˜ค' },
+ { title: 'smiley pouting face', character: '๐Ÿ˜ ' },
+ { title: 'smiley angry face', character: '๐Ÿ˜ก' },
+ { title: 'smiley face with symbols on mouth', character: '๐Ÿคฌ' },
+ { title: 'smiley smiling face with horns', character: '๐Ÿ˜ˆ' },
+ { title: 'smiley angry face with horns', character: '๐Ÿ‘ฟ' },
+ { title: 'skull', character: '๐Ÿ’€' },
+ { title: 'skull and crossbones', character: 'โ˜ ๏ธ' },
+ { title: 'pile of poo', character: '๐Ÿ’ฉ' },
+ { title: 'smiley clown face', character: '๐Ÿคก' },
+ { title: 'ogre', character: '๐Ÿ‘น' },
+ { title: 'goblin', character: '๐Ÿ‘บ' },
+ { title: 'jack-o-lantern', character: '๐ŸŽƒ' },
+ { title: 'ghost', character: '๐Ÿ‘ป' },
+ { title: 'alien', character: '๐Ÿ‘ฝ' },
+ { title: 'alien monster', character: '๐Ÿ‘พ' },
+ { title: 'robot', character: '๐Ÿค–' },
+ { title: 'smiley grinning cat', character: '๐Ÿ˜บ' },
+ { title: 'smiley grinning cat with smiling eyes', character: '๐Ÿ˜ธ' },
+ { title: 'smiley cat with tears of joy', character: '๐Ÿ˜น' },
+ { title: 'smiley smiling cat with heart-eyes', character: '๐Ÿ˜ป' },
+ { title: 'smiley cat with wry smile', character: '๐Ÿ˜ผ' },
+ { title: 'smiley kissing cat', character: '๐Ÿ˜ฝ' },
+ { title: 'smiley weary cat', character: '๐Ÿ™€' },
+ { title: 'smiley crying cat', character: '๐Ÿ˜ฟ' },
+ { title: 'smiley pouting cat', character: '๐Ÿ˜พ' },
+ { title: 'see-no-evil monkey', character: '๐Ÿ™ˆ' },
+ { title: 'hear-no-evil monkey', character: '๐Ÿ™‰' },
+ { title: 'speak-no-evil monkey', character: '๐Ÿ™Š' },
+ { title: 'waving hand', character: '๐Ÿ‘‹' },
+ { title: 'raised back of hand', character: '๐Ÿคš' },
+ { title: 'hand with fingers splayed', character: '๐Ÿ–' },
+ { title: 'raised hand', character: 'โœ‹' },
+ { title: 'vulcan salute', character: '๐Ÿ––' },
+ { title: 'OK hand', character: '๐Ÿ‘Œ' },
+ { title: 'pinched fingers', character: '๐ŸคŒ' },
+ { title: 'pinching hand', character: '๐Ÿค' },
+ { title: 'victory hand', character: 'โœŒ๏ธ' },
+ { title: 'crossed fingers', character: '๐Ÿคž' },
+ { title: 'love-you gesture', character: '๐ŸคŸ' },
+ { title: 'sign of the horns', character: '๐Ÿค˜' },
+ { title: 'call me hand', character: '๐Ÿค™' },
+ { title: 'backhand index pointing left', character: '๐Ÿ‘ˆ' },
+ { title: 'backhand index pointing right', character: '๐Ÿ‘‰' },
+ { title: 'backhand index pointing up', character: '๐Ÿ‘†' },
+ { title: 'backhand index pointing down', character: '๐Ÿ‘‡' },
+ { title: 'index pointing up', character: 'โ˜๏ธ' },
+ { title: 'thumbs up', character: '๐Ÿ‘' },
+ { title: 'thumbs down', character: '๐Ÿ‘Ž' },
+ { title: 'raised fist', character: 'โœŠ' },
+ { title: 'clapping hands', character: '๐Ÿ‘' },
+ { title: 'raising hands', character: '๐Ÿ™Œ' },
+ { title: 'open hands', character: '๐Ÿ‘' },
+ { title: 'palms up together', character: '๐Ÿคฒ' },
+ { title: 'handshake', character: '๐Ÿค' },
+ { title: 'folded hands', character: '๐Ÿ™' },
+ { title: 'writing hand', character: 'โœ๏ธ' },
+ { title: 'selfie', character: '๐Ÿคณ' },
+ { title: 'flexed biceps', character: '๐Ÿ’ช' },
+ { title: 'ear', character: '๐Ÿ‘‚' },
+ { title: 'nose', character: '๐Ÿ‘ƒ' },
+ { title: 'eyes', character: '๐Ÿ‘€' },
+ { title: 'baby', character: '๐Ÿ‘ถ' },
+ { title: 'child', character: '๐Ÿง’' },
+ { title: 'boy', character: '๐Ÿ‘ฆ' },
+ { title: 'girl', character: '๐Ÿ‘ง' },
+ { title: 'person', character: '๐Ÿง‘' },
+ { title: 'man', character: '๐Ÿ‘จ' },
+ { title: 'woman', character: '๐Ÿ‘ฉ' },
+ { title: 'person frowning', character: '๐Ÿ™' },
+ { title: 'man frowning', character: '๐Ÿ™โ€โ™‚๏ธ' },
+ { title: 'woman frowning', character: '๐Ÿ™โ€โ™€๏ธ' },
+ { title: 'person pouting', character: '๐Ÿ™Ž' },
+ { title: 'man pouting', character: '๐Ÿ™Žโ€โ™‚๏ธ' },
+ { title: 'woman pouting', character: '๐Ÿ™Žโ€โ™€๏ธ' },
+ { title: 'person gesturing NO', character: '๐Ÿ™…' },
+ { title: 'man gesturing NO', character: '๐Ÿ™…โ€โ™‚๏ธ' },
+ { title: 'woman gesturing NO', character: '๐Ÿ™…โ€โ™€๏ธ' },
+ { title: 'person gesturing OK', character: '๐Ÿ™†' },
+ { title: 'man gesturing OK', character: '๐Ÿ™†โ€โ™‚๏ธ' },
+ { title: 'woman gesturing OK', character: '๐Ÿ™†โ€โ™€๏ธ' },
+ { title: 'person tipping hand', character: '๐Ÿ’' },
+ { title: 'man tipping hand', character: '๐Ÿ’โ€โ™‚๏ธ' },
+ { title: 'woman tipping hand', character: '๐Ÿ’โ€โ™€๏ธ' },
+ { title: 'person raising hand', character: '๐Ÿ™‹' },
+ { title: 'man raising hand', character: '๐Ÿ™‹โ€โ™‚๏ธ' },
+ { title: 'woman raising hand', character: '๐Ÿ™‹โ€โ™€๏ธ' },
+ { title: 'person facepalming', character: '๐Ÿคฆ' },
+ { title: 'man facepalming', character: '๐Ÿคฆโ€โ™‚๏ธ' },
+ { title: 'woman facepalming', character: '๐Ÿคฆโ€โ™€๏ธ' },
+ { title: 'person shrugging', character: '๐Ÿคท' },
+ { title: 'man shrugging', character: '๐Ÿคทโ€โ™‚๏ธ' },
+ { title: 'woman shrugging', character: '๐Ÿคทโ€โ™€๏ธ' },
+ { title: 'speaking head', character: '๐Ÿ—ฃ' },
+ { title: 'bust in silhouette', character: '๐Ÿ‘ค' },
+ { title: 'busts in silhouette', character: '๐Ÿ‘ฅ' },
+ { title: 'people hugging', character: '๐Ÿซ‚' },
+ { title: 'footprints', character: '๐Ÿ‘ฃ' },
+ ] );
+}
diff --git a/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiSport.js b/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiSport.js
new file mode 100644
index 0000000..997ad1c
--- /dev/null
+++ b/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiSport.js
@@ -0,0 +1,5 @@
+export default function SpecialCharactersEmojiSport( editor ) {
+ editor.plugins.get( 'SpecialCharacters' ).addItems( 'Emoji Sport', [
+ { title: '', character: '' },
+ ] );
+} \ No newline at end of file
diff --git a/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiSymbols.js b/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiSymbols.js
new file mode 100644
index 0000000..d6da0eb
--- /dev/null
+++ b/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiSymbols.js
@@ -0,0 +1,224 @@
+export default function SpecialCharactersEmojiSymbols( editor ) {
+ editor.plugins.get( 'SpecialCharacters' ).addItems( 'Emoji Symbols', [
+ { title: 'red heart', character: 'โค๏ธ' },
+ { title: 'orange heart', character: '๐Ÿงก' },
+ { title: 'yellow heart', character: '๐Ÿ’›' },
+ { title: 'green heart', character: '๐Ÿ’š' },
+ { title: 'blue heart', character: '๐Ÿ’™' },
+ { title: 'purple heart', character: '๐Ÿ’œ' },
+ { title: 'brown heart', character: '๐ŸคŽ' },
+ { title: 'black heart', character: '๐Ÿ–ค' },
+ { title: 'white heart', character: '๐Ÿค' },
+ { title: 'heart with arrow', character: '๐Ÿ’˜' },
+ { title: 'heart with ribbon', character: '๐Ÿ’' },
+ { title: 'sparkling heart', character: '๐Ÿ’–' },
+ { title: 'growing heart', character: '๐Ÿ’—' },
+ { title: 'beating heart', character: '๐Ÿ’“' },
+ { title: 'revolving hearts', character: '๐Ÿ’ž' },
+ { title: 'two hearts', character: '๐Ÿ’•' },
+ { title: 'heart exclamation', character: 'โฃ๏ธ' },
+ { title: 'broken heart', character: '๐Ÿ’”' },
+ { title: 'heart on fire', character: 'โค๏ธโ€๐Ÿ”ฅ' },
+ { title: 'mending heart', character: 'โค๏ธโ€๐Ÿฉน' },
+ { title: 'heart decoration', character: '๐Ÿ’Ÿ' },
+ { title: 'place of worship', character: '๐Ÿ›' },
+ { title: 'atom symbol', character: 'โš›๏ธ' },
+ { title: 'om', character: '๐Ÿ•‰' },
+ { title: 'star of David', character: 'โœก๏ธ' },
+ { title: 'wheel of dharma', character: 'โ˜ธ๏ธ' },
+ { title: 'yin yang', character: 'โ˜ฏ๏ธ' },
+ { title: 'latin cross', character: 'โœ๏ธ' },
+ { title: 'orthodox cross', character: 'โ˜ฆ๏ธ' },
+ { title: 'star and crescent', character: 'โ˜ช๏ธ' },
+ { title: 'peace symbol', character: 'โ˜ฎ๏ธ' },
+ { title: 'menorah', character: '๐Ÿ•Ž' },
+ { title: 'dotted six-pointed star', character: '๐Ÿ”ฏ' },
+ { title: 'Aries', character: 'โ™ˆ' },
+ { title: 'Taurus', character: 'โ™‰' },
+ { title: 'Gemini', character: 'โ™Š' },
+ { title: 'Cancer', character: 'โ™‹' },
+ { title: 'Leo', character: 'โ™Œ' },
+ { title: 'Virgo', character: 'โ™' },
+ { title: 'Libra', character: 'โ™Ž' },
+ { title: 'Scorpio', character: 'โ™' },
+ { title: 'Sagittarius', character: 'โ™' },
+ { title: 'Capricorn', character: 'โ™‘' },
+ { title: 'Aquarius', character: 'โ™’' },
+ { title: 'Pisces', character: 'โ™“' },
+ { title: 'Ophiuchus', character: 'โ›Ž' },
+ { title: 'ATM sign', character: '๐Ÿง' },
+ { title: 'litter in bin sign', character: '๐Ÿšฎ' },
+ { title: 'potable water', character: '๐Ÿšฐ' },
+ { title: 'wheelchair symbol', character: 'โ™ฟ๏ธ' },
+ { title: 'menโ€™s room', character: '๐Ÿšน' },
+ { title: 'womenโ€™s room', character: '๐Ÿšบ' },
+ { title: 'restroom', character: '๐Ÿšป' },
+ { title: 'baby symbol', character: '๐Ÿšผ' },
+ { title: 'water closet', character: '๐Ÿšพ' },
+ { title: 'passport control', character: '๐Ÿ›‚' },
+ { title: 'customs', character: '๐Ÿ›ƒ' },
+ { title: 'baggage claim', character: '๐Ÿ›„' },
+ { title: 'left luggage', character: '๐Ÿ›…' },
+ { title: 'warning', character: 'โš ๏ธ' },
+ { title: 'children crossing', character: '๐Ÿšธ' },
+ { title: 'no entry', character: 'โ›”๏ธ' },
+ { title: 'prohibited', character: '๐Ÿšซ' },
+ { title: 'no bicycles', character: '๐Ÿšณ' },
+ { title: 'no smoking', character: '๐Ÿšญ' },
+ { title: 'no littering', character: '๐Ÿšฏ' },
+ { title: 'non-potable water', character: '๐Ÿšฑ' },
+ { title: 'no pedestrians', character: '๐Ÿšท' },
+ { title: 'no mobile phones', character: '๐Ÿ“ต' },
+ { title: 'no one under eighteen', character: '๐Ÿ”ž' },
+ { title: 'radioactive', character: 'โ˜ข๏ธ' },
+ { title: 'biohazard', character: 'โ˜ฃ๏ธ' },
+ { title: 'up arrow', character: 'โฌ†๏ธ' },
+ { title: 'up-right arrow', character: 'โ†—๏ธ' },
+ { title: 'right arrow', character: 'โžก๏ธ' },
+ { title: 'down-right arrow', character: 'โ†˜๏ธ' },
+ { title: 'down arrow', character: 'โฌ‡๏ธ' },
+ { title: 'down-left arrow', character: 'โ†™๏ธ' },
+ { title: 'left arrow', character: 'โฌ…๏ธ' },
+ { title: 'up-left arrow', character: 'โ†–๏ธ' },
+ { title: 'up-down arrow', character: 'โ†•๏ธ' },
+ { title: 'left-right arrow', character: 'โ†”๏ธ' },
+ { title: 'right arrow curving left', character: 'โ†ฉ๏ธ' },
+ { title: 'left arrow curving right', character: 'โ†ช๏ธ' },
+ { title: 'right arrow curving up', character: 'โคด๏ธ' },
+ { title: 'right arrow curving down', character: 'โคต๏ธ' },
+ { title: 'clockwise vertical arrows', character: '๐Ÿ”ƒ' },
+ { title: 'counterclockwise arrows button', character: '๐Ÿ”„' },
+ { title: 'shuffle tracks button', character: '๐Ÿ”€' },
+ { title: 'repeat button', character: '๐Ÿ”' },
+ { title: 'repeat single button', character: '๐Ÿ”‚' },
+ { title: 'play button', character: 'โ–ถ๏ธ' },
+ { title: 'fast-forward button', character: 'โฉ' },
+ { title: 'next track button', character: 'โญ๏ธ' },
+ { title: 'play or pause button', character: 'โฏ๏ธ' },
+ { title: 'reverse button', character: 'โ—€๏ธ' },
+ { title: 'fast reverse button', character: 'โช' },
+ { title: 'last track button', character: 'โฎ๏ธ' },
+ { title: 'upwards button', character: '๐Ÿ”ผ' },
+ { title: 'fast up button', character: 'โซ' },
+ { title: 'downwards button', character: '๐Ÿ”ฝ' },
+ { title: 'fast down button', character: 'โฌ' },
+ { title: 'pause button', character: 'โธ๏ธ' },
+ { title: 'stop button', character: 'โน๏ธ' },
+ { title: 'record button', character: 'โบ๏ธ' },
+ { title: 'eject button', character: 'โ๏ธ' },
+ { title: 'cinema', character: '๐ŸŽฆ' },
+ { title: 'dim button', character: '๐Ÿ”…' },
+ { title: 'bright button', character: '๐Ÿ”†' },
+ { title: 'antenna bars', character: '๐Ÿ“ถ' },
+ { title: 'vibration mode', character: '๐Ÿ“ณ' },
+ { title: 'mobile phone off', character: '๐Ÿ“ด' },
+ { title: 'female sign', character: 'โ™€๏ธ' },
+ { title: 'male sign', character: 'โ™‚๏ธ' },
+ { title: 'transgender symbol', character: 'โšง๏ธ' },
+ { title: 'multiply', character: 'โœ–๏ธ' },
+ { title: 'plus', character: 'โž•๏ธ' },
+ { title: 'minus', character: 'โž–๏ธ' },
+ { title: 'divide', character: 'โž—๏ธ' },
+ { title: 'infinity', character: 'โ™พ๏ธ' },
+ { title: 'double exclamation mark', character: 'โ€ผ๏ธ' },
+ { title: 'exclamation question mark', character: 'โ‰๏ธ' },
+ { title: 'red question mark', character: 'โ“๏ธ' },
+ { title: 'red exclamation mark', character: 'โ—๏ธ' },
+ { title: 'white question mark', character: 'โ”๏ธ' },
+ { title: 'white exclamation mark', character: 'โ•๏ธ' },
+ { title: 'wavy dash', character: 'ใ€ฐ๏ธ' },
+ { title: 'currency exchange', character: '๐Ÿ’ฑ' },
+ { title: 'heavy dollar sign', character: '๐Ÿ’ฒ' },
+ { title: 'medical symbol', character: 'โš•๏ธ' },
+ { title: 'recycling symbol', character: 'โ™ป๏ธ' },
+ { title: 'fleur-de-lis', character: 'โšœ๏ธ' },
+ { title: 'trident emblem', character: '๐Ÿ”ฑ' },
+ { title: 'name badge', character: '๐Ÿ“›' },
+ { title: 'Japanese symbol for beginner', character: '๐Ÿ”ฐ' },
+ { title: 'hollow red circle', character: 'โญ•๏ธ' },
+ { title: 'check mark button', character: 'โœ…๏ธ' },
+ { title: 'check box with check', character: 'โ˜‘๏ธ' },
+ { title: 'check mark', character: 'โœ”๏ธ' },
+ { title: 'cross mark', character: 'โŒ๏ธ' },
+ { title: 'cross mark button', character: 'โŽ๏ธ' },
+ { title: 'curly loop', character: 'โžฐ๏ธ' },
+ { title: 'double curly loop', character: 'โžฟ๏ธ' },
+ { title: 'part alternation mark', character: 'ใ€ฝ๏ธ' },
+ { title: 'eight-spoked asterisk', character: 'โœณ๏ธ' },
+ { title: 'eight-pointed star', character: 'โœด๏ธ' },
+ { title: 'sparkle', character: 'โ‡๏ธ' },
+ { title: 'copyright', character: 'ยฉ๏ธ' },
+ { title: 'registered', character: 'ยฎ๏ธ' },
+ { title: 'trade mark', character: 'โ„ข๏ธ' },
+ { title: 'keycap: #', character: '#๏ธโƒฃ' },
+ { title: 'keycap: *', character: '*๏ธโƒฃ' },
+ { title: 'keycap: 0', character: '0๏ธโƒฃ' },
+ { title: 'keycap: 1', character: '1๏ธโƒฃ' },
+ { title: 'keycap: 2', character: '2๏ธโƒฃ' },
+ { title: 'keycap: 3', character: '3๏ธโƒฃ' },
+ { title: 'keycap: 4', character: '4๏ธโƒฃ' },
+ { title: 'keycap: 5', character: '5๏ธโƒฃ' },
+ { title: 'keycap: 6', character: '6๏ธโƒฃ' },
+ { title: 'keycap: 7', character: '7๏ธโƒฃ' },
+ { title: 'keycap: 8', character: '8๏ธโƒฃ' },
+ { title: 'keycap: 9', character: '9๏ธโƒฃ' },
+ { title: 'keycap: 10', character: '๐Ÿ”Ÿ' },
+ { title: 'input latin uppercase', character: '๐Ÿ” ' },
+ { title: 'input latin lowercase', character: '๐Ÿ”ก' },
+ { title: 'input numbers', character: '๐Ÿ”ข' },
+ { title: 'input symbols', character: '๐Ÿ”ฃ' },
+ { title: 'input latin letters', character: '๐Ÿ”ค' },
+ { title: 'A button (blood type)', character: '๐Ÿ…ฐ๏ธ' },
+ { title: 'AB button (blood type)', character: '๐Ÿ†Ž๏ธ' },
+ { title: 'B button (blood type)', character: '๐Ÿ…ฑ๏ธ' },
+ { title: 'O button (blood type)', character: '๐Ÿ…พ๏ธ' },
+ { title: 'CL button', character: '๐Ÿ†‘๏ธ' },
+ { title: 'COOL button', character: '๐Ÿ†’๏ธ' },
+ { title: 'FREE button', character: '๐Ÿ†“๏ธ' },
+ { title: 'information', character: 'โ„น๏ธ' },
+ { title: 'ID button', character: '๐Ÿ†”๏ธ' },
+ { title: 'circled M', character: 'โ“‚๏ธ' },
+ { title: 'NEW button', character: '๐Ÿ†•๏ธ' },
+ { title: 'NG button', character: '๐Ÿ†–๏ธ' },
+ { title: 'OK button', character: '๐Ÿ†—๏ธ' },
+ { title: 'P button', character: '๐Ÿ…ฟ๏ธ' },
+ { title: 'SOS button', character: '๐Ÿ†˜๏ธ' },
+ { title: 'UP! button', character: '๐Ÿ†™๏ธ' },
+ { title: 'VS button', character: '๐Ÿ†š๏ธ' },
+ { title: 'red circle', character: '๐Ÿ”ด' },
+ { title: 'orange circle', character: '๐ŸŸ ' },
+ { title: 'yellow circle', character: '๐ŸŸก' },
+ { title: 'green circle', character: '๐ŸŸข' },
+ { title: 'blue circle', character: '๐Ÿ”ต' },
+ { title: 'purple circle', character: '๐ŸŸฃ' },
+ { title: 'brown circle', character: '๐ŸŸค' },
+ { title: 'white circle', character: 'โšช๏ธ' },
+ { title: 'black circle', character: 'โšซ๏ธ' },
+ { title: 'red square', character: '๐ŸŸฅ' },
+ { title: 'orange square', character: '๐ŸŸง' },
+ { title: 'yellow square', character: '๐ŸŸจ' },
+ { title: 'green square', character: '๐ŸŸฉ' },
+ { title: 'blue square', character: '๐ŸŸฆ' },
+ { title: 'purple square', character: '๐ŸŸช' },
+ { title: 'brown square', character: '๐ŸŸซ' },
+ { title: 'black large square', character: 'โฌ›๏ธ' },
+ { title: 'white large square', character: 'โฌœ๏ธ' },
+ { title: 'black medium square', character: 'โ—ผ๏ธ' },
+ { title: 'white medium square', character: 'โ—ป๏ธ' },
+ { title: 'black medium-small square', character: 'โ—พ๏ธ' },
+ { title: 'white medium-small square', character: 'โ—ฝ๏ธ' },
+ { title: 'black small square', character: 'โ–ช๏ธ' },
+ { title: 'white small square', character: 'โ–ซ๏ธ' },
+ { title: 'large orange diamond', character: '๐Ÿ”ถ๏ธ' },
+ { title: 'large blue diamond', character: '๐Ÿ”ท๏ธ' },
+ { title: 'small orange diamond', character: '๐Ÿ”ธ๏ธ' },
+ { title: 'small blue diamond', character: '๐Ÿ”น๏ธ' },
+ { title: 'red triangle pointed up', character: '๐Ÿ”บ๏ธ' },
+ { title: 'red triangle pointed down', character: '๐Ÿ”ป' },
+ { title: 'diamond with a dot', character: '๐Ÿ’ ' },
+ { title: 'radio button', character: '๐Ÿ”˜' },
+ { title: 'white square button', character: '๐Ÿ”ฒ' },
+ { title: 'black square button', character: '๐Ÿ”ณ' },
+
+ ] );
+}
diff --git a/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiTraffic.js b/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiTraffic.js
new file mode 100644
index 0000000..e036ea6
--- /dev/null
+++ b/resources/assets/javascripts/cke/special_characters/SpecialCharactersEmojiTraffic.js
@@ -0,0 +1,214 @@
+export default function SpecialCharactersEmojiTraffic( editor ) {
+ editor.plugins.get( 'SpecialCharacters' ).addItems( 'Emoji Traffic', [
+ { title: 'globe showing Europe-Africa', character: '๐ŸŒ' },
+ { title: 'globe showing Americas', character: '๐ŸŒŽ' },
+ { title: 'globe showing Asia-Australia', character: '๐ŸŒ' },
+ { title: 'globe with meridians', character: '๐ŸŒ' },
+ { title: 'world map', character: '๐Ÿ—บ' },
+ { title: 'compass', character: '๐Ÿงญ' },
+ { title: 'snow-capped mountain', character: '๐Ÿ”' },
+ { title: 'mountain', character: 'โ›ฐ' },
+ { title: 'volcano', character: '๐ŸŒ‹' },
+ { title: 'mount fuji', character: '๐Ÿ—ป' },
+ { title: 'camping', character: '๐Ÿ•' },
+ { title: 'beach with umbrella', character: '๐Ÿ–' },
+ { title: 'desert', character: '๐Ÿœ' },
+ { title: 'desert island', character: '๐Ÿ' },
+ { title: 'national park', character: '๐Ÿž' },
+ { title: 'stadium', character: '๐ŸŸ' },
+ { title: 'classical building', character: '๐Ÿ›' },
+ { title: 'building construction', character: '๐Ÿ—' },
+ { title: 'brick', character: '๐Ÿงฑ' },
+ { title: 'rock', character: '๐Ÿชจ' },
+ { title: 'wood', character: '๐Ÿชต' },
+ { title: 'hut', character: '๐Ÿ›–' },
+ { title: 'houses', character: '๐Ÿ˜' },
+ { title: 'derelict house', character: '๐Ÿš' },
+ { title: 'house', character: '๐Ÿ ' },
+ { title: 'house with garden', character: '๐Ÿก' },
+ { title: 'office building', character: '๐Ÿข' },
+ { title: 'post office', character: '๐Ÿค' },
+ { title: 'hospital', character: '๐Ÿฅ' },
+ { title: 'bank', character: '๐Ÿฆ' },
+ { title: 'hotel', character: '๐Ÿจ' },
+ { title: 'convenience store', character: '๐Ÿช' },
+ { title: 'school', character: '๐Ÿซ' },
+ { title: 'department store', character: '๐Ÿฌ' },
+ { title: 'factory', character: '๐Ÿญ' },
+ { title: 'Japanese castle', character: '๐Ÿฏ' },
+ { title: 'castle', character: '๐Ÿฐ' },
+ { title: 'wedding', character: '๐Ÿ’’' },
+ { title: 'Tokyo tower', character: '๐Ÿ—ผ' },
+ { title: 'Statue of Liberty', character: '๐Ÿ—ฝ' },
+ { title: 'church', character: 'โ›ช' },
+ { title: 'mosque', character: '๐Ÿ•Œ' },
+ { title: 'hindu temple', character: '๐Ÿ›•' },
+ { title: 'synagogue', character: '๐Ÿ•' },
+ { title: 'shinto shrine', character: 'โ›ฉ' },
+ { title: 'kaaba', character: '๐Ÿ•‹' },
+ { title: 'fountain', character: 'โ›ฒ' },
+ { title: 'tent', character: 'โ›บ' },
+ { title: 'foggy', character: '๐ŸŒ' },
+ { title: 'night with stars', character: '๐ŸŒƒ' },
+ { title: 'cityscape', character: '๐Ÿ™' },
+ { title: 'sunrise over mountains', character: '๐ŸŒ„' },
+ { title: 'sunrise', character: '๐ŸŒ…' },
+ { title: 'cityscape at dusk', character: '๐ŸŒ†' },
+ { title: 'sunset', character: '๐ŸŒ‡' },
+ { title: 'bridge at night', character: '๐ŸŒ‰' },
+ { title: 'hot springs', character: 'โ™จ๏ธ' },
+ { title: 'carousel horse', character: '๐ŸŽ ' },
+ { title: 'ferris wheel', character: '๐ŸŽก' },
+ { title: 'roller coaster', character: '๐ŸŽข' },
+ { title: 'barber pole', character: '๐Ÿ’ˆ' },
+ { title: 'circus tent', character: '๐ŸŽช' },
+ { title: 'locomotive', character: '๐Ÿš‚' },
+ { title: 'railway car', character: '๐Ÿšƒ' },
+ { title: 'high-speed train', character: '๐Ÿš„' },
+ { title: 'bullet train', character: '๐Ÿš…' },
+ { title: 'train', character: '๐Ÿš†' },
+ { title: 'metro', character: '๐Ÿš‡' },
+ { title: 'light rail', character: '๐Ÿšˆ' },
+ { title: 'station', character: '๐Ÿš‰' },
+ { title: 'tram', character: '๐ŸšŠ' },
+ { title: 'monorail', character: '๐Ÿš' },
+ { title: 'mountain railway', character: '๐Ÿšž' },
+ { title: 'tram car', character: '๐Ÿš‹' },
+ { title: 'bus', character: '๐ŸšŒ' },
+ { title: 'oncoming bus', character: '๐Ÿš' },
+ { title: 'trolleybus', character: '๐ŸšŽ' },
+ { title: 'minibus', character: '๐Ÿš' },
+ { title: 'ambulance', character: '๐Ÿš‘' },
+ { title: 'fire engine', character: '๐Ÿš’' },
+ { title: 'police car', character: '๐Ÿš“' },
+ { title: 'oncoming police car', character: '๐Ÿš”' },
+ { title: 'taxi', character: '๐Ÿš•' },
+ { title: 'oncoming taxi', character: '๐Ÿš–' },
+ { title: 'automobile', character: '๐Ÿš—' },
+ { title: 'oncoming automobile', character: '๐Ÿš˜' },
+ { title: 'sport utility vehicle', character: '๐Ÿš™' },
+ { title: 'pickup truck', character: '๐Ÿ›ป' },
+ { title: 'delivery truck', character: '๐Ÿšš' },
+ { title: 'articulated lorry', character: '๐Ÿš›' },
+ { title: 'tractor', character: '๐Ÿšœ' },
+ { title: 'racing car', character: '๐ŸŽ' },
+ { title: 'motorcycle', character: '๐Ÿ' },
+ { title: 'motor scooter', character: '๐Ÿ›ต' },
+ { title: 'manual wheelchair', character: '๐Ÿฆฝ' },
+ { title: 'motorized wheelchair', character: '๐Ÿฆผ' },
+ { title: 'auto rickshaw', character: '๐Ÿ›บ' },
+ { title: 'bicycle', character: '๐Ÿšฒ' },
+ { title: 'kick scooter', character: '๐Ÿ›ด' },
+ { title: 'skateboard', character: '๐Ÿ›น' },
+ { title: 'roller skate', character: '๐Ÿ›ผ' },
+ { title: 'bus stop', character: '๐Ÿš' },
+ { title: 'motorway', character: '๐Ÿ›ฃ' },
+ { title: 'railway track', character: '๐Ÿ›ค' },
+ { title: 'oil drum', character: '๐Ÿ›ข' },
+ { title: 'fuel pump', character: 'โ›ฝ' },
+ { title: 'police car light', character: '๐Ÿšจ' },
+ { title: 'horizontal traffic light', character: '๐Ÿšฅ' },
+ { title: 'vertical traffic light', character: '๐Ÿšฆ' },
+ { title: 'stop sign', character: '๐Ÿ›‘' },
+ { title: 'construction', character: '๐Ÿšง' },
+ { title: 'anchor', character: 'โš“๏ธ' },
+ { title: 'sailboat', character: 'โ›ต' },
+ { title: 'canoe', character: '๐Ÿ›ถ' },
+ { title: 'speedboat', character: '๐Ÿšค' },
+ { title: 'passenger ship', character: '๐Ÿ›ณ' },
+ { title: 'ferry', character: 'โ›ด' },
+ { title: 'motor boat', character: '๐Ÿ›ฅ' },
+ { title: 'ship', character: '๐Ÿšข' },
+ { title: 'airplane', character: 'โœˆ๏ธ' },
+ { title: 'small airplane', character: '๐Ÿ›ฉ' },
+ { title: 'airplane departure', character: '๐Ÿ›ซ' },
+ { title: 'airplane arrival', character: '๐Ÿ›ฌ' },
+ { title: 'parachute', character: '๐Ÿช‚' },
+ { title: 'seat', character: '๐Ÿ’บ' },
+ { title: 'helicopter', character: '๐Ÿš' },
+ { title: 'suspension railway', character: '๐ŸšŸ' },
+ { title: 'mountain cableway', character: '๐Ÿš ' },
+ { title: 'aerial tramway', character: '๐Ÿšก' },
+ { title: 'satellite', character: '๐Ÿ›ฐ' },
+ { title: 'rocket', character: '๐Ÿš€' },
+ { title: 'flying saucer', character: '๐Ÿ›ธ' },
+ { title: 'bellhop bell', character: '๐Ÿ›Ž' },
+ { title: 'luggage', character: '๐Ÿงณ' },
+ { title: 'hourglass done', character: 'โŒ›' },
+ { title: 'hourglass not done', character: 'โณ' },
+ { title: 'watch', character: 'โŒš' },
+ { title: 'alarm clock', character: 'โฐ' },
+ { title: 'stopwatch', character: 'โฑ' },
+ { title: 'timer clock', character: 'โฒ' },
+ { title: 'mantelpiece clock', character: '๐Ÿ•ฐ' },
+ { title: 'twelve oโ€™clock', character: '๐Ÿ•›' },
+ { title: 'twelve-thirty', character: '๐Ÿ•ง' },
+ { title: 'one oโ€™clock', character: '๐Ÿ•' },
+ { title: 'one-thirty', character: '๐Ÿ•œ' },
+ { title: 'two oโ€™clock', character: '๐Ÿ•‘' },
+ { title: 'two-thirty', character: '๐Ÿ•' },
+ { title: 'three oโ€™clock', character: '๐Ÿ•’' },
+ { title: 'three-thirty', character: '๐Ÿ•ž' },
+ { title: 'four oโ€™clock', character: '๐Ÿ•“' },
+ { title: 'four-thirty', character: '๐Ÿ•Ÿ' },
+ { title: 'five oโ€™clock', character: '๐Ÿ•”' },
+ { title: 'five-thirty', character: '๐Ÿ• ' },
+ { title: 'six oโ€™clock', character: '๐Ÿ••' },
+ { title: 'six-thirty', character: '๐Ÿ•ก' },
+ { title: 'seven oโ€™clock', character: '๐Ÿ•–' },
+ { title: 'seven-thirty', character: '๐Ÿ•ข' },
+ { title: 'eight oโ€™clock', character: '๐Ÿ•—' },
+ { title: 'eight-thirty', character: '๐Ÿ•ฃ' },
+ { title: 'nine oโ€™clock', character: '๐Ÿ•˜' },
+ { title: 'nine-thirty', character: '๐Ÿ•ค' },
+ { title: 'ten oโ€™clock', character: '๐Ÿ•™' },
+ { title: 'ten-thirty', character: '๐Ÿ•ฅ' },
+ { title: 'eleven oโ€™clock', character: '๐Ÿ•š' },
+ { title: 'eleven-thirty', character: '๐Ÿ•ฆ' },
+ { title: 'new moon', character: '๐ŸŒ‘' },
+ { title: 'waxing crescent moon', character: '๐ŸŒ’' },
+ { title: 'first quarter moon', character: '๐ŸŒ“' },
+ { title: 'waxing gibbous moon', character: '๐ŸŒ”' },
+ { title: 'full moon', character: '๐ŸŒ•' },
+ { title: 'waning gibbous moon', character: '๐ŸŒ–' },
+ { title: 'last quarter moon', character: '๐ŸŒ—' },
+ { title: 'waning crescent moon', character: '๐ŸŒ˜' },
+ { title: 'crescent moon', character: '๐ŸŒ™' },
+ { title: 'new moon face', character: '๐ŸŒš' },
+ { title: 'first quarter moon face', character: '๐ŸŒ›' },
+ { title: 'last quarter moon face', character: '๐ŸŒœ' },
+ { title: 'thermometer', character: '๐ŸŒก' },
+ { title: 'sun', character: 'โ˜€๏ธ' },
+ { title: 'full moon face', character: '๐ŸŒ' },
+ { title: 'sun with face', character: '๐ŸŒž' },
+ { title: 'ringed planet', character: '๐Ÿช' },
+ { title: 'star', character: 'โญ' },
+ { title: 'glowing star', character: '๐ŸŒŸ' },
+ { title: 'shooting star', character: '๐ŸŒ ' },
+ { title: 'milky way', character: '๐ŸŒŒ' },
+ { title: 'cloud with lightning and rain', character: 'โ›ˆ' },
+ { title: 'sun behind small cloud', character: '๐ŸŒค' },
+ { title: 'sun behind large cloud', character: '๐ŸŒฅ' },
+ { title: 'sun behind rain cloud', character: '๐ŸŒฆ' },
+ { title: 'cloud with rain', character: '๐ŸŒง' },
+ { title: 'cloud with snow', character: '๐ŸŒจ' },
+ { title: 'cloud with lightning', character: '๐ŸŒฉ' },
+ { title: 'tornado', character: '๐ŸŒช' },
+ { title: 'fog', character: '๐ŸŒซ' },
+ { title: 'wind face', character: '๐ŸŒฌ' },
+ { title: 'cyclone', character: '๐ŸŒ€' },
+ { title: 'rainbow', character: '๐ŸŒˆ' },
+ { title: 'closed umbrella', character: '๐ŸŒ‚' },
+ { title: 'umbrella', character: 'โ˜‚๏ธ' },
+ { title: 'umbrella with rain drops', character: 'โ˜”' },
+ { title: 'umbrella on ground', character: 'โ›ฑ' },
+ { title: 'high voltage', character: 'โšก๏ธ' },
+ { title: 'snowflake', character: 'โ„๏ธ' },
+ { title: 'snowman', character: 'โ˜ƒ๏ธ' },
+ { title: 'snowman without snow', character: 'โ›„' },
+ { title: 'comet', character: 'โ˜„๏ธ' },
+ { title: 'fire', character: '๐Ÿ”ฅ' },
+ { title: 'droplet', character: '๐Ÿ’ง' },
+ { title: 'water wave', character: '๐ŸŒŠ' },
+ ] );
+}
diff --git a/resources/assets/javascripts/cke/special_characters/SpecialCharactersGreek.js b/resources/assets/javascripts/cke/special_characters/SpecialCharactersGreek.js
new file mode 100644
index 0000000..7720e42
--- /dev/null
+++ b/resources/assets/javascripts/cke/special_characters/SpecialCharactersGreek.js
@@ -0,0 +1,52 @@
+export default function SpecialCharactersGreek( editor ) {
+ editor.plugins.get( 'SpecialCharacters' ).addItems( 'Greek', [
+ { title: 'capital alpha', character: 'ฮ‘' },
+ { title: 'small beta', character: 'ฮฑ' },
+ { title: 'capital beta', character: 'ฮ’' },
+ { title: 'small alpha', character: 'ฮฒ' },
+ { title: 'capital gamma', character: 'ฮ“' },
+ { title: 'small gamma', character: 'ฮณ' },
+ { title: 'capital delta', character: 'ฮ”' },
+ { title: 'small delta', character: 'ฮด' },
+ { title: 'capital epsilon', character: 'ฮ•' },
+ { title: 'small epsilon', character: 'ฮต' },
+ { title: 'capital zeta', character: 'ฮ–' },
+ { title: 'small zeta', character: 'ฮถ' },
+ { title: 'capital eta', character: 'ฮ—' },
+ { title: 'small eta', character: 'ฮท' },
+ { title: 'capital theta', character: 'ฮ˜' },
+ { title: 'small theta', character: 'ฮธ' },
+ { title: 'capital iota', character: 'ฮ™' },
+ { title: 'small iota', character: 'ฮน' },
+ { title: 'capital kappa', character: 'ฮš' },
+ { title: 'small kappa', character: 'ฮบ' },
+ { title: 'capital lambda', character: 'ฮ›' },
+ { title: 'small lambda', character: 'ฮป' },
+ { title: 'capital mu', character: 'ฮœ' },
+ { title: 'small mu', character: 'ฮผ' },
+ { title: 'capital nu', character: 'ฮ' },
+ { title: 'small nu', character: 'ฮฝ' },
+ { title: 'capital xi', character: 'ฮž' },
+ { title: 'small xi', character: 'ฮพ' },
+ { title: 'capital omicron', character: 'ฮŸ' },
+ { title: 'small omicron', character: 'ฮฟ' },
+ { title: 'capital pi', character: 'ฮ ' },
+ { title: 'small pi', character: 'ฯ€' },
+ { title: 'capital rho', character: 'ฮก' },
+ { title: 'small rho', character: 'ฯ' },
+ { title: 'capital sigma', character: 'ฮฃ' },
+ { title: 'small sigma', character: 'ฯƒ' },
+ { title: 'capital tau', character: 'ฮค' },
+ { title: 'small tau', character: 'ฯ„' },
+ { title: 'capital upsilon', character: 'ฮฅ' },
+ { title: 'small upsilon', character: 'ฯ…' },
+ { title: 'capital phi', character: 'ฮฆ' },
+ { title: 'small phi', character: 'ฯ†' },
+ { title: 'capital chi', character: 'ฮง' },
+ { title: 'small chi', character: 'ฯ‡' },
+ { title: 'capital psi', character: 'ฮจ' },
+ { title: 'small psi', character: 'ฯˆ' },
+ { title: 'capital omega', character: 'ฮฉ' },
+ { title: 'small omega', character: 'ฯ‰' },
+ ] );
+} \ No newline at end of file
diff --git a/resources/assets/javascripts/cke/studip-a11y-dialog/a11y-dialog.js b/resources/assets/javascripts/cke/studip-a11y-dialog/a11y-dialog.js
new file mode 100644
index 0000000..133a6ba
--- /dev/null
+++ b/resources/assets/javascripts/cke/studip-a11y-dialog/a11y-dialog.js
@@ -0,0 +1,24 @@
+import { Plugin } from 'ckeditor5/src/core';
+import { add } from '@ckeditor/ckeditor5-utils/src/translation-service';
+import { $gettext } from '../../lib/gettext.js';
+import A11YDialogEditing from './editing.js';
+import A11YDialogUI from './ui.js';
+
+export function updateVoiceLabel() {
+ add('de', {
+ 'Rich Text Editor': $gettext('Rich Text Editor (Um Bedienhinweise zu erhalten, drรผcken Sie ALT+0 im Eingabefeld.)'),
+ });
+}
+
+export default class A11YDialog extends Plugin {
+ static get requires() {
+ return [A11YDialogUI, A11YDialogEditing];
+ }
+
+ /**
+ * @inheritDoc
+ */
+ static get pluginName() {
+ return 'A11YDialog';
+ }
+}
diff --git a/resources/assets/javascripts/cke/studip-a11y-dialog/command.js b/resources/assets/javascripts/cke/studip-a11y-dialog/command.js
new file mode 100644
index 0000000..71c6fe0
--- /dev/null
+++ b/resources/assets/javascripts/cke/studip-a11y-dialog/command.js
@@ -0,0 +1,19 @@
+import { Command } from 'ckeditor5/src/core';
+import Dialog from '../../lib/dialog.js';
+
+export default class A11YDialogCommand extends Command {
+ refresh() {
+ this.isEnabled = true;
+ }
+
+ execute() {
+ const activeElement = document.activeElement;
+ const id = 'cke-a11y-help';
+ Dialog.fromURL(STUDIP.URLHelper.getURL('dispatch.php/wysiwyg/a11yhelp'), { id });
+ $(document).one('dialog-close', function (event, { dialog, options }) {
+ if (options.id === id) {
+ activeElement?.focus();
+ }
+ });
+ }
+}
diff --git a/resources/assets/javascripts/cke/studip-a11y-dialog/editing.js b/resources/assets/javascripts/cke/studip-a11y-dialog/editing.js
new file mode 100644
index 0000000..95c1559
--- /dev/null
+++ b/resources/assets/javascripts/cke/studip-a11y-dialog/editing.js
@@ -0,0 +1,16 @@
+import { Plugin } from 'ckeditor5/src/core';
+import A11YDialogCommand from './command.js';
+
+export default class A11YDialogEditing extends Plugin {
+ static get pluginName() {
+ return 'A11YDialogEditing';
+ }
+
+ init() {
+ const editor = this.editor;
+
+ editor.commands.add('a11ydialog', new A11YDialogCommand(editor));
+
+ editor.keystrokes.set('ALT+0', 'a11ydialog');
+ }
+}
diff --git a/resources/assets/javascripts/cke/studip-a11y-dialog/ui.js b/resources/assets/javascripts/cke/studip-a11y-dialog/ui.js
new file mode 100644
index 0000000..9d2980b
--- /dev/null
+++ b/resources/assets/javascripts/cke/studip-a11y-dialog/ui.js
@@ -0,0 +1,32 @@
+import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
+import { Plugin } from 'ckeditor5/src/core';
+import { $gettext } from '../../lib/gettext.js';
+
+const a11yIcon =
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 54"><path d="M32.5,43h-11a1.5,1.5,0,0,0,0,3h11a1.5,1.5,0,0,0,0-3Z"/><path d="M31.5,48h-9a1.5,1.5,0,0,0,0,3h9a1.5,1.5,0,0,0,0-3Z"/><path d="M27,3a18.54,18.54,0,0,0-2,.11,17,17,0,0,0-6.95,31.37A2,2,0,0,1,19,36.13v3.34A1.5,1.5,0,0,0,20.5,41h13a1.5,1.5,0,0,0,1.5-1.5V36.12a2,2,0,0,1,.9-1.67A17,17,0,0,0,27,3Zm7.33,28.92A5,5,0,0,0,32,36.12V38H22V36.13a5,5,0,0,0-2.33-4.24,14,14,0,0,1,5.7-25.83A14.84,14.84,0,0,1,27,6a14,14,0,0,1,7.33,25.92Z"/><path d="M32.39,9.05A12.51,12.51,0,0,0,27.24,8a12.66,12.66,0,0,0-10.37,5.4,1.73,1.73,0,0,0,.42,2.41,1.69,1.69,0,0,0,1,.32,1.73,1.73,0,0,0,1.42-.74,9.21,9.21,0,0,1,7.54-3.93,9.08,9.08,0,0,1,3.74.8,1.73,1.73,0,1,0,1.41-3.16Z"/><path d="M17,16.31A1.73,1.73,0,0,0,15,17.58a12.38,12.38,0,0,0-.37,3,12.68,12.68,0,0,0,.28,2.67,1.74,1.74,0,0,0,1.69,1.36,1.55,1.55,0,0,0,.37,0,1.74,1.74,0,0,0,1.33-2.06A8.92,8.92,0,0,1,18,20.61a9.08,9.08,0,0,1,.27-2.2A1.74,1.74,0,0,0,17,16.31Z"/></svg>';
+
+export default class A11YDialogUI extends Plugin {
+ static get pluginName() {
+ return 'A11YDialogUI';
+ }
+
+ init() {
+ const editor = this.editor;
+ editor.ui.componentFactory.add('open-a11y-dialog', (locale) => {
+ const view = new ButtonView(locale);
+
+ view.set({
+ label: $gettext('Informationen zur Bedienung'),
+ icon: a11yIcon,
+ keystroke: 'ALT+0',
+ tooltip: true,
+ });
+
+ view.on('execute', () => {
+ editor.execute('a11ydialog');
+ });
+
+ return view;
+ });
+ }
+}
diff --git a/resources/assets/javascripts/cke/studip-quote/StudipBlockQuote.js b/resources/assets/javascripts/cke/studip-quote/StudipBlockQuote.js
new file mode 100644
index 0000000..f5ac256
--- /dev/null
+++ b/resources/assets/javascripts/cke/studip-quote/StudipBlockQuote.js
@@ -0,0 +1,127 @@
+import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
+import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
+import { $gettext } from '../../lib/gettext.js';
+import { icons } from 'ckeditor5/src/core';
+
+const divideIcon =
+ '<svg version="1.1" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m9.3 2h2v16h-2zm-7.2987 8.423a6.5 6.5 0 0 1 6.056-6.408l0.038 0.67c-2.646 0.738-3.74 2.978-3.874 5.315h3.78c0.552 0 0.5 0.432 0.5 0.986v4.511c0 0.554-0.448 0.503-1 0.503h-5c-0.552 0-0.5-0.449-0.5-1.003zm10 0a6.5 6.5 0 0 1 6.056-6.408l0.038 0.67c-2.646 0.739-3.74 2.979-3.873 5.315h3.779c0.552 0 0.5 0.432 0.5 0.986v4.511c0 0.554-0.448 0.503-1 0.503h-5c-0.552 0-0.5-0.449-0.5-1.003z" stroke-width="1.1664"/></svg>';
+
+const removeIcon =
+ '<svg version="1.1" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m16.594 14.6 1.7829 1.7824a0.42044 0.42042 0 0 1-0.59459 0.59456l-1.7825-1.7828-1.7829 1.7828a0.42029 0.42027 0 0 1-0.59417-0.59456l1.7829-1.7824-1.7829-1.7828a0.42021 0.42018 0 0 1 0.59417-0.59414l1.7829 1.7828 1.7825-1.7828a0.42029 0.42027 0 1 1 0.59459 0.59414zm-13.594-4.1774a6.5 6.5 0 0 1 6.056-6.408l0.038 0.67c-2.646 0.738-3.74 2.978-3.874 5.315h3.78c0.552 0 0.5 0.432 0.5 0.986v4.511c0 0.554-0.448 0.503-1 0.503h-5c-0.552 0-0.5-0.449-0.5-1.003zm8 0c0.04006-3.3879 2.6758-6.1768 6.056-6.408l0.038 0.67c-2.646 0.739-3.74 2.979-3.873 5.315h3.779c0.552 0 0.49078 0.43208 0.5 0.986l0.0098 0.59148c-5.3063 0.37805-4.512-1.1664-4.5961 4.4172l-1.4137 0.005319c-0.552 0.002077-0.5-0.449-0.5-1.003z" stroke-width=".42019"/></svg>';
+
+export default class StudipBlockQuote extends Plugin {
+ init() {
+ const editor = this.editor;
+
+ editor.ui.componentFactory.add('insertBlockQuote', (locale) => {
+ const view = new ButtonView(locale);
+
+ view.set({
+ label: $gettext('Zitat einfรผgen'),
+ icon: icons.quote,
+ tooltip: true,
+ });
+
+ // Callback executed once the image is clicked.
+ view.on('execute', () => {
+ this.insertStudipQuote(editor);
+ });
+
+ return view;
+ });
+
+ editor.ui.componentFactory.add('splitBlockQuote', (locale) => {
+ const view = new ButtonView(locale);
+
+ view.set({
+ label: $gettext('Zitat teilen'),
+ icon: divideIcon,
+ keystroke: 'Ctrl+Shift+Enter',
+ tooltip: true,
+ withText: false,
+ });
+
+ // Callback executed once the image is clicked.
+ view.on('execute', () => {
+ this.splitStudipQuote(editor);
+ });
+
+ return view;
+ });
+
+ editor.ui.componentFactory.add('removeBlockQuote', (locale) => {
+ const view = new ButtonView(locale);
+
+ view.set({
+ label: $gettext('Zitat lรถschen'),
+ icon: removeIcon,
+ tooltip: true,
+ withText: false,
+ });
+
+ // Callback executed once the image is clicked.
+ view.on('execute', () => {
+ this.removeStudipQuote(editor);
+ });
+
+ return view;
+ });
+ }
+
+ insertStudipQuote(editor) {
+ // If quoting is changed update these functions:
+ // - StudipFormat::markupQuote
+ // lib/classes/StudipFormat.php
+ // - quotes_encode lib/visual.inc.php
+ // - STUDIP.Forum.citeEntry > quote
+ // public/plugins_packages/core/Forum/javascript/forum.js
+ // - StudipBlockQuote > insertStudipQuote
+ // resources/assets/javascripts/cke/studip-quote/StudipBlockQuote.js
+
+ var writtenBy = $gettext('%s hat geschrieben:');
+
+ const content =
+ '<blockquote><div class="author">' +
+ writtenBy.replace('%s', $gettext('"Name"')) +
+ '</div><p>&nbsp</p></blockquote><p>&nbsp;</p>';
+ const viewFragment = editor.data.processor.toView(content);
+ const modelFragment = editor.data.toModel(viewFragment);
+ editor.model.insertContent(modelFragment);
+ }
+
+ splitStudipQuote(editor) {
+ const position = editor.model.document.selection.getFirstPosition();
+ const quote = position.findAncestor('blockQuote');
+
+ if (quote !== null) {
+ editor.model.change((writer) => {
+ const limitElement = quote.parent;
+ const split = writer.split(position, limitElement);
+ writer.insertElement('paragraph', split.position);
+ });
+ }
+ }
+
+ removeStudipQuote(editor) {
+ const position = editor.model.document.selection.getFirstPosition();
+ const quote = position.findAncestor('blockQuote');
+
+ if (quote !== null) {
+ editor.model.change((writer) => {
+ // Remove the top "written by" bar
+ for (var child of quote.getChildren()) {
+ if (
+ child.is('element', 'htmlDivParagraph') &&
+ child.getAttribute('htmlAttributes').classes.includes('author')
+ ) {
+ writer.remove(child);
+ }
+ }
+ // Only remove the current quote - save all children
+ const range = writer.createRangeIn(quote);
+ writer.move(range, quote, 'after');
+ writer.remove(quote);
+ });
+ }
+ }
+}
diff --git a/resources/assets/javascripts/cke/wiki-link/editing.js b/resources/assets/javascripts/cke/wiki-link/editing.js
new file mode 100644
index 0000000..5322694
--- /dev/null
+++ b/resources/assets/javascripts/cke/wiki-link/editing.js
@@ -0,0 +1,16 @@
+import { Plugin } from 'ckeditor5/src/core';
+import InsertCommand from './insertcommand';
+
+export default class WikiLinkEditing extends Plugin {
+ static get pluginName() {
+ return 'WikiLinkEditing';
+ }
+
+ init() {
+ this._defineCommands();
+ }
+
+ _defineCommands() {
+ this.editor.commands.add('insertStudipWikiLink', new InsertCommand(this.editor));
+ }
+}
diff --git a/resources/assets/javascripts/cke/wiki-link/formview.js b/resources/assets/javascripts/cke/wiki-link/formview.js
new file mode 100644
index 0000000..68f4e0a
--- /dev/null
+++ b/resources/assets/javascripts/cke/wiki-link/formview.js
@@ -0,0 +1,185 @@
+import {
+ View,
+ ButtonView,
+ FormHeaderView,
+ LabeledFieldView,
+ FocusCycler,
+ createLabeledInputText,
+ submitHandler,
+ ViewCollection,
+ injectCssTransitionDisabler,
+ createDropdown,
+ addListToDropdown,
+} from 'ckeditor5/src/ui';
+import { FocusTracker, KeystrokeHandler, Collection, Rect, isVisible } from 'ckeditor5/src/utils';
+import { $gettext } from '../../lib/gettext.js';
+
+export default class WikiLinkFormView extends View {
+ constructor(locale) {
+ super(locale);
+
+ const t = locale.t;
+
+ this._keywordInputView = this._createInputField($gettext('Wikiseite'), $gettext('zum Beispiel "Wiki-Startseite"'));
+ this._labelInputView = this._createInputField($gettext('Linktext'), $gettext('optional'));
+ this._insertButtonView = this._createButton({
+ label: $gettext('Einfรผgen'),
+ withText: true,
+ });
+
+ this._keywordFieldsetView = this._createKeywordFieldset();
+ this._focusTracker = new FocusTracker();
+
+ this._keystrokes = new KeystrokeHandler();
+ this._focusables = new ViewCollection();
+
+ this._focusCycler = new FocusCycler({
+ focusables: this._focusables,
+ focusTracker: this._focusTracker,
+ keystrokeHandler: this._keystrokes,
+ actions: {
+ focusPrevious: 'shift + tab',
+ focusNext: 'tab',
+ },
+ });
+
+ this.setTemplate({
+ tag: 'form',
+ attributes: {
+ class: ['ck', 'ck-studip-wiki-link-form'],
+
+ tabindex: '-1',
+ },
+ children: [
+ new FormHeaderView(locale, {
+ label: $gettext('Link auf Wikiseite einfรผgen'),
+ }),
+ this._keywordFieldsetView,
+ ],
+ });
+
+ injectCssTransitionDisabler(this);
+ }
+
+ render() {
+ super.render();
+
+ submitHandler({ view: this });
+
+ this._initFocusCycling();
+ this._initKeystrokeHandling();
+ }
+
+ destroy() {
+ super.destroy();
+
+ this._focusTracker.destroy();
+ this._keystrokes.destroy();
+ }
+
+ focus() {
+ this._focusCycler.focusFirst();
+ }
+
+ reset() {
+ this._keywordInputView.fieldView.element.value = '';
+ this._keywordInputView.errorText = null;
+ this._labelInputView.fieldView.element.value = '';
+ }
+
+ get _keywordToInsert() {
+ return this._keywordInputView.fieldView.element.value;
+ }
+
+ get _labelToInsert() {
+ return this._labelInputView.fieldView.element.value;
+ }
+
+ _createKeywordFieldset() {
+ const locale = this.locale;
+ const fieldsetView = new View(locale);
+
+ this._insertButtonView.on('execute', this._onInsertButtonExecute.bind(this));
+
+ fieldsetView.setTemplate({
+ tag: 'fieldset',
+ attributes: {
+ class: ['ck'],
+ },
+ children: [this._keywordInputView, this._labelInputView, this._insertButtonView],
+ });
+
+ return fieldsetView;
+ }
+
+ _onInsertButtonExecute() {
+ if (!this._keywordToInsert) {
+ this._keywordInputView.errorText = $gettext('Das Feld fรผr die Wikiseite darf nicht leer sein.');
+
+ return;
+ }
+ this.fire('insert', {
+ keyword: this._keywordToInsert,
+ label: this._labelToInsert,
+ });
+ }
+
+ _initFocusCycling() {
+ const childViews = [this._keywordInputView, this._labelInputView, this._insertButtonView];
+
+ childViews.forEach((v) => {
+ this._focusables.add(v);
+ this._focusTracker.add(v.element);
+ });
+ }
+
+ _initKeystrokeHandling() {
+ const stopPropagation = (data) => data.stopPropagation();
+ const stopPropagationAndPreventDefault = (data) => {
+ data.stopPropagation();
+ data.preventDefault();
+ };
+
+ this._keystrokes.listenTo(this.element);
+ this._keystrokes.set('enter', (event) => {
+ const target = event.target;
+
+ if (
+ target === this._keywordInputView.fieldView.element ||
+ target === this._labelInputView.fieldView.element
+ ) {
+ this._insertButtonView.fire('execute');
+ stopPropagationAndPreventDefault(event);
+ }
+ });
+
+ this._keystrokes.set('arrowright', stopPropagation);
+ this._keystrokes.set('arrowleft', stopPropagation);
+ this._keystrokes.set('arrowup', stopPropagation);
+ this._keystrokes.set('arrowdown', stopPropagation);
+
+ this.listenTo(
+ this._keywordInputView.element,
+ 'selectstart',
+ (evt, domEvt) => {
+ domEvt.stopPropagation();
+ },
+ { priority: 'high' }
+ );
+ }
+
+ _createButton(options) {
+ const button = new ButtonView(this.locale);
+ button.set(options);
+
+ return button;
+ }
+
+ _createInputField(label, infoText = '') {
+ const labeledInput = new LabeledFieldView(this.locale, createLabeledInputText);
+ labeledInput.label = label;
+ labeledInput.infoText = infoText;
+
+ return labeledInput;
+ }
+}
diff --git a/resources/assets/javascripts/cke/wiki-link/insertcommand.js b/resources/assets/javascripts/cke/wiki-link/insertcommand.js
new file mode 100644
index 0000000..1bf36b8
--- /dev/null
+++ b/resources/assets/javascripts/cke/wiki-link/insertcommand.js
@@ -0,0 +1,18 @@
+import { Command } from 'ckeditor5/src/core';
+
+export default class InsertCommand extends Command {
+ refresh() {
+ const model = this.editor.model;
+ const selection = model.document.selection;
+ const allowedIn = model.schema.findAllowedParent(selection.getFirstPosition(), '$text');
+ this.isEnabled = allowedIn !== null;
+ }
+
+ execute({ keyword, label }) {
+ this.editor.model.change((writer) => {
+ this.editor.model.insertContent(
+ writer.createText(label !== '' ? `[[${keyword}|${label}]]` : `[[${keyword}]]`)
+ );
+ });
+ }
+}
diff --git a/resources/assets/javascripts/cke/wiki-link/ui.js b/resources/assets/javascripts/cke/wiki-link/ui.js
new file mode 100644
index 0000000..1765a93
--- /dev/null
+++ b/resources/assets/javascripts/cke/wiki-link/ui.js
@@ -0,0 +1,70 @@
+import { Plugin } from 'ckeditor5/src/core';
+import { createDropdown } from 'ckeditor5/src/ui';
+import WikiLinkFormView from './formview.js';
+import { $gettext } from '../../lib/gettext.js';
+
+const wikiIcon =
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 54"><path class="cls-1" d="M49.83,15a15.17,15.17,0,0,1-10.17,7.9,31.41,31.41,0,0,1,3.45,11.38C46.63,32.05,53.82,25.94,49.83,15ZM4.17,15c-4,10.94,3.2,17,6.72,19.28A31.41,31.41,0,0,1,14.34,22.9,15.17,15.17,0,0,1,4.17,15ZM27,16c-7.1,0-12.85,10.31-12.85,23h25.7C39.85,26.29,34.1,16,27,16Z"/></svg>';
+
+export default class WikiLinkUI extends Plugin {
+ static get pluginName() {
+ return 'WikiLinkUI';
+ }
+
+ constructor(editor) {
+ super(editor);
+ this.formView = null;
+ }
+
+ init() {
+ const editor = this.editor;
+ editor.ui.componentFactory.add('studip-wiki', (locale) => {
+ const dropdown = createDropdown(locale);
+ const formView = (this.formView = new WikiLinkFormView(editor.locale));
+
+ dropdown.bind('isEnabled').to(editor.commands.get('insertStudipWikiLink'));
+ dropdown.panelView.children.add(formView);
+
+ dropdown.on(
+ 'change:isOpen',
+ (event, name, isOpen) => {
+ if (isOpen) {
+ formView.disableCssTransitions();
+
+ formView.reset();
+ formView._keywordInputView.fieldView.select();
+ formView.focus();
+
+ formView.enableCssTransitions();
+ } else {
+ formView.reset();
+ formView.focus();
+ }
+ },
+ { priority: 'low' }
+ );
+
+ this._setupDropdownButton(dropdown);
+ this._setupFormView(formView);
+
+ this.on('close', () => (dropdown.isOpen = false));
+
+ return dropdown;
+ });
+ }
+
+ _setupDropdownButton(dropdown) {
+ const editor = this.editor;
+ const t = editor.locale.t;
+
+ dropdown.buttonView.set({
+ icon: wikiIcon,
+ label: $gettext('Link auf Wikiseite einfรผgen'),
+ tooltip: true,
+ });
+ }
+
+ _setupFormView(formView) {
+ formView.delegate('insert').to(this);
+ }
+}
diff --git a/resources/assets/javascripts/cke/wiki-link/wiki-link.js b/resources/assets/javascripts/cke/wiki-link/wiki-link.js
new file mode 100644
index 0000000..4809977
--- /dev/null
+++ b/resources/assets/javascripts/cke/wiki-link/wiki-link.js
@@ -0,0 +1,28 @@
+import { Plugin } from 'ckeditor5/src/core';
+import WikiLinkUI from './ui.js';
+import WikiLinkEditing from './editing.js';
+
+export default class WikiLink extends Plugin {
+ static get requires() {
+ return [WikiLinkEditing, WikiLinkUI];
+ }
+
+ /**
+ * @inheritDoc
+ */
+ static get pluginName() {
+ return 'WikiLink';
+ }
+
+ /**
+ * @inheritDoc
+ */
+ init() {
+ const ui = this.editor.plugins.get('WikiLinkUI');
+
+ ui.on('insert', (event, data) => {
+ this.editor.execute('insertStudipWikiLink', data);
+ ui.fire('close');
+ });
+ }
+}