diff --git a/addon/src/_locales/bg/messages.json b/addon/src/_locales/bg/messages.json index 49f58e53..50f8c297 100644 --- a/addon/src/_locales/bg/messages.json +++ b/addon/src/_locales/bg/messages.json @@ -278,8 +278,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "Тук се добавят клавишни комбинации.
Ограничения:
1. Тези клавишни комбинации ще работят само в страници от интернет (http:, https:), а не в служебните (about:) страници на четеца, защото ППИ на WebExtensions не го позволява.
2. Някои комбинации няма да работят с всички клавиатурни подредби. Например, комбинацията Ctrl + ~, създадена с актива английска подредба няма да работи ако в момента е активна българската, защото в българската подредба този клавиш има друг код. За да заобиколите този недостатък просто създайте същата комбинация докато е активна българска клавиатурна подредба: Ctrl + Ю.", - "description": "Hotkeys description" + "message": "Също така можете да настроите клавишни комбинации на страницата Управление на клавишни комбинации на разширения. Ще работят във всички прозорци и на всички страници.", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "Нова комбинация", @@ -1031,10 +1031,6 @@ } } }, - "hotkeysDescription2": { - "message": "Също така можете да настроите клавишни комбинации на страницата Управление на клавишни комбинации на разширения. Ще работят във всички прозорци и на всички страници.", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "Спиране звука на раздела", "description": "Mute tab" diff --git a/addon/src/_locales/cs_CZ/messages.json b/addon/src/_locales/cs_CZ/messages.json index 9475fd99..dc94b8fb 100644 --- a/addon/src/_locales/cs_CZ/messages.json +++ b/addon/src/_locales/cs_CZ/messages.json @@ -266,8 +266,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "Zde můžete přidat klávesové zkratky.
Omezení:
1. Tyto zkratky fungují pouze na webových stránkách (http:, https:). Nefungují na stránkách prohlížeče (about:) - WebExtensions API to neumožňuje.
2. Některé zkratky nebudou fungovat na všech klávesnicích. Například: zkratka vytvořená na anglické klávesnici Ctrl + ~ nebude fungovat na ruské klávesnici, protože tato klávesa má na ruské jiný kód. Pro opravu prostě vytvořte novou klávesovou zkratku na ruské klávesnici Ctrl + Ё", - "description": "Hotkeys description" + "message": "Klávesové zkratky lze také nastavit ve správě doplňků ve Firefoxu. Tyto zkratky fungují na všech stránkách.", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "Přidat zkratku", @@ -959,10 +959,6 @@ } } }, - "hotkeysDescription2": { - "message": "Klávesové zkratky lze také nastavit ve správě doplňků ve Firefoxu. Tyto zkratky fungují na všech stránkách.", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "Ztlumit zvuk panelu", "description": "Mute tab" diff --git a/addon/src/_locales/de/messages.json b/addon/src/_locales/de/messages.json index eedceba4..ce2d4187 100644 --- a/addon/src/_locales/de/messages.json +++ b/addon/src/_locales/de/messages.json @@ -278,8 +278,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "Hier kannst du Hotkeys hinzufügen.
Beschränkungen:
1. Diese Hotkeys funktionieren nur auf regulären Webseiten (http://, https://). Auf den Browserseiten (about:) funktionieren sie nicht (die WebExtensions-API verhindert das).
2. Einige Hotkeys funktionieren nicht mit allen Tastatur-Layouts. Wird zum Beispiel der Shortcut Ctrl + ~ mit englischem Layout erstellt, funktioniert er nicht im russischen Layout, da im russischen Layout diese Taste mit einem anderen Code belegt ist. Um dies zu beheben, erzeuge einen neuen Hotkey im russischen Layout: Ctrl + Ё.", - "description": "Hotkeys description" + "message": "Du kannst außerdem Tastenkürzel auf der Seite Manage extension shortcuts in Firefox einrichten. Sie funktionieren auf allen Seiten und Fenstern.", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "Hotkey hinzufügen", @@ -1023,10 +1023,6 @@ } } }, - "hotkeysDescription2": { - "message": "Du kannst außerdem Tastenkürzel auf der Seite Manage extension shortcuts in Firefox einrichten. Sie funktionieren auf allen Seiten und Fenstern.", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "Tab stummschalten", "description": "Mute tab" diff --git a/addon/src/_locales/el/messages.json b/addon/src/_locales/el/messages.json index 125f720e..e7acf2d4 100644 --- a/addon/src/_locales/el/messages.json +++ b/addon/src/_locales/el/messages.json @@ -251,10 +251,6 @@ "message": "Hotkeys", "description": "Hotkeys" }, - "hotkeysDescription": { - "message": "Εδώ μπορείτε να προσθέσετε hot keys.
Περιορισμοί:
1. Τα hotkeys λειτουργούν μόνο σε σελίδες web (http:, https:). Δεν λειτουργούν σε σελίδες browser (about:) - το WebExtensions API δεν το επιτρέπει.
2. Μερικά hotkeys δεν θα λειτουργούν σε κάποιες γλώσσες πληκτρολογίου. Για παράδειγμα, η συντόμευση (δημιουργημένη σε Αγγλικό πληκτρολόγιο) Ctrl + ~ δεν θα λειτουργεί στο Ρωσσικό πληκτρολόγιο, γιατί εκεί αυτό το πλήκτρο έχει άλλον κωδικό. Για να το ξεπεράσετε, απλά δημιουργείστε ένα άλλο hotkey στο Ρωσσικό πληκτρολόγιο: Ctrl + Ё", - "description": "Hotkeys description" - }, "addHotKeyButton": { "message": "Προσθήκη hotkey", "description": "Add hotkey" diff --git a/addon/src/_locales/en/messages.json b/addon/src/_locales/en/messages.json index 8555f30e..fa3c9154 100644 --- a/addon/src/_locales/en/messages.json +++ b/addon/src/_locales/en/messages.json @@ -282,8 +282,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "Here you can add hotkeys.
Restrictions:
1. These hotkeys will only work on web pages (http:, https:), not on the browser pages (about:), because the WebExtensions API does not allow this.
2. Some hotkeys will not work with all keyboard layouts. For example, a Ctrl + ~ shortcut created with an English layout will not work with a keyboard with Russian layout, because in the Russian layout this key has another code. To fix this, just create another hotkey with the Russian layout: Ctrl + Ё", - "description": "Hotkeys description" + "message": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages.", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "Add hotkey", @@ -1035,10 +1035,6 @@ } } }, - "hotkeysDescription2": { - "message": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages.", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "Mute tab", "description": "Mute tab" diff --git a/addon/src/_locales/es_AR/messages.json b/addon/src/_locales/es_AR/messages.json index e7d65284..52909f56 100644 --- a/addon/src/_locales/es_AR/messages.json +++ b/addon/src/_locales/es_AR/messages.json @@ -270,8 +270,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "Acá podes agregar atajos rápidos.
Restricciones:
1. Estos atajos rápidos solo funcionan en paginas web (http:, https:),no en las paginas del navegador (about:), porque la API WebExtensions no lo permite.
2. Algunos atajos rápidos no funcionarán con todas las distribuciones de teclados. Por ejemplo, el atajo Ctrl + ~ creado en un teclado en Inglés no funcionará en un teclado en Ruso, porque en el diseño Ruso esta tecla tiene otro código. Para corregir esto, creá un atajo rápido con el teclado en Ruso Ctrl + Ё", - "description": "Hotkeys description" + "message": "Además podes configurar atajos rápidos en la página Gestionar atajos de teclado de extensiones en Firefox. Estos funcionarán en todas las ventanas y páginas del navegador.", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "Agregar atajo rápido", @@ -1003,10 +1003,6 @@ } } }, - "hotkeysDescription2": { - "message": "Además podes configurar atajos rápidos en la página Gestionar atajos de teclado de extensiones en Firefox. Estos funcionarán en todas las ventanas y páginas del navegador.", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "Mutear pestaña", "description": "Mute tab" diff --git a/addon/src/_locales/es_ES/messages.json b/addon/src/_locales/es_ES/messages.json index 8aff5887..d874ba03 100644 --- a/addon/src/_locales/es_ES/messages.json +++ b/addon/src/_locales/es_ES/messages.json @@ -278,8 +278,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "Aquí puede añadir atajos de teclado.
Restricciones:
1. Estos atajos solo funcionarán en páginas web (http:, https:), no en las páginas del mismo navegador (about:), ya que el API WebExtensions no lo permite.
2. Algunos atajos no funcionarán con todas las distribuciones de teclado. Por ejemplo, un atajo Ctrl + ~ creado con un teclado con distribución en Inglés no funcionará en un teclado con distribución en Ruso, ya que en Ruso este atajo tiene otro código. Para corregirlo, solo cree otro atajo con la distribución de teclado en Ruso: Ctrl + Ë", - "description": "Hotkeys description" + "message": "También puedes configurar los atajos en la página Gestionar atajos de teclado de extensiones en Firefox. Funcionarán en todas las ventanas y páginas del navegador.", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "Añadir atajo", @@ -1023,10 +1023,6 @@ } } }, - "hotkeysDescription2": { - "message": "También puedes configurar los atajos en la página Gestionar atajos de teclado de extensiones en Firefox. Funcionarán en todas las ventanas y páginas del navegador.", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "Silenciar pestaña", "description": "Mute tab" diff --git a/addon/src/_locales/fr/messages.json b/addon/src/_locales/fr/messages.json index 0fe616d9..2d7a880d 100644 --- a/addon/src/_locales/fr/messages.json +++ b/addon/src/_locales/fr/messages.json @@ -278,8 +278,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "Ici vous pouvez ajouter des raccourcis.
Restrictions :
1. Ces raccourcis ne fonctionneront que sur des pages web (http:, https:). Sur des pages du navigateur (about:) - cela ne fonctionne pas, l'API WebExtensions ne l'autorise pas.
2. Certains raccourcis ne fonctionneront pas sur différentes dispositions de clavier. Par exemple, le raccourci Ctrl + ~ créé dans la disposition US ne fonctionnera pas sur la disposition RU, car la disposition russe a un autre code pour cette touche. Pour contourner ce problème, créez simplement un autre raccourci avec la disposition russe : Ctrl + Ё", - "description": "Hotkeys description" + "message": "Vous pouvez aussi configurer les raccourcis sur la page Gérer les raccourcis d'extension. Ceci s'appliquera à toutes les fenêtres et toutes les pages du navigateur.", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "Ajouter un raccourci", @@ -1023,10 +1023,6 @@ } } }, - "hotkeysDescription2": { - "message": "Vous pouvez aussi configurer les raccourcis sur la page Gérer les raccourcis d'extension. Ceci s'appliquera à toutes les fenêtres et toutes les pages du navigateur.", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "Rendre l'onglet silencieux", "description": "Mute tab" diff --git a/addon/src/_locales/in_ID/messages.json b/addon/src/_locales/in_ID/messages.json index 43076ba4..d09334b9 100644 --- a/addon/src/_locales/in_ID/messages.json +++ b/addon/src/_locales/in_ID/messages.json @@ -270,8 +270,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "Di sini Anda dapat menambahkan hotkey.
Pembatasan:
1. Tombol pintas ini hanya akan berfungsi di halaman web (http:, https:), bukan di halaman browser (about:), karena API WebExtensions tidak mengizinkan ini.
2. Beberapa tombol pintas tidak akan berfungsi dengan semua tata letak keyboard. Misalnya, pintasan Ctrl + ~ yang dibuat dengan tata letak bahasa Inggris tidak akan berfungsi dengan keyboard dengan tata letak Rusia, karena dalam tata letak Rusia tombol ini memiliki kode lain. Untuk memperbaikinya, cukup buat hotkey lain dengan tata letak Rusia: Ctrl + ", - "description": "Hotkeys description" + "message": "Anda juga dapat mengonfigurasi tombol pintas di halaman Kelola pintasan ekstensi di Firefox. Mereka akan bekerja di semua jendela dan halaman browser.", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "Tambahkan hotkey", @@ -1003,10 +1003,6 @@ } } }, - "hotkeysDescription2": { - "message": "Anda juga dapat mengonfigurasi tombol pintas di halaman Kelola pintasan ekstensi di Firefox. Mereka akan bekerja di semua jendela dan halaman browser.", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "Bisukan tab", "description": "Mute tab" diff --git a/addon/src/_locales/it/messages.json b/addon/src/_locales/it/messages.json index 2d6de622..6ec0e09f 100644 --- a/addon/src/_locales/it/messages.json +++ b/addon/src/_locales/it/messages.json @@ -270,8 +270,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "Qui puoi aggiungere le scorciatoie.
Limitazioni:
1. Queste scorciatoie funzioneranno solamente nelle pagine web (http:, https:). Sulle pagine del browser (about:) non funzionano a causa delle limitazioni imposte delle WebExtension API.
2. Alcune delle scorciatoie non funzioneranno con alcuni configurazioni della tastiera. La scorciatoia creata con la tastiera inglese Ctrl + ~ non funziona sulla tastiera russa, perché questo tasto ha un altro codice. Per sistemare questo problema, crea una scorciatoia con un altro tasto: per il caso precedente, aggiungi la scorciatoia Ctrl + Ё.", - "description": "Hotkeys description" + "message": "Puoi modificare le scorciatoie sulla pagina Gestire le scorciatoie da tastiera per i componenti aggiuntivi in Firefox. Funzioneranno su tutte le finestre e le pagine del browser.", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "Aggiungi una scorciatoia", @@ -1003,10 +1003,6 @@ } } }, - "hotkeysDescription2": { - "message": "Puoi modificare le scorciatoie sulla pagina Gestire le scorciatoie da tastiera per i componenti aggiuntivi in Firefox. Funzioneranno su tutte le finestre e le pagine del browser.", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "Silenzia la scheda", "description": "Mute tab" diff --git a/addon/src/_locales/ja/messages.json b/addon/src/_locales/ja/messages.json index 2759f36b..27bb1f44 100644 --- a/addon/src/_locales/ja/messages.json +++ b/addon/src/_locales/ja/messages.json @@ -270,8 +270,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "ホットキーを追加できます。
制限事項
1. これらのホットキーはウェブページ (http:, https:) でのみ機能します。ブラウザーページ (about:) では機能しません。WebExtensions API の制限によるもです。
2. いくつかのホットキーは English layout 以外のキーボードレイアウトでは機能しません。例えば、English layout で作成したホットキー Ctrl + ~ は Russian layout では動作しません。この問題を解決するには、別のホットキーを新たに作成してください。例:Russian layout にて Ctrl + Ё を作成する", - "description": "Hotkeys description" + "message": "ホットキーは、Firefox のショートカットキーの管理 ページでも設定できます。これらはすべてのウィンドウとブラウザーページで動作します。", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "ホットキーの追加", @@ -977,10 +977,6 @@ } } }, - "hotkeysDescription2": { - "message": "ホットキーは、Firefox のショートカットキーの管理 ページでも設定できます。これらはすべてのウィンドウとブラウザーページで動作します。", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "タブをミュート", "description": "Mute tab" diff --git a/addon/src/_locales/ko_KR/messages.json b/addon/src/_locales/ko_KR/messages.json index d68f60b3..9dc30309 100644 --- a/addon/src/_locales/ko_KR/messages.json +++ b/addon/src/_locales/ko_KR/messages.json @@ -253,14 +253,6 @@ "message": "컨테이너가 있는 탭을 끌어 이 그룹으로 이동", "description": "Catch and move tabs with containers to this group" }, - "regexpForTabsTitle": { - "message": "Regular expressions for catch tabs [미번역]", - "description": "Regular expressions for catch tabs" - }, - "regexpForTabsPlaceholder": { - "message": "Regular expressions [미번역]", - "description": "Regular expressions" - }, "regexpForTabsHelp": { "message": "여기에 웹 주소에 대한 정규식을 삽입하십시오. 일치하는 탭은 자동으로 이 그룹으로 이동됩니다.\n규칙당 한 줄을 사용합니다. 원하는 만큼 사용할 수 있습니다.\n예:\ngithub\\.com/drive4ik/simple-tab-groups - 애드온 저장소의 모든 페이지를 캐치\nbugzilla\\.mozilla\\.org - Firefox 버그 보고서를 캐치\n(facebook|twitter|youtube)\\.com - 모든 소셜 페이지", "description": "Regular exceptions helper" @@ -269,10 +261,6 @@ "message": "단축키", "description": "Hotkeys" }, - "hotkeysDescription": { - "message": "여기에서 단축키를 추가할 수 있습니다.
제한:
1. 이 단축키는 WebExtensions API가 이를 허용하지 않기 때문에 브라우저 페이지(about:)가 아닌 웹 페이지(http:, https:)에서만 작동합니다.
2. 일부 단축키는 모든 키보드 레이아웃에서 작동하지 않습니다. 예를 들어, 영어 레이아웃으로 생성된 Ctrl + ~ 단축키는 러시아어 레이아웃의 키보드에서 작동하지 않습니다. 러시아어 레이아웃에서 이 키에 다른 코드가 있기 때문입니다. 이 문제를 해결하려면 러시아어 레이아웃으로 다른 핫키를 만드세요. Ctrl + Ё", - "description": "Hotkeys description" - }, "addHotKeyButton": { "message": "단축키 추가", "description": "Add hotkey" @@ -887,62 +875,14 @@ "message": "컨테이너에서 URL을 열 수 없습니다", "description": "Can't open URL in container" }, - "helpPageOpenInContainerMainTitle": { - "message": "Can't open the URL into $containerName$ container (미번역)", - "description": "Can't open the URL into Personal container", - "placeholders": { - "containerName": { - "content": "$1", - "example": "Personal" - } - } - }, "helpPageOpenInContainerSubTitle": { "message": "확장 프로그램이 URL을 열 수 없습니다:", "description": "addon can't open URL:" }, - "helpPageOpenInContainerDesc1": { - "message": "Group $groupTitle$ was assigned to open tabs in $containerName$ container. (미번역)", - "description": "Group 'Group 1' was assigned to open tabs in Personal container.", - "placeholders": { - "groupTitle": { - "content": "$1", - "example": "Group 1" - }, - "containerName": { - "content": "$2", - "example": "Personal" - } - } - }, "helpPageOpenInContainerDesc2": { "message": "또 다른 확장 프로그램:", "description": "Another addon:" }, - "helpPageOpenInContainerDesc3": { - "message": "tries to open this URL in $containerName$ container. Move the tab to another group or forbid the addon $addonName$ to perform this action. (미번역)", - "description": "tries to open this URL in Business container. Move the tab to another group or forbid the addon 'Facebook Container' to perform this action.", - "placeholders": { - "containerName": { - "content": "$1", - "example": "Business" - }, - "addonName": { - "content": "$2", - "example": "Facebook Container" - } - } - }, - "helpPageOpenInContainerOpenInContainer": { - "message": "Open in $containerName$ container (미번역)", - "description": "Open in Personal container", - "placeholders": { - "containerName": { - "content": "$1", - "example": "Personal" - } - } - }, "groupNotLoaded": { "message": "그룹이 로드되지 않았습니다", "description": "Group not loaded" @@ -979,34 +919,6 @@ "message": "이 컨테이너를 제외하고", "description": "excluding these containers" }, - "helpPageOpenInContainerExcludeContainerToGroup": { - "message": "Exclude $containerName$ container for group $groupTitle$ (미번역)", - "description": "Exclude Personal container for group Group 1", - "placeholders": { - "containerName": { - "content": "$1", - "example": "Personal" - }, - "groupTitle": { - "content": "$2", - "example": "Group 1" - } - } - }, - "helpPageOpenInContainerIgnoreAppForSession": { - "message": "Ignore extension \"$addonName$\" until the browser is closed (미번역)", - "description": "Ignore addon for session", - "placeholders": { - "addonName": { - "content": "$1", - "example": "Facebook Container" - } - } - }, - "hotkeysDescription2": { - "message": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages. (미번역)", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "탭 음소거", "description": "Mute tab" diff --git a/addon/src/_locales/nl/messages.json b/addon/src/_locales/nl/messages.json index a9f298e4..cd89696c 100644 --- a/addon/src/_locales/nl/messages.json +++ b/addon/src/_locales/nl/messages.json @@ -233,10 +233,6 @@ "message": "Sneltoetsen", "description": "Hotkeys" }, - "hotkeysDescription": { - "message": "Hier kan je sneltoetsen toevoegen.
Beperkingen:
1. Deze sneltoetsen zullen alleen werken op webpagina's (http:, https:). Op de browserpagina's (about:) werken ze niet: de WebExtensions API staat dit niet toe.
2. Sommige sneltoetsen werken niet op bepaalde toetsenbordindelingen. Bijvoorbeeld: de sneltoets Ctrl + ~ aangemaakt met een Engelse toetsenbordindeling zal niet werken met een Russische toetsenbordindeling, omdat deze toets daar een andere code heeft. Om dit op te lossen, voeg je een sneltoets toe met de Russische toetsenbordindeling: Ctrl + Ё", - "description": "Hotkeys description" - }, "addHotKeyButton": { "message": "Sneltoets toevoegen", "description": "Add hotkey" diff --git a/addon/src/_locales/pl/messages.json b/addon/src/_locales/pl/messages.json index 1e945988..1058df22 100644 --- a/addon/src/_locales/pl/messages.json +++ b/addon/src/_locales/pl/messages.json @@ -278,8 +278,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "Tutaj możesz dodać skróty klawiszowe.
Ograniczenia:
1. Skróty te działają tylko na stronach internetowych (http:, https:). Na stronach przeglądarki np. (about:) - to nie działa, interfejs WebExtensions API na to nie zezwala.
2. Niektóre skróty klawiszowe nie działają w różnych układach klawiatury. Na przykład skrót utworzony w angielskim układzie Ctrl + ~ nie będzie działał na rosyjskim układzie, ponieważ w rosyjskim układzie ten klucz ma inny kod. Aby to naprawić, po prostu utwórz kolejny skrót w rosyjskim układzie: Ctrl + Ё", - "description": "Hotkeys description" + "message": "Możesz również skonfigurować skróty klawiszowe na stronie Zarządzanie skrótami klawiaturowymi w Firefox. Będą one działać we wszystkich oknach i stronach przeglądarki.", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "Dodaj skrót", @@ -1023,10 +1023,6 @@ } } }, - "hotkeysDescription2": { - "message": "Możesz również skonfigurować skróty klawiszowe na stronie Zarządzanie skrótami klawiaturowymi w Firefox. Będą one działać we wszystkich oknach i stronach przeglądarki.", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "Wycisz kartę", "description": "Mute tab" diff --git a/addon/src/_locales/pt_BR/messages.json b/addon/src/_locales/pt_BR/messages.json index 99c83f12..f4ee7e4e 100644 --- a/addon/src/_locales/pt_BR/messages.json +++ b/addon/src/_locales/pt_BR/messages.json @@ -278,8 +278,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "Aqui você pode adicionar teclas de atalho.
Restrições:
1. Estas teclas de atalho vão funcionar somente em paginas web (http:, https:). Em páginas do navegador (about:) - não vai funcionar, o WebExtensions API não permite isso.
2. Algumas teclas de atalho não vão funcioanr em teclados diferentes. Por exemplo, o atalho criado no layout Ingles Ctrl + ~ não vai funcionar no layout Russo, porque no layout Russo essa tecla tem outro código. Para corrigir isso, apenas crie outro atalho no layout russo: Ctrl + Ё", - "description": "Hotkeys description" + "message": "Você também pode configurar teclas de atalho na página Gerenciar atalhos de extensão no Firefox. Eles funcionarão em todas as janelas e páginas do navegador.", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "Adicionar tecla de atalho", @@ -1015,10 +1015,6 @@ } } }, - "hotkeysDescription2": { - "message": "Você também pode configurar teclas de atalho na página Gerenciar atalhos de extensão no Firefox. Eles funcionarão em todas as janelas e páginas do navegador.", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "Mutar aba", "description": "Mute tab" diff --git a/addon/src/_locales/ru/messages.json b/addon/src/_locales/ru/messages.json index 6d26bbf5..a648af8d 100644 --- a/addon/src/_locales/ru/messages.json +++ b/addon/src/_locales/ru/messages.json @@ -278,8 +278,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "Здесь вы можете управлять горячими клавишами для плагина.
Ограничения:
1. Эти горячие клавиши будут работать только на веб страницах (http:, https:). На защищенных страницах браузера (about:addons например) они работать не будут. Это ограничение WebExtensions API.
2. Возможно некоторые горячие клавиши могут не работать на разных раскладках клавиатуры. Например у вас есть горячая клавиша Ctrl + ~ создана на английской раскладке клавиатуры, но на русской раскладке она работать не будет, потому что клавиша Ё там имеет другой код. Для решения этой проблемы достаточно создать такую же горячую клавишу с тем же действием, только уже на русской раскладке - Ctrl + Ё.", - "description": "Hotkeys description" + "message": "Вы также можете настроить горячие клавиши на странице Управление горячими клавишами в расширениях Firefox. Они будут работать на всех окнах и страницах браузера.", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "Добавить горячую клавишу", @@ -1031,10 +1031,6 @@ } } }, - "hotkeysDescription2": { - "message": "Вы также можете настроить горячие клавиши на странице Управление горячими клавишами в расширениях Firefox. Они будут работать на всех окнах и страницах браузера.", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "Убрать звук вкладки", "description": "Mute tab" diff --git a/addon/src/_locales/sv/messages.json b/addon/src/_locales/sv/messages.json index 6c2fbe64..d667ae28 100644 --- a/addon/src/_locales/sv/messages.json +++ b/addon/src/_locales/sv/messages.json @@ -251,10 +251,6 @@ "message": "Snabbval", "description": "Hotkeys" }, - "hotkeysDescription": { - "message": "Här kan du ange snabbval.
Begränsningar
1. Snabbbvalen fungerar endast på webbsidor (http://, https://). På grund av begränsningar i WebExtensions API:t fungerar de inte på webbläsarens egna sidor (about:).
2. Alla snabbvalskombinationer fungerar inte med alla typer av tangentbordslayouter. Till exempel: snabbvalet Ctrl + ~ skapat för engelsk layout fungerar inte med ett tangentbord med rysk layout, eftersom kombinationen med ett ryskt tangentbord ger en annan kod.", - "description": "Hotkeys description" - }, "addHotKeyButton": { "message": "Lägg till snabbval", "description": "Add hotkey" diff --git a/addon/src/_locales/tr_TR/messages.json b/addon/src/_locales/tr_TR/messages.json index d5863ab0..7891e14b 100644 --- a/addon/src/_locales/tr_TR/messages.json +++ b/addon/src/_locales/tr_TR/messages.json @@ -269,10 +269,6 @@ "message": "Kısayollar", "description": "Hotkeys" }, - "hotkeysDescription": { - "message": "Burada kısayol tuşları ekleyebilirsiniz.
Kısıtlamalar:
1. Bu kısayol tuşları yalnızca web sayfalarında çalışır (http:, https:), tarayıcı sayfalarında değil (about:) çünkü WebExtensions API buna izin vermiyor.
2. Bazı kısayol tuşları tüm klavye düzenleriyle çalışmayacaktır. Örneğin, İngilizce bir düzende oluşturulmuş bir Ctrl + ~ kısayolu, Rusça yerleşimli bir klavyede çalışmaz, çünkü Rusça düzeninde bu tuşun başka bir kodu vardır. Bunu düzeltmek için, Rusça düzen ile başka bir kısayol tuşu oluşturun: Ctrl + Ё", - "description": "Hotkeys description" - }, "addHotKeyButton": { "message": "Kısayol ekle", "description": "Add hotkey" diff --git a/addon/src/_locales/uk/messages.json b/addon/src/_locales/uk/messages.json index 4e07f3f8..66a47b5b 100644 --- a/addon/src/_locales/uk/messages.json +++ b/addon/src/_locales/uk/messages.json @@ -278,8 +278,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "Тут ви можете управляти гарячими клавішами для плагіна.
Обмеження:
1. Ці гарячі клавіші будуть працювати тільки на веб сторінках (http:, https:). На захищених сторінках браузера (about: addons наприклад) вони працювати не будуть. Це обмеження WebExtensions API.
2. Можливо деякі гарячі клавіші можуть не працювати на різних розкладках клавіатури. Наприклад у вас є гаряча клавіша Ctrl + Е створена на англійській розкладці клавіатури, але в українській розкладці вона працювати не буде, тому що клавіша Е в ній має інший код. Для вирішення цієї проблеми досить створити таку ж гарячу клавішу з тією ж дією, тільки вже в українській розкладці - Ctrl + Е.", - "description": "Hotkeys description" + "message": "Ви також можете налаштувати гарячі клавіші на сторінці Управління гарячими клавішами в розширеннях Firefox . Вони будуть працювати на всіх вікнах і сторінках браузера.", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "Додати гарячу клавішу", @@ -1031,10 +1031,6 @@ } } }, - "hotkeysDescription2": { - "message": "Ви також можете налаштувати гарячі клавіші на сторінці Управління гарячими клавішами в розширеннях Firefox . Вони будуть працювати на всіх вікнах і сторінках браузера.", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "Вимкнути звук вкладки", "description": "Mute tab" diff --git a/addon/src/_locales/zh_CN/messages.json b/addon/src/_locales/zh_CN/messages.json index 3407d0c5..61a33263 100644 --- a/addon/src/_locales/zh_CN/messages.json +++ b/addon/src/_locales/zh_CN/messages.json @@ -278,8 +278,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "在这里,你可以添加快捷键。
【限制】
1. 这些快捷键只在网页中生效(网址协议为http:、https:)。而在浏览器页面(about:)则无法工作,因为 WebExtensions 的 API 不允许如此。
2. 某些快捷键会在不同的键盘布局中无法工作。例如,在英语布局中创建的 Ctrl + ~ ,在俄语布局中则无法工作,因为在后者中这个按键有另外的编码。要修复这个问题,你只要在后者中再创建一个快捷键 Ctrl + Ё。", - "description": "Hotkeys description" + "message": "您也可以在页面配置快捷键。它们可以在所有窗口和浏览器页面工作。", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "添加快捷键", @@ -1011,10 +1011,6 @@ } } }, - "hotkeysDescription2": { - "message": "您也可以在页面配置快捷键。它们可以在所有窗口和浏览器页面工作。", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "静音标签页", "description": "Mute tab" diff --git a/addon/src/_locales/zh_TW/messages.json b/addon/src/_locales/zh_TW/messages.json index 2fb392c2..deb58f94 100644 --- a/addon/src/_locales/zh_TW/messages.json +++ b/addon/src/_locales/zh_TW/messages.json @@ -278,8 +278,8 @@ "description": "Hotkeys" }, "hotkeysDescription": { - "message": "可以在這裡新增快速鍵。
限制:
1. 這些快速鍵只適用於網頁 (http:, https:),不適用於瀏覽器頁面 (about:),因 WebExtension 的 API 不允許。
2. 有些快速鍵在不同的鍵盤配置可能無法運作。例如英文配置下設定的快速鍵 Ctrl + ~ 在俄羅斯文配置下無法運作,因為此按鍵在後者有不同的按鍵碼;在俄羅斯文配置下設定快速鍵 Ctrl +Ё 即可修復此問題。", - "description": "Hotkeys description" + "message": "也可以在
Manage extension shortcuts in Firefox 設定全域快速鍵。", + "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." }, "addHotKeyButton": { "message": "新增快速鍵", @@ -1023,10 +1023,6 @@ } } }, - "hotkeysDescription2": { - "message": "也可以在 Manage extension shortcuts in Firefox 設定全域快速鍵。", - "description": "You can also configure hotkeys on the Manage extension shortcuts in Firefox page. They will work on all windows and browser pages." - }, "muteTab": { "message": "分頁靜音", "description": "Mute tab" diff --git a/addon/src/js/constants.js b/addon/src/js/constants.js index 19a136f5..436705e5 100644 --- a/addon/src/js/constants.js +++ b/addon/src/js/constants.js @@ -4,6 +4,8 @@ export const STG_BASE_URL = browser.runtime.getURL(''); export const IS_BACKGROUND_PAGE = self.location.href.startsWith(MANIFEST.background.page); +export const IS_MAC = (navigator.userAgentData?.platform || navigator.platform || '').toLowerCase().includes('mac'); + export const ACTIVE_SYMBOL = '〇'; export const DISCARDED_SYMBOL = '✱'; export const STICKY_SYMBOL = '📌'; @@ -323,22 +325,11 @@ export const DEFAULT_OPTIONS = Object.freeze({ hotkeys: [ { - ctrlKey: true, - shiftKey: false, - altKey: false, - metaKey: false, - key: '`', - keyCode: 192, // TODO + value: `${IS_MAC ? 'Mac' : ''}Ctrl+Backquote`, action: 'load-next-group', groupId: 0, - }, - { - ctrlKey: true, - shiftKey: true, - altKey: false, - metaKey: false, - key: '`', - keyCode: 192, + }, { + value: `${IS_MAC ? 'Mac' : ''}Ctrl+Shift+Backquote`, action: 'load-prev-group', groupId: 0, }, diff --git a/addon/src/js/groups.js b/addon/src/js/groups.js index 79aba960..5a5532a4 100644 --- a/addon/src/js/groups.js +++ b/addon/src/js/groups.js @@ -846,25 +846,25 @@ export function getTitle({id, title, isArchive, isSticky, tabs, iconViewType, ne title = beforeTitle.join(' ') + ' ' + title; } - tabs = tabs.slice(); - if (withCountTabs) { - title += ' (' + tabsCountMessage(tabs, isArchive) + ')'; + title += ' (' + tabsCountMessage(tabs.slice(), isArchive) + ')'; } - if (withTabs && tabs.length) { - title += ':\n' + tabs - .slice(0, 30) - .map(tab => Tabs.getTitle(tab, false, 70, !isArchive)) - .join('\n'); - - if (tabs.length > 30) { - title += '\n...'; + if (withTabs) { + if (tabs.length) { + title += ':\n' + tabs + .slice(0, 30) + .map(tab => Tabs.getTitle(tab, false, 70, !isArchive)) + .join('\n'); + + if (tabs.length > 30) { + title += '\n...'; + } } } if (window.localStorage.enableDebug) { - let windowId = Cache.getWindowId(id) || tabs[0]?.windowId || 'no window'; + let windowId = Cache.getWindowId(id) || tabs?.[0]?.windowId || 'no window'; title = `@${windowId}:#${id} ${title}`; } diff --git a/addon/src/js/hotkeys.js b/addon/src/js/hotkeys.js new file mode 100644 index 00000000..5a955cf5 --- /dev/null +++ b/addon/src/js/hotkeys.js @@ -0,0 +1,102 @@ + +const IS_MAC = (navigator.userAgentData?.platform || navigator.platform || '').toLowerCase().includes('mac'); + +const mapValue = value => [value, value]; + +export const NOT_SUPPORTED_CODE_KEYS = new Set([ + 'Tab', 'CapsLock', 'Escape', 'Backspace', 'NumLock', 'OSLeft', 'OSRight', +]); + +const FunctionalKeysRegExp = /^F([0-9]|1[0-2])$/; + +const codeKeyMap = new Map([ + // digits + ...Array.from({length: 10}, (n, i) => [`Digit${i}`, i]), + ...Array.from({length: 10}, (n, i) => [`Numpad${i}`, i]), + + // Functional keys + ...Array.from({length: 12}, (n, i) => `F${i + 1}`).map(mapValue), + + // alphabet + ...Array.from({length: 26}, (n, i) => String.fromCharCode(i + 65)).map(char => [`Key${char}`, char]), + + ...['Home', 'End', 'PageUp', 'PageDown', 'Insert', 'Delete', 'Space', 'Comma', 'Period', 'Quote', 'Backquote', 'Semicolon', 'Slash', 'Backslash', 'Enter', 'Equal', 'Minus'].map(mapValue), + + ['NumpadEnter', 'Enter'], + + ['NumpadDecimal', 'Decimal'], + ['NumpadSubtract', 'Subtract'], + ['NumpadMultiply', 'Multiply'], + ['NumpadDivide', 'Divide'], + + ['ArrowUp', 'Up'], + ['ArrowDown', 'Down'], + ['ArrowLeft', 'Left'], + ['ArrowRight', 'Right'], + + ...['MediaPlayPause', 'MediaStop'].map(mapValue), + ['MediaTrackNext', 'MediaNextTrack'], + ['MediaTrackPrevious', 'MediaPrevTrack'], +]); + +function normalizeEventKey({code}) { + return codeKeyMap.get(code); +} + +function isFuncKeyValue(value) { + return FunctionalKeysRegExp.test(value); +} + +export function isValidHotkeyEvent(event) { + if (!event.ctrlKey && !event.altKey && !event.metaKey) { + return isFuncKeyValue(event.code); + } + + if (!normalizeEventKey(event)) { + return false; + } + + return true; +} + +export function isValidHotkeyValue(value) { + const parts = value.split('+'); + return (parts.length >= 2 && parts.every(key => key)) || isFuncKeyValue(value); +} + +// Command ???? хз +export function nomalizeValueForPlatform(value) { + if (IS_MAC && value.startsWith('Ctrl')) { + return value.replace('Ctrl', 'MacCtrl'); + } else if (!IS_MAC && value.startsWith('MacCtrl')) { + return value.replace('MacCtrl', 'Ctrl'); + } + + return value; +} + +export function eventToHotkeyValue(event) { + const valueParts = []; + + if (event.ctrlKey) { + valueParts.push(IS_MAC ? 'MacCtrl' : 'Ctrl'); + } + + if (event.metaKey) { + valueParts.push('Command'); + } + + if (event.altKey) { + valueParts.push('Alt'); + } + + if (event.shiftKey) { + valueParts.push('Shift'); + } + + const normalizedKey = normalizeEventKey(event); + + valueParts.push(normalizedKey || ''); + + return valueParts.join('+'); +} diff --git a/addon/src/js/utils.js b/addon/src/js/utils.js index cacd0e1c..3da36a47 100644 --- a/addon/src/js/utils.js +++ b/addon/src/js/utils.js @@ -12,6 +12,8 @@ const tagsToReplace = { const INNER_HTML = 'innerHTML'; +export const IS_MAC = (navigator.userAgentData?.platform || navigator.platform || '').toLowerCase().includes('mac'); + export function unixNow() { return Math.round(Date.now() / 1000); } @@ -470,7 +472,7 @@ export function normalizeGroupIcon(iconUrl) { } export function resizeImage(img, height, width, useTransparency = true, ...canvasParams) { // img: new Image() - let canvas = document.createElement('canvas'), + const canvas = document.createElement('canvas'), context = canvas.getContext('2d'); if (!useTransparency) { @@ -486,7 +488,7 @@ export function resizeImage(img, height, width, useTransparency = true, ...canva } function isCanvasBlank(canvas, useTransparency, ...canvasParams) { - let blank = document.createElement('canvas'), + const blank = document.createElement('canvas'), canvasDataUrl = canvas.toDataURL(...canvasParams); if (!useTransparency) { @@ -499,7 +501,7 @@ function isCanvasBlank(canvas, useTransparency, ...canvasParams) { let isEmpty = canvasDataUrl === blank.toDataURL(...canvasParams); if (!isEmpty) { - let blankContext = blank.getContext('2d'); + const blankContext = blank.getContext('2d'); blankContext.fillStyle = 'rgb(255, 255, 255)'; blankContext.fillRect(0, 0, blank.width, blank.height); @@ -570,20 +572,20 @@ export function compareVersions(a, b) { return 0; } - let regExStrip0 = /(\.0+)+$/, + const regExStrip0 = /(\.0+)+$/, segmentsA = a.replace(regExStrip0, '').split('.'), segmentsB = b.replace(regExStrip0, '').split('.'), l = Math.min(segmentsA.length, segmentsB.length); for (let i = 0; i < l; i++) { - let diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10); + const diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10); if (diff) { return diff > 0 ? 1 : -1; } } - let diff = segmentsA.length - segmentsB.length; + const diff = segmentsA.length - segmentsB.length; if (diff) { return diff > 0 ? 1 : -1; diff --git a/addon/src/manifest.json b/addon/src/manifest.json index c1e8accb..c42fa14b 100644 --- a/addon/src/manifest.json +++ b/addon/src/manifest.json @@ -59,8 +59,8 @@ "content_scripts": [ { "matches": [""], - "js": ["web/hotkeys.js"], - "css": ["web/hotkeys.css"], + "js": ["web/content-script.js"], + "css": ["web/content-script.css"], "match_about_blank": true, "run_at": "document_start" } diff --git a/addon/src/options/Options.vue b/addon/src/options/Options.vue index 3e6cec62..6fa0fce3 100644 --- a/addon/src/options/Options.vue +++ b/addon/src/options/Options.vue @@ -15,6 +15,7 @@ import * as File from 'file'; import * as Urls from 'urls'; import * as Groups from 'groups'; + import {isValidHotkeyEvent, isValidHotkeyValue, eventToHotkeyValue} from 'hotkeys'; import JSON from 'json'; import defaultGroupMixin from 'default-group.mixin'; @@ -26,7 +27,6 @@ const SECTION_GENERAL = 'general', SECTION_HOTKEYS = 'hotkeys', SECTION_BACKUP = 'backup', - funcKeys = [...Array(12).keys()].map(n => KeyEvent[`DOM_VK_F${n + 1}`]), folderNameRegExp = /[\<\>\:\"\/\\\|\?\*\x00-\x1F]|^(?:aux|con|nul|prn|com\d|lpt\d)$|^\.+|\.+$/gi; document.title = browser.i18n.getMessage('openSettings'); @@ -34,18 +34,17 @@ export default { mixins: [defaultGroupMixin], data() { - return { - SECTION_GENERAL, - SECTION_HOTKEYS, - SECTION_BACKUP, - - section: window.localStorage.optionsSection || SECTION_GENERAL, + this.HOTKEY_ACTIONS = Constants.HOTKEY_ACTIONS; + this.HOTKEY_ACTIONS_WITH_CUSTOM_GROUP = Constants.HOTKEY_ACTIONS_WITH_CUSTOM_GROUP; + this.GROUP_ICON_VIEW_TYPES = Constants.GROUP_ICON_VIEW_TYPES; + this.AUTO_BACKUP_INTERVAL_KEY = Constants.AUTO_BACKUP_INTERVAL_KEY; - HOTKEY_ACTIONS: Constants.HOTKEY_ACTIONS, - HOTKEY_ACTIONS_WITH_CUSTOM_GROUP: Constants.HOTKEY_ACTIONS_WITH_CUSTOM_GROUP, + this.SECTION_GENERAL = SECTION_GENERAL; + this.SECTION_HOTKEYS = SECTION_HOTKEYS; + this.SECTION_BACKUP = SECTION_BACKUP; - GROUP_ICON_VIEW_TYPES: Constants.GROUP_ICON_VIEW_TYPES, - AUTO_BACKUP_INTERVAL_KEY: Constants.AUTO_BACKUP_INTERVAL_KEY, + return { + section: window.localStorage.optionsSection || SECTION_GENERAL, contextMenuTabTitles: { 'open-in-new-window': { @@ -128,7 +127,6 @@ options: {}, groups: [], - isMac: false, manageAddonSettings: null, manageAddonSettingsTitle: '', @@ -152,9 +150,6 @@ 'manage-addon-backup': manageAddonBackup, }, async created() { - const {os} = await browser.runtime.getPlatformInfo(); - this.isMac = os === browser.runtime.PlatformOs.MAC; - const data = await Storage.get(); const options = Utils.assignKeys({}, data, Constants.ALL_OPTIONS_KEYS); @@ -241,41 +236,36 @@ }, 'options.hotkeys': { handler(hotkeys, oldValue) { - if (!hotkeys) { - return; - } - - let beforeLength = hotkeys.length, - hasChange = false; + let hasChange = false; hotkeys = hotkeys.filter((hotkey, index, self) => { - if (!hotkey.action) { + if (!hotkey.action || !isValidHotkeyValue(hotkey.value)) { return false; } - if (!hotkey.keyCode && !hotkey.key) { - return false; + if ( + Constants.HOTKEY_ACTIONS_WITH_CUSTOM_GROUP.includes(hotkey.action) && + hotkey.groupId && + !this.groups.some(gr => gr.id === hotkey.groupId) + ) { + hotkey.groupId = 0; + hasChange = true; } - if (!(hotkey.ctrlKey || hotkey.shiftKey || hotkey.altKey || hotkey.metaKey || funcKeys.includes(hotkey.keyCode))) { - return false; - } + const leaveHotkey = self.findIndex(h => h.value === hotkey.value) === index; - if (Constants.HOTKEY_ACTIONS_WITH_CUSTOM_GROUP.includes(hotkey.action) && hotkey.groupId && !this.groups.some(gr => gr.id === hotkey.groupId)) { - hotkey.groupId = 0; + if (!leaveHotkey) { hasChange = true; } - return self.findIndex(h => Object.keys(hotkey).every(key => hotkey[key] === h[key])) === index; + return leaveHotkey; }); - if (!oldValue && hotkeys.length === beforeLength && !hasChange) { + if (!hasChange) { return; } - Messages.sendMessageModule('BG.saveOptions', { - hotkeys: hotkeys, - }); + Messages.sendMessageModule('BG.saveOptions', {hotkeys}); }, deep: true, }, @@ -303,19 +293,34 @@ }, openBackupFolder: File.openBackupFolder, + getGroupTitle: Groups.getTitle, + + getHotkeyParentNode(event) { + return event.target.closest('.control'); + }, + + onBlurHotkey(event) { + const inputParent = this.getHotkeyParentNode(event); + + inputParent.classList.remove('key-success'); + }, saveHotkeyKeyCodeAndStopEvent(hotkey, event, withKeyCode) { event.preventDefault(); event.stopPropagation(); event.stopImmediatePropagation(); - if (!event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) { - hotkey.key = event.key.length === 1 ? event.key.toUpperCase() : event.key; + const inputParent = this.getHotkeyParentNode(event); - if (withKeyCode) { - hotkey.keyCode = event.keyCode; - } + if (isValidHotkeyEvent(event)) { + inputParent.classList.add('key-success'); + inputParent.classList.remove('key-error'); + } else { + inputParent.classList.add('key-error'); + inputParent.classList.remove('key-success'); } + + hotkey.value = eventToHotkeyValue(event); }, setManageAddonSettings(data, popupTitle, disableEmptyGroups = false, allowClearAddonDataBeforeRestore = false) { @@ -592,12 +597,7 @@ createHotkey() { return { - ctrlKey: false, - shiftKey: false, - altKey: false, - metaKey: false, - key: '', - keyCode: 0, + value: '', action: '', groupId: 0, }; @@ -625,7 +625,8 @@ } }, - getGroupIconUrl(group) { + getGroupIconUrl(groupId) { + const group = this.groups.find(gr => gr.id === groupId); return Groups.getIconUrl(group); }, @@ -847,30 +848,11 @@
-
- - - -
- +
- +
- - + +
@@ -1214,6 +1196,25 @@ width: 300px; } + .hotkeys { + .control .input { + width: 15em; + ime-mode: disabled; + } + .control:not(.key-success):not(.key-error) .input:focus { + --in-content-border-focus: transparent; + outline: 2px solid dodgerblue; + } + .control.key-success .input:focus { + --in-content-border-focus: transparent; + outline: 2px solid limegreen; + } + .control.key-error .input { + --in-content-border-focus: transparent; + outline: 2px solid orangered; + } + } + .hotkeys > .field { &:not(:last-child) { border-bottom: 1px solid var(--color-hr); diff --git a/addon/src/stg-background.js b/addon/src/stg-background.js index 300fadf4..441c0f2e 100644 --- a/addon/src/stg-background.js +++ b/addon/src/stg-background.js @@ -14,6 +14,7 @@ import * as Groups from './js/groups.js'; import * as Tabs from './js/tabs.js'; import * as Windows from './js/windows.js'; import * as Management from './js/management.js'; +import * as Hotkeys from './js/hotkeys.js'; self.IS_TEMPORARY = false; @@ -2699,9 +2700,10 @@ async function saveOptions(_options) { const tabs = await Tabs.get(null, null, null, { discarded: false, }), - actionData = { + actionData = JSON.clone({ action: 'update-hotkeys', - }; + hotkeys: options.hotkeys, + }); tabs.forEach(tab => Tabs.sendMessage(tab.id, actionData)); } @@ -2863,9 +2865,7 @@ async function restoreBackup(data, clearAddonDataBeforeRestore = false) { await loadingBrowserAction(); - const {os} = await browser.runtime.getPlatformInfo(), - isMac = os === browser.runtime.PlatformOs.MAC, - currentData = {}; + const currentData = {}; let {lastCreatedGroupPosition} = await Storage.get('lastCreatedGroupPosition'); @@ -2917,9 +2917,7 @@ async function restoreBackup(data, clearAddonDataBeforeRestore = false) { data.groups ??= []; data.hotkeys ??= []; - if (!isMac) { - data.hotkeys.forEach(hotkey => hotkey.metaKey = false); - } + data.hotkeys.forEach(hotkey => hotkey.value = Hotkeys.nomalizeValueForPlatform(hotkey.value)); data.groups.forEach(groupToRestore => { if (!currentData.groups.some(currentGroup => currentGroup.id === groupToRestore.moveToGroupIfNoneCatchTabRules)) { @@ -3666,6 +3664,7 @@ async function runMigrateForData(data) { { version: '5.1.1', async migration() { + // migrate groups const mainGroupId = data.groups.find(group => group.isMain)?.id; data.groups.forEach(group => { @@ -3678,6 +3677,62 @@ async function runMigrateForData(data) { delete group.isMain; delete group.moveToMainIfNotInCatchTabRules; }); + + // migrate hotkeys + const keysMap = new Map([ + [110, 'Decimal'], + [109, 'Subtract'], + [106, 'Multiply'], + [111, 'Divide'], + [222, 'Quote'], + [192, 'Backquote'], + [13, 'Enter'], + [191, 'Slash'], + [220, 'Backslash'], + [61, 'Equal'], + [173, 'Minus'], + [32, 'Space'], + [188, 'Comma'], + [190, 'Period'], + [59, 'Semicolon'], + + ...['Home', 'End', 'PageUp', 'PageDown', 'Insert', 'Delete', 'Enter'].map(value => [value, value]), + ]); + + function normalizeHotkeyKey({key, keyCode}) { + return keysMap.get(keyCode) || keysMap.get(key) || key.toUpperCase(); + } + + data.hotkeys.forEach(hotkey => { + const valueParts = []; + + if (hotkey.ctrlKey) { + valueParts.push(IS_MAC ? 'MacCtrl' : 'Ctrl'); + } + + if (hotkey.metaKey) { + valueParts.push('Command'); + } + + if (hotkey.altKey) { + valueParts.push('Alt'); + } + + if (hotkey.shiftKey) { + valueParts.push('Shift'); + } + + valueParts.push(normalizeHotkeyKey(hotkey)); + + hotkey.value = valueParts.join('+'); + + delete hotkey.ctrlKey; + delete hotkey.shiftKey; + delete hotkey.altKey; + delete hotkey.metaKey; + delete hotkey.key; + delete hotkey.keyCode; + }); }, }, ]; diff --git a/addon/src/web/hotkeys.js b/addon/src/web/content-script.js similarity index 67% rename from addon/src/web/hotkeys.js rename to addon/src/web/content-script.js index 45a86acb..eccc883d 100644 --- a/addon/src/web/hotkeys.js +++ b/addon/src/web/content-script.js @@ -1,103 +1,88 @@ 'use strict'; -import './move-tab-popup.scss'; -import Messages from '../js/messages.js'; +import './select-group-popup.scss'; +import {isValidHotkeyEvent, eventToHotkeyValue, NOT_SUPPORTED_CODE_KEYS} from '../js/hotkeys.js'; -let errorCounter = 0, - hotkeys = [], +let hotkeys = [], foundHotKey = false; -const POPUP_ID = 'stg-move-tab-to-group-popup-wrapper'; +const POPUP_ID = 'stg-select-group-popup-wrapper'; -browser.runtime.onMessage.addListener(changeHotkeysListener); +browser.runtime.onMessage.addListener(onMessageListener); -window.addEventListener('unload', unsubscribeAllListeners); +// window.addEventListener('unload', unsubscribeAllListeners); -init(); - -async function init() { - removeWindowListeners(); - - let result = null; +loadHotkeys(); +addWindowListeners(); +async function loadHotkeys(errorCounter = 0) { try { - result = await browser.storage.local.get({hotkeys}); - - if (!result) { - throw Error; - } + ({hotkeys} = await browser.storage.local.get({hotkeys})); } catch (e) { errorCounter++; if (errorCounter < 100) { - setTimeout(init, 200); + setTimeout(loadHotkeys, 200, errorCounter); } else { console.error('[STG] can\'t load hotkeys from storage'); - errorCounter = 0; } - - return; - } - - hotkeys = result.hotkeys; - - if (hotkeys.length) { - addWindowListeners(); } } -function changeHotkeysListener(request) { +function onMessageListener(request) { if (request.action === 'update-hotkeys') { - init(); + hotkeys = request.hotkeys; } else if (request.action === 'show-groups-popup') { - showGroupsPopup(request); + if (foundHotKey) { + setTimeout(onMessageListener, 100, request); + } else { + showGroupsPopup(request); + } } else if (request.action === 'show-prompt') { return showPrompt(request); } } -function removeWindowListeners() { - window.removeEventListener('keydown', checkKey); - window.removeEventListener('keyup', resetFoundHotKey); -} +// function removeWindowListeners() { +// window.removeEventListener('keydown', checkKey); +// window.removeEventListener('keyup', resetFoundHotKey); +// } function addWindowListeners() { window.addEventListener('keydown', checkKey); window.addEventListener('keyup', resetFoundHotKey); } -function unsubscribeAllListeners() { - removeWindowListeners(); - browser.runtime.onMessage.removeListener(changeHotkeysListener); -} +// function unsubscribeAllListeners() { +// removeWindowListeners(); +// browser.runtime.onMessage.removeListener(onMessageListener); +// } function resetFoundHotKey() { foundHotKey = false; } -function checkKey(e) { - if (foundHotKey || [KeyEvent.DOM_VK_SHIFT, KeyEvent.DOM_VK_CONTROL, KeyEvent.DOM_VK_ALT, KeyEvent.DOM_VK_META].includes(e.keyCode)) { // not track only auxiliary keys +function checkKey(event) { + if ( + foundHotKey || + !hotkeys.length || + event.repeat || + NOT_SUPPORTED_CODE_KEYS.has(event.code) || + document.getElementById(POPUP_ID) || + !isValidHotkeyEvent(event) + ) { return; } - hotkeys.some(function(hotkey) { - if (hotkey.ctrlKey === e.ctrlKey && - hotkey.shiftKey === e.shiftKey && - hotkey.altKey === e.altKey && - hotkey.metaKey === e.metaKey && - ( - (hotkey.keyCode && hotkey.keyCode === e.keyCode) || - (!hotkey.keyCode && !e.keyCode && hotkey.key.toUpperCase() === e.key.toUpperCase()) - ) - ) { + const hotkeyValue = eventToHotkeyValue(event); + + hotkeys.some(hotkey => { + if (hotkeyValue === hotkey.value) { foundHotKey = true; - stopEvent(e); + stopEvent(event); - Messages.sendMessage(hotkey.action, { - groupId: hotkey.groupId, - }) - .then(() => foundHotKey = false); + browser.runtime.sendMessage(hotkey).catch(() => {}); return true; } @@ -107,7 +92,6 @@ function checkKey(e) { function stopEvent(e) { e.preventDefault(); e.stopPropagation(); - e.stopImmediatePropagation(); } function showGroupsPopup(data) { @@ -115,7 +99,7 @@ function showGroupsPopup(data) { return; } - let wrapper = document.createElement('div'), + const wrapper = document.createElement('div'), closeGroupsPopup = wrapper.remove.bind(wrapper), isDark = window.matchMedia('(prefers-color-scheme: dark)').matches; @@ -124,15 +108,15 @@ function showGroupsPopup(data) { Object.assign(wrapper, { id: POPUP_ID, onclick: closeGroupsPopup, - onkeydown: ({keyCode}) => KeyEvent.DOM_VK_ESCAPE === keyCode ? closeGroupsPopup() : null, + onkeydown: ({code}) => code === 'Escape' ? closeGroupsPopup() : null, }); document.body.append(wrapper); - let main = document.createElement('div'); + const main = document.createElement('div'); main.classList.add('stg-popup-main'); wrapper.append(main); - let header = document.createElement('div'); + const header = document.createElement('div'); header.classList = 'stg-popup-has-text stg-popup-header'; Object.assign(header, { tabIndex: -1, @@ -143,38 +127,38 @@ function showGroupsPopup(data) { return; } - if (KeyEvent.DOM_VK_DOWN === e.keyCode) { + if (e.code === 'ArrowDown') { setFocusToNextElement(groupsWrapper.lastElementChild, 'down', e); - } else if (KeyEvent.DOM_VK_UP === e.keyCode) { + } else if (e.code === 'ArrowUp') { setFocusToNextElement(groupsWrapper.firstElementChild, 'up', e); } }, }); main.append(header); - let groupsWrapper = document.createElement('div'); + const groupsWrapper = document.createElement('div'); groupsWrapper.classList.add('stg-popup-groups-wrapper'); main.append(groupsWrapper); function checkUpDownKeys(e) { - if ([KeyEvent.DOM_VK_PAGE_UP, KeyEvent.DOM_VK_HOME].includes(e.keyCode)) { + if (['PageUp', 'Home'].includes(e.code)) { setFocusToNextElement(groupsWrapper.lastElementChild, 'down', e); return true; - } else if ([KeyEvent.DOM_VK_PAGE_DOWN, KeyEvent.DOM_VK_END].includes(e.keyCode)) { + } else if (['PageDown', 'End'].includes(e.code)) { setFocusToNextElement(groupsWrapper.firstElementChild, 'up', e); return true; } } function createGroupNode(group, isEnabled) { - let groupNode = document.createElement('div'); + const groupNode = document.createElement('div'); groupNode.dataset.groupId = group.id; groupNode.classList.add('stg-popup-group'); - let imgNode = document.createElement('img'); + const imgNode = document.createElement('img'); imgNode.src = group.iconUrl.startsWith('/icons') ? browser.runtime.getURL(group.iconUrl) : group.iconUrl; - let figureNode = document.createElement('figure'); + const figureNode = document.createElement('figure'); figureNode.classList = 'group-icon'; group.isSticky && figureNode.classList.add('is-sticky'); figureNode.append(imgNode); @@ -182,13 +166,13 @@ function showGroupsPopup(data) { groupNode.append(figureNode); if (group.contextualIdentity) { - let containerImgNode = document.createElement('img'); + const containerImgNode = document.createElement('img'); containerImgNode.title = group.contextualIdentity.name; containerImgNode.src = group.contextualIdentity.iconUrl; containerImgNode.style.fill = group.contextualIdentity.colorCode; - let containerFigureNode = document.createElement('figure'); + const containerFigureNode = document.createElement('figure'); containerFigureNode.classList = 'container-icon'; containerFigureNode.append(containerImgNode); @@ -204,7 +188,7 @@ function showGroupsPopup(data) { groupNode.append(archiveImgNode); }*/ - let titleNode = document.createElement('span'); + const titleNode = document.createElement('span'); titleNode.innerText = group.title; titleNode.classList.add('stg-popup-has-text'); groupNode.append(titleNode); @@ -215,7 +199,7 @@ function showGroupsPopup(data) { groupNode.onmouseover = () => groupsWrapper.contains(document.activeElement) && header.focus(); groupNode.onclick = function(sendData) { - Messages.sendMessage(sendData).catch(e => console.error(e)); + browser.runtime.sendMessage(sendData).catch(() => {}); closeGroupsPopup(); }.bind(null, { ...data, @@ -228,14 +212,14 @@ function showGroupsPopup(data) { return; } - if (e.key === 'Enter' || e.code === 'Space') { + if (e.code.includes('Enter') || e.code === 'Space') { stopEvent(e); groupNode.click(); - } else if (e.key === 'Tab') { + } else if (e.code === 'Tab') { setFocusToNextElement(groupNode, e.shiftKey ? 'up' : 'down', e); - } else if (e.key === 'ArrowDown') { + } else if (e.code === 'ArrowDown') { setFocusToNextElement(groupNode, 'down', e); - } else if (e.key === 'ArrowUp') { + } else if (e.code === 'ArrowUp') { setFocusToNextElement(groupNode, 'up', e); } }; @@ -256,8 +240,9 @@ function showGroupsPopup(data) { stopEvent(eventToStop); } - let nodes = Array.from(groupsWrapper.children).filter(n => !n.classList.contains('stg-popup-disabled')), - nodeIndex = nodes.indexOf(node); + const nodes = Array.from(groupsWrapper.children).filter(n => !n.classList.contains('stg-popup-disabled')); + + let nodeIndex = nodes.indexOf(node); if ('down' === vector) { nodeIndex++; @@ -289,7 +274,7 @@ function showGroupsPopup(data) { data.groups.forEach(group => groupsWrapper.append(createGroupNode(group, !data.disableGroupIds.includes(group.id)))); if (true !== data.disableNewGroupItem) { - let newGroupNode = createGroupNode({ + const newGroupNode = createGroupNode({ id: 'new', title: browser.i18n.getMessage('createNewGroup'), iconUrl: browser.runtime.getURL('/icons/group-new.svg'), @@ -313,7 +298,7 @@ function showGroupsPopup(data) { } }); } else { - let hoveredElements = document.querySelectorAll(':hover'); + const hoveredElements = document.querySelectorAll(':hover'); if (groupsWrapper.contains(hoveredElements[hoveredElements.length - 1])) { header.focus(); diff --git a/addon/src/web/move-tab-popup.scss b/addon/src/web/select-group-popup.scss similarity index 96% rename from addon/src/web/move-tab-popup.scss rename to addon/src/web/select-group-popup.scss index 56cc1d5b..52bb3caf 100644 --- a/addon/src/web/move-tab-popup.scss +++ b/addon/src/web/select-group-popup.scss @@ -1,7 +1,7 @@ // reset styles -#stg-move-tab-to-group-popup-wrapper, -#stg-move-tab-to-group-popup-wrapper div { +#stg-select-group-popup-wrapper, +#stg-select-group-popup-wrapper div { width: unset; margin: unset; padding: unset; @@ -10,7 +10,7 @@ box-shadow: unset; } -#stg-move-tab-to-group-popup-wrapper { +#stg-select-group-popup-wrapper { position: fixed; left: 0; top: 0; diff --git a/addon/webpack.config.mjs b/addon/webpack.config.mjs index 5e9d64f5..d9a5002d 100644 --- a/addon/webpack.config.mjs +++ b/addon/webpack.config.mjs @@ -27,7 +27,7 @@ export default { 'popup/popup': './popup/popup.js', 'options/options': './options/options.js', 'manage/manage': './manage/manage.js', - 'web/hotkeys': './web/hotkeys.js', + 'web/content-script': './web/content-script.js', }, experiments: { outputModule: true, @@ -57,6 +57,7 @@ export default { utils: '/js/utils.js', json: '/js/json.js', storage: '/js/storage.js', + hotkeys: '/js/hotkeys.js', // vue mixins 'default-group.mixin': '/js/mixins/default-group.mixin.js', @@ -141,6 +142,7 @@ export default { 'js/tabs.js', 'js/windows.js', 'js/management.js', + 'js/hotkeys.js', 'js/mixins',