Switch from gemoji to tanuki_emoji

This commit is contained in:
Alexander Meindl 2022-04-10 13:45:24 +02:00
parent b2fea6e7f3
commit f23d70594f
34 changed files with 496 additions and 137 deletions

View File

@ -2,6 +2,8 @@ env:
browser: true
jquery: true
extends: 'eslint:recommended'
parserOptions:
ecmaVersion: 2019
rules:
indent:
- error

View File

@ -7,7 +7,7 @@ Rails:
AllCops:
TargetRubyVersion: 2.7
TargetRailsVersion: 6.1.4
TargetRailsVersion: 6.1
NewCops: enable
Metrics/AbcSize:

View File

@ -10,6 +10,7 @@ Changelog
- Drop feature "remove help" from top menu
- Add project filter for new_issue_message type
- Mermaid 9.0.0 support
- Switch from gemoji to tanuki_emoji
3.0.5.2
+++++++

View File

@ -20,9 +20,9 @@ Gem::Specification.new do |spec|
spec.require_paths = ['lib']
spec.required_ruby_version = '>= 2.7'
spec.add_runtime_dependency 'gemoji', '~> 3.0.0'
spec.add_runtime_dependency 'redmine_plugin_kit'
spec.add_runtime_dependency 'render_async'
spec.add_runtime_dependency 'rss'
spec.add_runtime_dependency 'slim-rails'
spec.add_runtime_dependency 'tanuki_emoji', '~> 0.6'
end

View File

@ -25,6 +25,10 @@ fieldset.settings
= additionals_settings_checkbox :add_go_to_top
em.info
= t :add_go_to_top_info
p
= additionals_settings_checkbox :emoji_support
em.info
= t :emoji_support_info_html
p
= additionals_settings_checkbox :legacy_smiley_support
em.info

BIN
assets/images/smilies.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -22,6 +22,12 @@ function openExternalUrlsInTab() {
'rel': 'noopener noreferrer'});
}
/* exported nativeEmojiSupport */
function nativeEmojiSupport(emoji_code) {
var noEmojis = /\p{Extended_Pictographic}/u;
return noEmojis.test(emoji_code);
}
/* exported formatNameWithIcon */
function formatNameWithIcon(opt) {
if (opt.loading) return opt.name;

View File

@ -73,6 +73,16 @@ img.inline_emojify {
height: 20px;
}
/* stylelint-disable selector-type-no-unknown */
additionals-emoji {
font-style: normal;
display: inline-flex;
vertical-align: baseline;
font-family: 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
font-size: 1.2em;
line-height: 1;
}
/* Legacy smilie classes */
.smiley {
@ -82,93 +92,28 @@ img.inline_emojify {
height: 16px;
}
.smiley-smiley {
background-image: url(../images/smileys/smiley.png);
}
.smiley-smiley2 {
background-image: url(../images/smileys/smiley2.png);
}
.smiley-laughing {
background-image: url(../images/smileys/smiley-grin.png);
}
.smiley-laughing2 {
background-image: url(../images/smileys/smiley-laughing2.png);
}
.smiley-crying {
background-image: url(../images/smileys/smiley-cry.png);
}
.smiley-sad {
background-image: url(../images/smileys/smiley-sad.png);
}
.smiley-wink {
background-image: url(../images/smileys/smiley-wink.png);
}
.smiley-cheeky {
background-image: url(../images/smileys/smiley-razz.png);
}
.smiley-shock {
background-image: url(../images/smileys/smiley-eek.png);
}
.smiley-annoyed {
background-image: url(../images/smileys/smiley-annoyed.png);
}
.smiley-confuse {
background-image: url(../images/smileys/smiley-confuse.png);
}
.smiley-straight {
background-image: url(../images/smileys/smiley-neutral.png);
}
.smiley-embarrassed {
background-image: url(../images/smileys/smiley-red.png);
}
.smiley-kiss {
background-image: url(../images/smileys/smiley-kiss.png);
}
.smiley-angel {
background-image: url(../images/smileys/smiley-angel.png);
}
.smiley-evil {
background-image: url(../images/smileys/smiley-evil.png);
}
.smiley-rock {
background-image: url(../images/smileys/smiley-cool.png);
}
.smiley-check {
background-image: url(../images/smileys/check.png);
}
.smiley-exclamation {
background-image: url(../images/smileys/exclamation-red-frame.png);
}
.smiley-question {
background-image: url(../images/smileys/question-frame.png);
}
.smiley-success {
background-image: url(../images/smileys/success-frame.png);
}
.smiley-failure {
background-image: url(../images/smileys/failure-frame.png);
}
.smiley-smiley { background-image: url(../images/smileys/smiley.png); }
.smiley-smiley2 { background-image: url(../images/smileys/smiley2.png); }
.smiley-laughing { background-image: url(../images/smileys/smiley-grin.png); }
.smiley-laughing2 { background-image: url(../images/smileys/smiley-laughing2.png); }
.smiley-crying { background-image: url(../images/smileys/smiley-cry.png); }
.smiley-sad { background-image: url(../images/smileys/smiley-sad.png); }
.smiley-wink { background-image: url(../images/smileys/smiley-wink.png); }
.smiley-cheeky { background-image: url(../images/smileys/smiley-razz.png); }
.smiley-shock { background-image: url(../images/smileys/smiley-eek.png); }
.smiley-annoyed { background-image: url(../images/smileys/smiley-annoyed.png); }
.smiley-confuse { background-image: url(../images/smileys/smiley-confuse.png); }
.smiley-straight { background-image: url(../images/smileys/smiley-neutral.png); }
.smiley-embarrassed { background-image: url(../images/smileys/smiley-red.png); }
.smiley-kiss { background-image: url(../images/smileys/smiley-kiss.png); }
.smiley-angel { background-image: url(../images/smileys/smiley-angel.png); }
.smiley-evil { background-image: url(../images/smileys/smiley-evil.png); }
.smiley-rock { background-image: url(../images/smileys/smiley-cool.png); }
.smiley-check { background-image: url(../images/smileys/check.png); }
.smiley-exclamation { background-image: url(../images/smileys/exclamation-red-frame.png); }
.smiley-question { background-image: url(../images/smileys/question-frame.png); }
.smiley-success { background-image: url(../images/smileys/success-frame.png); }
.smiley-failure { background-image: url(../images/smileys/failure-frame.png); }
div.clear-both { clear: both; }

View File

@ -166,7 +166,9 @@ cs:
label_without_value: "No %{value}"
label_yearly: "roční"
latest_entries_changes: "Poslední %{value} změny"
legacy_smiley_support_info_html: 'Převod smajlíků v textu. Tato volba by měla být aktivována, pouze pokud je kód pro smajlíky (e.g. :) ) byl zadán ručně a měl by být zobrazen jako smajlík. In the <a href="https://www.webpagefx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> the available Emoji codes can be used. <strong>Restart the application server</strong>, in order to activate the settings.'
label_emoji_support: Emoji support
emoji_support_info_html: 'Emojis im Text konvertieren. Aktivere diese Option, wenn :heart:, :+1: etc in Emojis konvertiert werden sollen. Im <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> können die zur Verfügung stehenden Emoji-Codes eingesetzt werden.'
legacy_smiley_support_info_html: 'Smileys im Text konvertieren. Aktiviere diese Option, wenn :), :-) etc in Smileys konvertiert werden sollen. Wird diese Einstellung verändert, <strong>muss der Anwendungsserver neu gestartet werden</strong>.'
max_live_search_results_info: "Počet maximálních výsledků vyhledávání pro službu LiveSearch. Poznámka: Nastavení se týká pouze zásuvných modulů, které podporují službu LiveSearch."
menu_roles_info: "Tuto položku nabídky uvidí pouze členové vybraných rolí."
new_ticket_message_info: "Všem, kteří chtějí přidat nové vydání, se zobrazí poznámka. Například zde můžete zadat akceptační testy nebo vydat pravidla. Tato nastavení se používají v celém projektu."

View File

@ -166,7 +166,9 @@ de:
label_without_value: "Ohne %{value}"
label_yearly: jährlich
latest_entries_changes: "Die letzten %{value} Änderungen"
legacy_smiley_support_info_html: 'Smileys im Text konvertieren. Diese Option sollte nur aktiviert werden, wenn der Code für Smileys (z.B. :) ) manuell eingetragen wurde und als Smiley Gesicht angezeigt werden soll. Im <a href="https://www.webpagefx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> können die zur Verfügung stehenden Emoji-Codes eingesetzt werden. Wird diese Einstellung aktiviert, <strong>muss der Anwendungsserver neu gestartet werden</strong>.'
label_emoji_support: Emoji Support
emoji_support_info_html: 'Emojis im Text konvertieren. Aktivere diese Option, wenn :heart:, :+1: etc in Emojis konvertiert werden sollen. Im <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> können die zur Verfügung stehenden Emoji-Codes eingesetzt werden.'
legacy_smiley_support_info_html: 'Smileys im Text konvertieren. Aktiviere diese Option, wenn :), :-) etc in Smileys konvertiert werden sollen. Wird diese Einstellung verändert, <strong>muss der Anwendungsserver neu gestartet werden</strong>.'
max_live_search_results_info: "Anzahl der maximalen Suchergebnisse für die LiveSearch. Hinweis: Einstellung wirkt sich nur auf Plugins aus, welche die LiveSearch unterstützen."
menu_roles_info: "Nur den ausgewählten Rollen wird der Menüpunkt angezeigt. Sobald ein Mitglied in einem Projekt die Rolle besitzt, wird der Menüpunkt angezeigt."
new_ticket_message_info: "Ein Hinweis, der beim Erstellen neuer Tickets angezeigt wird. Es kann beispielsweise auf Akzeptanztests oder Richtlinien zum Erstellen der Tickets hingewiesen werden. Dieser Einstellung ist projektübergreifend und ist in allen Projekten aktiv."

View File

@ -166,7 +166,9 @@ en:
label_without_value: "No %{value}"
label_yearly: yearly
latest_entries_changes: "Latest %{value} changes"
legacy_smiley_support_info_html: 'Convert smileys in text. This option should only be activated if the code for smileys (e.g. :) ) was entered manually and should be displayed as smiley face. In the <a href="https://www.webpagefx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> the available Emoji codes can be used. <strong>Restart the application server</strong>, in order to activate the settings.'
label_emoji_support: Emoji support
emoji_support_info_html: 'Emojis im Text konvertieren. Aktivere diese Option, wenn :heart:, :+1: etc in Emojis konvertiert werden sollen. Im <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> können die zur Verfügung stehenden Emoji-Codes eingesetzt werden.'
legacy_smiley_support_info_html: 'Smileys im Text konvertieren. Aktiviere diese Option, wenn :), :-) etc in Smileys konvertiert werden sollen. Wird diese Einstellung verändert, <strong>muss der Anwendungsserver neu gestartet werden</strong>.'
max_live_search_results_info: "Number of maximum search results for LiveSearch. Note: Setting only affects plugins that support LiveSearch."
menu_roles_info: "Only members of selected roles will see this menu entry."
new_ticket_message_info: "A note will be shown to everyone who wants to add a new issue. For example you can enter acceptance tests or issue rules here. These settings are used project wide."

View File

@ -166,7 +166,9 @@ es:
label_without_value: "No %{value}"
label_yearly: anualmente
latest_entries_changes: "Últimos %{value} cambios"
legacy_smiley_support_info_html: 'Convierte los smileys en texto. Esta opción sólo debería activarse si el código para los smileys (por ejemplo :) ) se introdujo manualmente y debería mostrarse como carita sonriente. En la <a href="https://www.webpagefx.com/tools/emoji-cheat-sheet/" target="_blank">hoja de trucos de Emoji </a> se pueden usar los códigos Emoji disponibles. Para activar esta configuración debe <strong>Reiniciar el servidor de aplicación</strong>.'
label_emoji_support: Emoji support
emoji_support_info_html: 'Emojis im Text konvertieren. Aktivere diese Option, wenn :heart:, :+1: etc in Emojis konvertiert werden sollen. Im <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> können die zur Verfügung stehenden Emoji-Codes eingesetzt werden.'
legacy_smiley_support_info_html: 'Smileys im Text konvertieren. Aktiviere diese Option, wenn :), :-) etc in Smileys konvertiert werden sollen. Wird diese Einstellung verändert, <strong>muss der Anwendungsserver neu gestartet werden</strong>.'
max_live_search_results_info: "Número de resultados máximos de búsqueda para LiveSearch. Nota: La configuración sólo afecta a los plugins que soportan LiveSearch."
menu_roles_info: "Solo los miembros con los roles selccionado podrán ver esta entrada de Menú."
new_ticket_message_info: "Se mostrará una nota a todos aquellos que quieran agregar una nueva petición. Puede por ejemplo agregar las condiciones de aceptación o las plantillas. Estas configuraciones afectan a todos los proyectos."

View File

@ -166,7 +166,9 @@ fr:
label_without_value: "Aucune %{value}"
label_yearly: annuellement
latest_entries_changes: "Derniers %{value} changements"
legacy_smiley_support_info_html: 'Convertissez les smileys en texte. Cette option ne doit être activée que si le code des smileys (par exemple :) ) a été saisi manuellement et doit être affiché sous forme de smiley. Dans la <a href="https://www.webpagefx.com/tools/emoji-cheat-sheet/" target="_blank">fiche Emoji</a> les codes Emoji disponibles peuvent être utilisés. <strong>Restart the application server</strong>, in order to activate the settings.'
label_emoji_support: Emoji support
emoji_support_info_html: 'Emojis im Text konvertieren. Aktivere diese Option, wenn :heart:, :+1: etc in Emojis konvertiert werden sollen. Im <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> können die zur Verfügung stehenden Emoji-Codes eingesetzt werden.'
legacy_smiley_support_info_html: 'Smileys im Text konvertieren. Aktiviere diese Option, wenn :), :-) etc in Smileys konvertiert werden sollen. Wird diese Einstellung verändert, <strong>muss der Anwendungsserver neu gestartet werden</strong>.'
max_live_search_results_info: "Nombre maximal de résultats de recherche pour la LiveSearch. Remarque : le paramètre n'a d'effet que sur les plugins qui supportent LiveSearch."
menu_roles_info: "Seuls les membres des rôles sélectionnés verront cette entrée de menu."
new_ticket_message_info: "Une note sera montrée à tous ceux qui veulent ajouter un nouveau numéro. Par exemple, vous pouvez saisir des tests d'acceptation ou édicter des règles ici. Ces paramètres sont utilisés à l'échelle du projet."

View File

@ -166,7 +166,9 @@ it:
label_without_value: "Nessun %{value}"
label_yearly: per anno
latest_entries_changes: "Ultime %{value} modifiche"
legacy_smiley_support_info_html: 'Convertire gli smileys in testo. Questa opzione dovrebbe essere attivata solo se il codice per gli smileys (ad es. :) ) è stato inserito manualmente e dovrebbe essere visualizzato come faccina sorridente. Nel <a href="https://www.webpagefx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> si possono utilizzare i codici Emoji disponibili. <strong>Restart the application server</strong>, in order to activate the settings.'
label_emoji_support: Emoji support
emoji_support_info_html: 'Emojis im Text konvertieren. Aktivere diese Option, wenn :heart:, :+1: etc in Emojis konvertiert werden sollen. Im <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> können die zur Verfügung stehenden Emoji-Codes eingesetzt werden.'
legacy_smiley_support_info_html: 'Smileys im Text konvertieren. Aktiviere diese Option, wenn :), :-) etc in Smileys konvertiert werden sollen. Wird diese Einstellung verändert, <strong>muss der Anwendungsserver neu gestartet werden</strong>.'
max_live_search_results_info: "Numero di risultati massimi di ricerca per LiveSearch. Nota: l'impostazione riguarda solo i plugin che supportano LiveSearch."
menu_roles_info: "Only members of selected roles will see this menu entry."
new_ticket_message_info: "Una nota verrà mostrata a tutti coloro che vogliono aggiungere un nuovo numero. Per esempio puoi inserire qui i test di accettazione o le regole di emissione. Queste impostazioni vengono utilizzate in tutto il progetto."

View File

@ -166,7 +166,9 @@ ja:
label_without_value: "%{value} なし"
label_yearly: '毎年'
latest_entries_changes: "最新の %{value} の変更点"
legacy_smiley_support_info_html: 'Convert smileys in text. This option should only be activated if the code for smileys (e.g. :) ) was entered manually and should be displayed as smiley face. In the <a href="https://www.webpagefx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> the available Emoji codes can be used. <strong>Restart the application server</strong>, in order to activate the settings.'
label_emoji_support: Emoji support
emoji_support_info_html: 'Emojis im Text konvertieren. Aktivere diese Option, wenn :heart:, :+1: etc in Emojis konvertiert werden sollen. Im <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> können die zur Verfügung stehenden Emoji-Codes eingesetzt werden.'
legacy_smiley_support_info_html: 'Smileys im Text konvertieren. Aktiviere diese Option, wenn :), :-) etc in Smileys konvertiert werden sollen. Wird diese Einstellung verändert, <strong>muss der Anwendungsserver neu gestartet werden</strong>.'
max_live_search_results_info: "LiveSearchの最大検索結果数です。注意この設定は、LiveSearchに対応したプラグインにのみ影響します。"
menu_roles_info: "選択された役割のメンバーだけがこのメニュー項目を表示します。"
new_ticket_message_info: "新規チケットを登録したいときに表示されるメモ書き。例えば、チケット入力のルールや承認規程を掲載する目的にでも使えます。これらの設定は全プロジェクトで有効です。"

View File

@ -166,7 +166,9 @@ ko:
label_without_value: "아니요 %{value}"
label_yearly: 매년
latest_entries_changes: "최근 %{value} 개의 변경 사항"
legacy_smiley_support_info_html: 'Convert smileys in text. This option should only be activated if the code for smileys (e.g. :) ) was entered manually and should be displayed as smiley face. In the <a href="https://www.webpagefx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> the available Emoji codes can be used. <strong>Restart the application server</strong>, in order to activate the settings.'
label_emoji_support: Emoji support
emoji_support_info_html: 'Emojis im Text konvertieren. Aktivere diese Option, wenn :heart:, :+1: etc in Emojis konvertiert werden sollen. Im <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> können die zur Verfügung stehenden Emoji-Codes eingesetzt werden.'
legacy_smiley_support_info_html: 'Smileys im Text konvertieren. Aktiviere diese Option, wenn :), :-) etc in Smileys konvertiert werden sollen. Wird diese Einstellung verändert, <strong>muss der Anwendungsserver neu gestartet werden</strong>.'
max_live_search_results_info: "LiveSearch의 최대 검색 결과 수입니다. 참고: 설정은 LiveSearch를 지원하는 플러그인에만 영향을 미칩니다."
menu_roles_info: "선택한 역할의 멤버 만이 메뉴 항목을 볼 수 있습니다."
new_ticket_message_info: "새로운 호를 추가하려는 모든 사람에게 메모가 표시됩니다. 예를 들어 수락 테스트를 입력하거나 규칙을 발행 할 수 있습니다. 이 설정은 프로젝트 전체에서 사용됩니다. "

View File

@ -166,7 +166,9 @@ pl:
label_without_value: "Nie %{value}"
label_yearly: coroczny
latest_entries_changes: "Ostatnie %{value} zmian"
legacy_smiley_support_info_html: 'Convert smileys in text. This option should only be activated if the code for smileys (e.g. :) ) was entered manually and should be displayed as smiley face. In the <a href="https://www.webpagefx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> the available Emoji codes can be used. <strong>Restart the application server</strong>, in order to activate the settings.'
label_emoji_support: Emoji support
emoji_support_info_html: 'Emojis im Text konvertieren. Aktivere diese Option, wenn :heart:, :+1: etc in Emojis konvertiert werden sollen. Im <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> können die zur Verfügung stehenden Emoji-Codes eingesetzt werden.'
legacy_smiley_support_info_html: 'Smileys im Text konvertieren. Aktiviere diese Option, wenn :), :-) etc in Smileys konvertiert werden sollen. Wird diese Einstellung verändert, <strong>muss der Anwendungsserver neu gestartet werden</strong>.'
max_live_search_results_info: "Liczba maksymalnych wyników wyszukiwania dla LiveSearch. Uwaga: Ustawienie ma wpływ tylko na wtyczki obsługujące LiveSearch."
menu_roles_info: "Tylko członkowie wybranych ról będą widzieć ten wpis w menu."
new_ticket_message_info: "Notatka zostanie wyświetlona każdemu, kto chce dodać nową issue. Na przykład, tutaj możesz wprowadzić testy akceptacyjne lub zasady issue. Ustawienia te są używane w całym projekcie."

View File

@ -166,7 +166,9 @@ pt-BR:
label_without_value: "Não %{value}"
label_yearly: "anual"
latest_entries_changes: "Últimas %{value} mudanças"
legacy_smiley_support_info_html: 'Convert smileys in text. This option should only be activated if the code for smileys (e.g. :) ) was entered manually and should be displayed as smiley face. In the <a href="https://www.webpagefx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> the available Emoji codes can be used. <strong>Restart the application server</strong>, in order to activate the settings.'
label_emoji_support: Emoji support
emoji_support_info_html: 'Emojis im Text konvertieren. Aktivere diese Option, wenn :heart:, :+1: etc in Emojis konvertiert werden sollen. Im <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> können die zur Verfügung stehenden Emoji-Codes eingesetzt werden.'
legacy_smiley_support_info_html: 'Smileys im Text konvertieren. Aktiviere diese Option, wenn :), :-) etc in Smileys konvertiert werden sollen. Wird diese Einstellung verändert, <strong>muss der Anwendungsserver neu gestartet werden</strong>.'
max_live_search_results_info: "Número máximo de resultados de busca para LiveSearch. Nota: A configuração só afeta os plugins que suportam o LiveSearch."
menu_roles_info: "Somente membros de funções selecionadas verão esta entrada de menu."
new_ticket_message_info: "Uma nota será mostrada a todos que quiserem acrescentar uma nova tarefa. Por exemplo, você pode inserir aqui testes de aceitação ou regras de tarefa. Estas configurações são usadas em todo o projeto."

View File

@ -166,7 +166,9 @@ ru:
label_without_value: "Нет %{value}"
label_yearly: "раз в год"
latest_entries_changes: "Последние изменения %{value}"
legacy_smiley_support_info_html: 'Convert smileys in text. This option should only be activated if the code for smileys (e.g. :) ) was entered manually and should be displayed as smiley face. In the <a href="https://www.webpagefx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> the available Emoji codes can be used. <strong>Restart the application server</strong>, in order to activate the settings.'
label_emoji_support: Emoji support
emoji_support_info_html: 'Emojis im Text konvertieren. Aktivere diese Option, wenn :heart:, :+1: etc in Emojis konvertiert werden sollen. Im <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> können die zur Verfügung stehenden Emoji-Codes eingesetzt werden.'
legacy_smiley_support_info_html: 'Smileys im Text konvertieren. Aktiviere diese Option, wenn :), :-) etc in Smileys konvertiert werden sollen. Wird diese Einstellung verändert, <strong>muss der Anwendungsserver neu gestartet werden</strong>.'
max_live_search_results_info: "Количество максимальных результатов поиска для LiveSearch. Примечание: Настройка влияет только на плагины, поддерживающие LiveSearch."
menu_roles_info: "Этот пункт меню будет доступен только пользователям с выбранными ролями."
new_ticket_message_info: "Всем, кто хочет добавить новое задание, будет показана заметка. Например, здесь вы можете ввести правила приемочных испытаний или заданий. Эти настройки используются для всего проекта."

View File

@ -166,7 +166,9 @@
label_without_value: "沒有 %{value}"
label_yearly: "每年"
latest_entries_changes: "Latest %{value} changes"
legacy_smiley_support_info_html: "Convert smileys in text. This option should only be activated if the code for smileys (e.g. :) ) was entered manually and should be displayed as smiley face. In the <a href=\"https://www.webpagefx.com/tools/emoji-cheat-sheet/\" target=\"_blank\">Emoji cheat sheet</a> the available Emoji codes can be used. 修改後必須重啟Redmine。"
label_emoji_support: Emoji support
emoji_support_info_html: 'Emojis im Text konvertieren. Aktivere diese Option, wenn :heart:, :+1: etc in Emojis konvertiert werden sollen. Im <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> können die zur Verfügung stehenden Emoji-Codes eingesetzt werden.'
legacy_smiley_support_info_html: 'Smileys im Text konvertieren. Aktiviere diese Option, wenn :), :-) etc in Smileys konvertiert werden sollen. Wird diese Einstellung verändert, <strong>muss der Anwendungsserver neu gestartet werden</strong>.'
max_live_search_results_info: "LiveSearch的最大搜索结果的数量。注意设置只影响到支持LiveSearch的插件。"
menu_roles_info: "只有所選的角色權限才能看到選單。"
new_ticket_message_info: "每個新建立議題用戶都會看到提示訊息。"

View File

@ -166,7 +166,9 @@ zh:
label_without_value: "没有 %{value}"
label_yearly: 每年
latest_entries_changes: "最新的 %{value} 变更"
legacy_smiley_support_info_html: '转换文字中的颜文字。此选项应当仅在希望将手动输入的颜文字代码(例如 :))展示为表情时选中。<a href="https://www.webpagefx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> 提供了可用的颜文字代码。为激活该配置,必须 <strong>重启 Redmine 服务</strong> 。'
label_emoji_support: Emoji support
emoji_support_info_html: 'Emojis im Text konvertieren. Aktivere diese Option, wenn :heart:, :+1: etc in Emojis konvertiert werden sollen. Im <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">Emoji cheat sheet</a> können die zur Verfügung stehenden Emoji-Codes eingesetzt werden.'
legacy_smiley_support_info_html: 'Smileys im Text konvertieren. Aktiviere diese Option, wenn :), :-) etc in Smileys konvertiert werden sollen. Wird diese Einstellung verändert, <strong>muss der Anwendungsserver neu gestartet werden</strong>.'
max_live_search_results_info: "LiveSearch的最大搜索结果的数量。注意设置只影响到支持LiveSearch的插件。"
menu_roles_info: "只有所选角色对应的用户才能看到菜单项。"
new_ticket_message_info: "每个新建问题的用户都会看到提示信息。例如,您可以输入可接受性测试或问题处理规则。这些配置在某个具体的项目范围内适用。"

View File

@ -2,30 +2,32 @@
account_login_bottom: ''
add_go_to_top: 0
disabled_modules:
open_external_urls: 1
emoji_support: 0
disable_emoji_native_support: 0
global_footer: ''
global_sidebar: ''
global_wiki_sidebar: ''
google_maps_api_key: ''
hidden_macros_in_toolbar:
max_live_search_results: 50
issue_assign_to_me: 0
issue_assign_to_x: ''
issue_auto_assign: 0
issue_auto_assign_role: ''
issue_auto_assign_status: ''
issue_auto_assign: 0
issue_change_status_in_sidebar: 0
issue_current_user_status: 0
issue_freezed_with_close: 0
issue_status_change: 0
issue_status_x: ''
issue_status_y: ''
issue_timelog_required: 0
issue_timelog_required_status: ''
issue_timelog_required_tracker: ''
issue_timelog_required: 0
legacy_smiley_support: 0
max_live_search_results: 50
new_issue_on_profile: 0
new_ticket_message: "Don't forget to define acceptance criteria!"
open_external_urls: 1
remove_help: 0
wiki_pdf_remove_attachments: 0
wiki_pdf_remove_title: 0

View File

@ -61,14 +61,6 @@ Install ``additionals`` plugin for `Redmine`_.
$ bundle config set --local without 'development test'
$ bundle install
$ bundle exec rake redmine:plugins:migrate RAILS_ENV=production
$
$ # if you want to use smiley/emoji legacy support, you have to put emoji icons to
$ # $REDMINE_ROOT/public/images/emoji
$ # To obtain image files, run the gemoji extract command on macOS Sierra or later:
$ bundle exec gemoji extract public/images/emoji
$
$ # if you to not have macOS, you can put these files manually to $REDMINE_ROOT/public/images/emoji
$ # see https://github.com/github/gemoji for more infos
Restart your application server (apache with passenger, nginx with passenger, unicorn, puma, etc.) and ``Additionals`` is ready to use.

View File

@ -9,6 +9,7 @@ module Additionals
DEFAULT_MODAL_WIDTH = '350px'
GOTO_LIST = " \xc2\xbb"
LIST_SEPARATOR = "#{GOTO_LIST} "
EMOJI_ASSERT_PATH = 'images/emojis'
include RedminePluginKit::PluginBase
@ -135,6 +136,7 @@ module Additionals
loader.add_patch [{ target: Redmine::WikiFormatting::Markdown::HTML, patch: 'FormatterMarkdown' },
{ target: Redmine::WikiFormatting::Markdown::Helper, patch: 'FormattingHelper' }]
when 'common_mark'
loader.add_patch [{ target: Redmine::WikiFormatting::CommonMark::Formatter, patch: 'FormatterCommonMark' }]
loader.add_patch [{ target: Redmine::WikiFormatting::CommonMark::Helper, patch: 'FormattingHelper' }]
when 'textile'
loader.add_patch [{ target: Redmine::WikiFormatting::Textile::Formatter, patch: 'FormatterTextile' },
@ -142,6 +144,9 @@ module Additionals
end
end
# Clients
loader.require_files File.join('wiki_formatting', 'common_mark', '**/*_filter.rb')
# Apply patches and helper
loader.apply!
@ -155,7 +160,7 @@ module Additionals
# Run the classic redmine plugin initializer after rails boot
class Plugin < ::Rails::Engine
require 'emoji'
require 'tanuki_emoji'
require 'render_async'
require 'rss'
require 'slim'
@ -165,6 +170,8 @@ module Additionals
# create some side effencts
plugin_id = 'additionals'
Additionals::Gemify.install_emoji_assets
# if plugin is already in plugins directory, use this and leave here
next if Redmine::Plugin.installed? plugin_id

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true
require 'emoji'
module Additionals
module Formatter
SMILEYS = { 'smiley' => ':-?\)', # :)
@ -30,8 +28,9 @@ module Additionals
def render_inline_smileys(text)
return text if text.blank?
inline_smileys text
text
content = text.dup
inline_smileys content
content
end
def inline_smileys(text)
@ -41,34 +40,67 @@ module Additionals
esc = Regexp.last_match 2
smiley = Regexp.last_match 3
if esc.nil?
leading + tag.span(class: "additionals smiley smiley-#{name}",
leading.to_s + ActionController::Base.helpers.tag.span(class: "additionals smiley smiley-#{name}",
title: smiley)
else
leading + smiley
leading.to_s + smiley
end
end
end
end
def inline_emojify(text)
text.gsub!(/:([\w+-]+):/) do |match|
emoji_code = Regexp.last_match 1
emoji = Emoji.find_by_alias emoji_code # rubocop:disable Rails/DynamicFindBy
if emoji.present?
tag.img src: inline_emojify_image_path(emoji.image_filename),
title: ":#{emoji_code}:",
def emoji_tag(emoji, emoji_code)
if Additionals.setting? :disable_emoji_native_support
emoji_tag_fallback emoji, emoji_code
else
emoji_tag_native emoji, emoji_code
end
end
def emoji_tag_native(emoji, _emoji_code)
return unless emoji
data = {
name: emoji.name,
unicode_version: emoji.unicode_version
}
options = { title: emoji.description, data: data }
ActionController::Base.helpers.content_tag 'additionals-emoji', emoji.codepoints, options
end
def emoji_tag_fallback(emoji, _emoji_code)
ActionController::Base.helpers.image_tag emoji_image_path(emoji),
title: emoji.description,
class: 'inline_emojify'
end
def emoji_image_path(emoji, local: false)
base_url = local ? '/' : Additionals.full_url
File.join base_url, Additionals::EMOJI_ASSERT_PATH, emoji.image_name
end
def with_emoji?(text)
text.match? emoji_pattern
end
def emoji_pattern
@emoji_pattern ||= TanukiEmoji.index.alpha_code_pattern
end
def inline_emojify(text)
return text unless with_emoji? text
text.gsub! emoji_pattern do |match|
emoji_code = Regexp.last_match 1
emoji = TanukiEmoji.find_by_alpha_code emoji_code # rubocop: disable Rails/DynamicFindBy
if emoji
emoji_tag emoji, emoji_code
else
match
end
end
text
end
# TODO: use relative path, if not for mailer
def inline_emojify_image_path(image_filename)
# path = '/' + Rails.public_path.relative_path_from Rails.root.join('public')
"#{Additionals.full_url '/images/emoji/'}#{image_filename}"
end
end
end

View File

@ -3,6 +3,28 @@
module Additionals
class Gemify
class << self
# install emoji fallback assets from gem (without asset pipline)
def install_emoji_assets
Additionals.debug 'install_emoji_assets'
return Rails.logger.error 'TanukiEmoji class for emoji not found' unless defined? TanukiEmoji
source_image_path = TanukiEmoji.images_path
target_image_path = File.join Dir.pwd, 'public', Additionals::EMOJI_ASSERT_PATH
begin
FileUtils.mkdir_p target_image_path
rescue StandardError => e
raise "Could not create directory #{target_image_path}: " + e.message
end
Dir["#{source_image_path}/*"].each do |file|
target = File.join target_image_path, file.gsub(source_image_path, '')
FileUtils.cp file, target unless File.exist?(target) && FileUtils.identical?(file, target)
rescue StandardError => e
raise "Could not copy #{file} to #{target}: " + e.message
end
end
# install assets from gem (without asset pipline)
def install_assets(plugin_id = 'additionals')
return unless Gem.loaded_specs[plugin_id]

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
module Additionals
module Patches
module FormatterCommonMarkPatch
extend ActiveSupport::Concern
included do
prepend InstanceOverwriteMethods
end
module InstanceOverwriteMethods
def to_html(*_args)
return super unless Additionals.setting?(:legacy_smiley_support) || Additionals.setting?(:emoji_support)
filters = Redmine::WikiFormatting::CommonMark::MarkdownPipeline.filters.dup
filters << Additionals::WikiFormatting::CommonMark::SmileyFilter if Additionals.setting? :legacy_smiley_support
filters << Additionals::WikiFormatting::CommonMark::EmojiFilter if Additionals.setting? :emoji_support
pipeline = HTML::Pipeline.new filters, Redmine::WikiFormatting::CommonMark::PIPELINE_CONFIG
result = pipeline.call @text
result[:output].to_s
end
end
end
end
end

View File

@ -10,8 +10,10 @@ module Additionals
# Add a postprocess hook to redcarpet's html formatter
def postprocess(text)
inline_emojify text if Additionals.setting? :emoji_support
if Additionals.setting? :legacy_smiley_support
render_inline_smileys(inline_emojify(text))
render_inline_smileys text
else
text
end

View File

@ -7,9 +7,20 @@ module Additionals
included do
include Additionals::Formatter
prepend InstanceOverwriteMethods
end
# emojify are always enabled
module InstanceOverwriteMethods
def to_html(*_rules)
if Additionals.setting? :emoji_support
Redmine::WikiFormatting::Textile::Formatter::RULES << :inline_emojify
else
Redmine::WikiFormatting::Textile::Formatter::RULES.delete :inline_emojify
end
@toc = []
super(*Redmine::WikiFormatting::Textile::Formatter::RULES).to_s
end
end
end
end

View File

@ -0,0 +1,65 @@
# frozen_string_literal: true
module Additionals
module WikiFormatting
module CommonMark
class EmojiFilter < HTML::Pipeline::Filter
IGNORED_ANCESTOR_TAGS = %w[pre code].to_set
include Additionals::Formatter
def call
doc.xpath('descendant-or-self::text()').each do |node|
content = node.to_html
next if has_ancestor? node, IGNORED_ANCESTOR_TAGS
next unless with_emoji?(content) || node.text.match(emoji_unicode_pattern)
html = emoji_unicode_element_unicode_filter content
html = emoji_name_element_unicode_filter html
next if html == content
node.replace html
end
doc
end
# Replace :emoji: with corresponding gl-emoji unicode.
#
# text - String text to replace :emoji: in.
#
# Returns a String with :emoji: replaced with gl-emoji unicode.
def emoji_name_element_unicode_filter(text)
text.gsub emoji_pattern do
name = Regexp.last_match 1
emoji = TanukiEmoji.find_by_alpha_code name # rubocop: disable Rails/DynamicFindBy
emoji_tag emoji, name
end
end
# Replace unicode emoji with corresponding gl-emoji unicode.
#
# text - String text to replace unicode emoji in.
#
# Returns a String with unicode emoji replaced with gl-emoji unicode.
def emoji_unicode_element_unicode_filter(text)
text.gsub emoji_unicode_pattern do |moji|
emoji = TanukiEmoji.find_by_codepoints moji # rubocop: disable Rails/DynamicFindBy
emoji_tag_native emoji, name
end
end
# Build a regexp that matches all valid unicode emojis names.
def self.emoji_unicode_pattern
@emoji_unicode_pattern ||= TanukiEmoji.index.codepoints_pattern
end
private
def emoji_unicode_pattern
self.class.emoji_unicode_pattern
end
end
end
end
end

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
module Additionals
module WikiFormatting
module CommonMark
class SmileyFilter < HTML::Pipeline::Filter
IGNORED_ANCESTOR_TAGS = %w[pre code].to_set
include Additionals::Formatter
def call
doc.xpath('descendant-or-self::text()').each do |node|
content = node.to_html
next if has_ancestor? node, IGNORED_ANCESTOR_TAGS
html = render_inline_smileys content
next if html == content
node.replace html
end
doc
end
end
end
end
end

View File

@ -0,0 +1,61 @@
# frozen_string_literal: true
require File.expand_path '../../../test_helper', __FILE__
module WikiFormatting
class CommonMarkTest < ActiveSupport::TestCase
include Additionals::TestHelper
def setup
@options = {}
end
def test_smilies
with_plugin_settings 'additionals', legacy_smiley_support: 1,
emoji_support: 0 do
input = <<~HTML
A small test :) with an smiley
HTML
expected = <<~HTML
A small test <span class="additionals smiley smiley-smiley" title=":)"></span> with an smiley
HTML
assert_equal expected, smiley_filter(input)
end
end
def test_emojis
input = <<~HTML
:heart:
<pre><code>
def foo
:heart:
end
</code></pre>
HTML
expected = <<~HTML
<img title="heavy black heart" class="inline_emojify" src="http://localhost:3000/images/emojis/emoji_u2764.png">
<pre><code>
def foo
:heart:
end
</code></pre>
HTML
with_plugin_settings 'additionals', legacy_smiley_support: 0,
emoji_support: 1,
disable_emoji_native_support: 1 do
assert_equal expected, emoji_filter(input)
end
end
private
def smiley_filter(html)
Additionals::WikiFormatting::CommonMark::SmileyFilter.to_html html, @options
end
def emoji_filter(html)
Additionals::WikiFormatting::CommonMark::EmojiFilter.to_html html, @options
end
end
end

View File

@ -0,0 +1,53 @@
# frozen_string_literal: true
require File.expand_path '../../../test_helper', __FILE__
module WikiFormatting
class MarkdownTest < ActionView::TestCase
include Additionals::TestHelper
def setup
skip 'Redcarpet is not installed' unless Object.const_defined? :Redcarpet
@formatter = Redmine::WikiFormatting::Markdown::Formatter
end
def test_smilies
with_plugin_settings 'additionals', legacy_smiley_support: 1,
emoji_support: 0 do
text = 'A small test :) with an smilie'
assert_equal '<p>A small test <span class="additionals smiley smiley-smiley" title=":)"></span> with an smilie</p>',
@formatter.new(text).to_html.strip
end
end
def test_emojies
with_plugin_settings 'additionals', legacy_smiley_support: 0,
emoji_support: 1,
disable_emoji_native_support: 1 do
text = 'A test with a :heart: emoji'
assert_equal '<p>A test with a <img title="heavy black heart" class="inline_emojify"' \
' src="http://localhost:3000/images/emojis/emoji_u2764.png" /> emoji</p>',
@formatter.new(text).to_html.strip
end
end
def test_smilies_and_emojies
with_plugin_settings 'additionals', legacy_smiley_support: 1,
emoji_support: 1,
disable_emoji_native_support: 1 do
text = ':heart: and :)'
assert_equal '<p><img title="heavy black heart" class="inline_emojify"' \
' src="http://localhost:3000/images/emojis/emoji_u2764.png" />' \
' and <span class="additionals smiley smiley-smiley" title=":)"></span></p>',
@formatter.new(text).to_html.strip
text = ' :) and :heart:'
assert_equal '<p><span class="additionals smiley smiley-smiley" title=":)"></span> and' \
' <img title="heavy black heart" class="inline_emojify"' \
' src="http://localhost:3000/images/emojis/emoji_u2764.png" /></p>',
@formatter.new(text).to_html.strip
end
end
end
end

View File

@ -0,0 +1,75 @@
# frozen_string_literal: true
require File.expand_path '../../../test_helper', __FILE__
require 'digest/md5'
module WikiFormatting
class TextileTest < ActionView::TestCase
include Additionals::TestHelper
def setup
@formatter = Redmine::WikiFormatting::Textile::Formatter
@to_test = {}
end
def test_smilies
with_plugin_settings 'additionals', legacy_smiley_support: 1,
emoji_support: 0 do
# this is required, because inline_smileys are activated with controller action
@formatter::RULES << :inline_smileys
@to_test['A test with a :) smiley'] = 'A test with a <span class="additionals smiley smiley-smiley" title=":)"></span> smiley'
@to_test[':) :)'] = '<span class="additionals smiley smiley-smiley" title=":)"></span>' \
' <span class="additionals smiley smiley-smiley" title=":)"></span>'
assert_html_output @to_test
end
end
def test_emojies
with_plugin_settings 'additionals', legacy_smiley_support: 0,
emoji_support: 1,
disable_emoji_native_support: 1 do
@formatter::RULES.delete :inline_smileys
str = 'A test with a :heart: emoji and a :) smiley'
@to_test[str] = 'A test with a <img title="heavy black heart" class="inline_emojify"' \
' src="http://localhost:3000/images/emojis/emoji_u2764.png" /> emoji and a :) smiley'
assert_html_output @to_test
end
end
def test_smilies_and_emojies
with_plugin_settings 'additionals', legacy_smiley_support: 1,
emoji_support: 1,
disable_emoji_native_support: 1 do
# this is required, because inline_smileys are activated with controller action
@formatter::RULES << :inline_smileys
@to_test[':heart: and :)'] = '<img title="heavy black heart" class="inline_emojify"' \
' src="http://localhost:3000/images/emojis/emoji_u2764.png" />' \
' and <span class="additionals smiley smiley-smiley" title=":)"></span>'
@to_test[':) and :heart:'] = '<span class="additionals smiley smiley-smiley" title=":)"></span> and' \
' <img title="heavy black heart" class="inline_emojify"' \
' src="http://localhost:3000/images/emojis/emoji_u2764.png" />'
assert_html_output @to_test
end
end
private
def assert_html_output(to_test, expect_paragraph: true)
to_test.each do |text, expected|
assert_equal(
(expect_paragraph ? "<p>#{expected}</p>" : expected),
@formatter.new(text).to_html,
"Formatting the following text failed:\n===\n#{text}\n===\n"
)
end
end
def to_html(text)
@formatter.new(text).to_html
end
end
end