From cc8eb89ce0cccf4c3feed2d6b06037724a9123d9 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 16 Oct 2020 17:44:03 -0500 Subject: [PATCH] Add keyboard shortcut to scroll current item to the top --- locale/translations.go | 33 +++++++++++++++++++++----------- locale/translations/de_DE.json | 1 + locale/translations/en_US.json | 1 + locale/translations/es_ES.json | 1 + locale/translations/fr_FR.json | 1 + locale/translations/it_IT.json | 1 + locale/translations/ja_JP.json | 1 + locale/translations/nl_NL.json | 1 + locale/translations/pl_PL.json | 1 + locale/translations/pt_BR.json | 1 + locale/translations/ru_RU.json | 1 + locale/translations/zh_CN.json | 1 + template/common.go | 3 ++- template/html/common/layout.html | 1 + ui/static/js.go | 4 ++-- ui/static/js/app.js | 7 +++++++ ui/static/js/bootstrap.js | 1 + ui/static/js/dom_helper.js | 4 ++-- 18 files changed, 48 insertions(+), 16 deletions(-) diff --git a/locale/translations.go b/locale/translations.go index 3995493e..328fc2f9 100644 --- a/locale/translations.go +++ b/locale/translations.go @@ -159,6 +159,7 @@ var translations = map[string]string{ "page.keyboard_shortcuts.download_content": "Vollständigen Inhalt herunterladen", "page.keyboard_shortcuts.toggle_bookmark_status": "Lesezeichen hinzufügen/entfernen", "page.keyboard_shortcuts.save_article": "Artikel speichern", + "page.keyboard_shortcuts.scroll_item_to_top": "Artikel nach oben blättern", "page.keyboard_shortcuts.remove_feed": "Dieses Abonnement entfernen", "page.keyboard_shortcuts.go_to_search": "Fokus auf das Suchformular setzen", "page.keyboard_shortcuts.close_modal": "Liste der Tastenkürzel schließen", @@ -508,6 +509,7 @@ var translations = map[string]string{ "page.keyboard_shortcuts.download_content": "Download original content", "page.keyboard_shortcuts.toggle_bookmark_status": "Toggle bookmark", "page.keyboard_shortcuts.save_article": "Save article", + "page.keyboard_shortcuts.scroll_item_to_top": "Scroll item to top", "page.keyboard_shortcuts.remove_feed": "Remove this feed", "page.keyboard_shortcuts.go_to_search": "Set focus on search form", "page.keyboard_shortcuts.close_modal": "Close modal dialog", @@ -837,6 +839,7 @@ var translations = map[string]string{ "page.keyboard_shortcuts.download_content": "Descargar el contento original", "page.keyboard_shortcuts.toggle_bookmark_status": "Agregar o quitar marcador", "page.keyboard_shortcuts.save_article": "Guardar artículo", + "page.keyboard_shortcuts.scroll_item_to_top": "Desplazar elemento hacia arriba", "page.keyboard_shortcuts.remove_feed": "Quitar esta fuente", "page.keyboard_shortcuts.go_to_search": "Centrarse en el cuadro de búsqueda", "page.keyboard_shortcuts.close_modal": "Cerrar el cuadro de diálogo modal", @@ -1167,6 +1170,7 @@ var translations = map[string]string{ "page.keyboard_shortcuts.download_content": "Télécharger le contenu original", "page.keyboard_shortcuts.toggle_bookmark_status": "Ajouter/Enlever favoris", "page.keyboard_shortcuts.save_article": "Sauvegarder l'article", + "page.keyboard_shortcuts.scroll_item_to_top": "Faire défiler l'élément vers le haut", "page.keyboard_shortcuts.remove_feed": "Supprimer ce flux", "page.keyboard_shortcuts.go_to_search": "Mettre le focus sur le champ de recherche", "page.keyboard_shortcuts.close_modal": "Fermer la boite de dialogue", @@ -1516,6 +1520,7 @@ var translations = map[string]string{ "page.keyboard_shortcuts.download_content": "Scarica il contenuto integrale", "page.keyboard_shortcuts.toggle_bookmark_status": "Aggiungi/rimuovi dai preferiti", "page.keyboard_shortcuts.save_article": "Salva l'articolo", + "page.keyboard_shortcuts.scroll_item_to_top": "Scorri l'articolo in alto", "page.keyboard_shortcuts.remove_feed": "Rimuovi questo feed", "page.keyboard_shortcuts.go_to_search": "Apri la casella di ricerca", "page.keyboard_shortcuts.close_modal": "Chiudi la finestra di dialogo", @@ -1845,6 +1850,7 @@ var translations = map[string]string{ "page.keyboard_shortcuts.download_content": "オリジナルの内容をダウンロード", "page.keyboard_shortcuts.toggle_bookmark_status": "星を付ける/外す", "page.keyboard_shortcuts.save_article": "記事を保存", + "page.keyboard_shortcuts.scroll_item_to_top": "アイテムを上にスクロール", "page.keyboard_shortcuts.remove_feed": "このフィードを削除", "page.keyboard_shortcuts.go_to_search": "検索フォームにフォーカスを移す", "page.keyboard_shortcuts.close_modal": "モーダルダイアログを閉じる", @@ -2175,6 +2181,7 @@ var translations = map[string]string{ "page.keyboard_shortcuts.download_content": "Download originele content", "page.keyboard_shortcuts.toggle_bookmark_status": "Ster toevoegen/weghalen", "page.keyboard_shortcuts.save_article": "Artikel opslaan", + "page.keyboard_shortcuts.scroll_item_to_top": "Scroll artikel naar boven", "page.keyboard_shortcuts.remove_feed": "Verwijder deze feed", "page.keyboard_shortcuts.go_to_search": "Focus instellen op zoekformulier", "page.keyboard_shortcuts.close_modal": "Sluit dialoogscherm", @@ -2523,6 +2530,7 @@ var translations = map[string]string{ "page.keyboard_shortcuts.download_content": "Pobierz oryginalną zawartość", "page.keyboard_shortcuts.toggle_bookmark_status": "Dodaj/usuń zakładki", "page.keyboard_shortcuts.save_article": "Zapisz artykuł", + "page.keyboard_shortcuts.scroll_item_to_top": "Przewiń artykuł do góry", "page.keyboard_shortcuts.remove_feed": "Usuń ten kanał", "page.keyboard_shortcuts.go_to_search": "Ustaw fokus na formularzu wyszukiwania", "page.keyboard_shortcuts.close_modal": "Zamknij listę skrótów klawiszowych", @@ -2876,6 +2884,7 @@ var translations = map[string]string{ "page.keyboard_shortcuts.download_content": "Buscar o conteúdo original", "page.keyboard_shortcuts.toggle_bookmark_status": "Marcar ou desmarcar como favorito", "page.keyboard_shortcuts.save_article": "Salvar item", + "page.keyboard_shortcuts.scroll_item_to_top": "Role o item para cima", "page.keyboard_shortcuts.remove_feed": "Remover essa fonte", "page.keyboard_shortcuts.go_to_search": "Ir para o campo de busca", "page.keyboard_shortcuts.close_modal": "Fechar janela", @@ -3207,6 +3216,7 @@ var translations = map[string]string{ "page.keyboard_shortcuts.download_content": "Загрузить оригинальное содержимое", "page.keyboard_shortcuts.toggle_bookmark_status": "Переключатель избранного", "page.keyboard_shortcuts.save_article": "Сохранить статью", + "page.keyboard_shortcuts.scroll_item_to_top": "Прокрутите элемент вверх", "page.keyboard_shortcuts.remove_feed": "Удалить эту подписку", "page.keyboard_shortcuts.go_to_search": "Установить фокус в поисковой форме", "page.keyboard_shortcuts.close_modal": "Закрыть модальный диалог", @@ -3540,6 +3550,7 @@ var translations = map[string]string{ "page.keyboard_shortcuts.download_content": "下载原始内容", "page.keyboard_shortcuts.toggle_bookmark_status": "切换收藏状态", "page.keyboard_shortcuts.save_article": "保存文章", + "page.keyboard_shortcuts.scroll_item_to_top": "滚动到顶部", "page.keyboard_shortcuts.remove_feed": "删除此Feed", "page.keyboard_shortcuts.go_to_search": "将重点放在搜索表单上", "page.keyboard_shortcuts.close_modal": "关闭模态对话窗口", @@ -3729,15 +3740,15 @@ var translations = map[string]string{ } var translationsChecksums = map[string]string{ - "de_DE": "8acdf65175293ab3684f945582f9f4adb442b5008afba3312a100bb75c7910d8", - "en_US": "0fdf8969fa460ffb6c21ad8afd624eef130dcd1bb18c489e3a7fd38e6ed2d563", - "es_ES": "86e8bf5fab817c536aa73bdf2aa0f5c09ddad6f7457b662a5e091304815aac05", - "fr_FR": "020deb5822f8bec9d94c9b9a387651efaef21f21239e7c203d76c71260bbbd54", - "it_IT": "77c5963a80c173e2257909b47e46cf7f1ecbbae773c61454fcc987d8b26e4a2a", - "ja_JP": "f2b6b61ac847f17031ab34284a3f3b6355c03fd1534164024e33d1659126e227", - "nl_NL": "4dba877744bb92911fc488c3cfa47aad605501d1ba351f7136b92cb4872fbd34", - "pl_PL": "10acf265cea096636f640d0e275b136fd06cf992d8a306eb418d6dcd21cb8b24", - "pt_BR": "dc853281eb52ae1225a36a9bd2c6bb3c62304834b3b1c092edcdec86823468b4", - "ru_RU": "46d039f6d50e48d841d09285d28810c609cd62dd821da4c68798490d57d1d090", - "zh_CN": "80e8a170246b0b90dffda393d897760ecb4e94b264cacc124db2be6845ac9361", + "de_DE": "70f68d24d17f22bac9bdd7963bc88a0bfdfa90984e4c073c2d0f4fd6ece65333", + "en_US": "2b5d9932f666b84adf67094dd32b126e1bd9b1632adb62c098207fa22cc11fe1", + "es_ES": "06d1963fd24b1d306cef39a37ebc4a2927b60d8867f10e3fbb058869d4414ef1", + "fr_FR": "ed687a738b609af41427728b6f11aa8ea172d1ba14a519f9d81c3e1fbdc5e15f", + "it_IT": "c202528dc69bf257746d48a2d11600efaf38b3f0e3da520f224149f84d3c6abd", + "ja_JP": "25e5699a217a258a5568dfd4dada9749e2af406a3db4a443ccdfd332ad38df18", + "nl_NL": "3b688c555a0cf618f537f13bb27384d6b077f18c53fce19ece9753e8d50b472c", + "pl_PL": "9ee91eef9779dfda54e10b5121732874d1cd184e2d603333c261a2fd2ca1c9db", + "pt_BR": "d6d668fba11e6a9db0d24e40420968e77a2215e4a881265b877e2bb69250d938", + "ru_RU": "df166bb00f389d9c290059e58112c4e7c90f9ea93c4ef7e7d250cd9c58368fcc", + "zh_CN": "762a1f61c41251400e6fcf31c228d34a66c7a414a7ebb1a276b2e5bad7c1275c", } diff --git a/locale/translations/de_DE.json b/locale/translations/de_DE.json index ff17e58e..3e3a5cf5 100644 --- a/locale/translations/de_DE.json +++ b/locale/translations/de_DE.json @@ -154,6 +154,7 @@ "page.keyboard_shortcuts.download_content": "Vollständigen Inhalt herunterladen", "page.keyboard_shortcuts.toggle_bookmark_status": "Lesezeichen hinzufügen/entfernen", "page.keyboard_shortcuts.save_article": "Artikel speichern", + "page.keyboard_shortcuts.scroll_item_to_top": "Artikel nach oben blättern", "page.keyboard_shortcuts.remove_feed": "Dieses Abonnement entfernen", "page.keyboard_shortcuts.go_to_search": "Fokus auf das Suchformular setzen", "page.keyboard_shortcuts.close_modal": "Liste der Tastenkürzel schließen", diff --git a/locale/translations/en_US.json b/locale/translations/en_US.json index f4d8ae9b..94fe8441 100644 --- a/locale/translations/en_US.json +++ b/locale/translations/en_US.json @@ -154,6 +154,7 @@ "page.keyboard_shortcuts.download_content": "Download original content", "page.keyboard_shortcuts.toggle_bookmark_status": "Toggle bookmark", "page.keyboard_shortcuts.save_article": "Save article", + "page.keyboard_shortcuts.scroll_item_to_top": "Scroll item to top", "page.keyboard_shortcuts.remove_feed": "Remove this feed", "page.keyboard_shortcuts.go_to_search": "Set focus on search form", "page.keyboard_shortcuts.close_modal": "Close modal dialog", diff --git a/locale/translations/es_ES.json b/locale/translations/es_ES.json index f945c621..9a102206 100644 --- a/locale/translations/es_ES.json +++ b/locale/translations/es_ES.json @@ -154,6 +154,7 @@ "page.keyboard_shortcuts.download_content": "Descargar el contento original", "page.keyboard_shortcuts.toggle_bookmark_status": "Agregar o quitar marcador", "page.keyboard_shortcuts.save_article": "Guardar artículo", + "page.keyboard_shortcuts.scroll_item_to_top": "Desplazar elemento hacia arriba", "page.keyboard_shortcuts.remove_feed": "Quitar esta fuente", "page.keyboard_shortcuts.go_to_search": "Centrarse en el cuadro de búsqueda", "page.keyboard_shortcuts.close_modal": "Cerrar el cuadro de diálogo modal", diff --git a/locale/translations/fr_FR.json b/locale/translations/fr_FR.json index 96b774e2..c1131bbc 100644 --- a/locale/translations/fr_FR.json +++ b/locale/translations/fr_FR.json @@ -154,6 +154,7 @@ "page.keyboard_shortcuts.download_content": "Télécharger le contenu original", "page.keyboard_shortcuts.toggle_bookmark_status": "Ajouter/Enlever favoris", "page.keyboard_shortcuts.save_article": "Sauvegarder l'article", + "page.keyboard_shortcuts.scroll_item_to_top": "Faire défiler l'élément vers le haut", "page.keyboard_shortcuts.remove_feed": "Supprimer ce flux", "page.keyboard_shortcuts.go_to_search": "Mettre le focus sur le champ de recherche", "page.keyboard_shortcuts.close_modal": "Fermer la boite de dialogue", diff --git a/locale/translations/it_IT.json b/locale/translations/it_IT.json index 005f5103..6a12476f 100644 --- a/locale/translations/it_IT.json +++ b/locale/translations/it_IT.json @@ -154,6 +154,7 @@ "page.keyboard_shortcuts.download_content": "Scarica il contenuto integrale", "page.keyboard_shortcuts.toggle_bookmark_status": "Aggiungi/rimuovi dai preferiti", "page.keyboard_shortcuts.save_article": "Salva l'articolo", + "page.keyboard_shortcuts.scroll_item_to_top": "Scorri l'articolo in alto", "page.keyboard_shortcuts.remove_feed": "Rimuovi questo feed", "page.keyboard_shortcuts.go_to_search": "Apri la casella di ricerca", "page.keyboard_shortcuts.close_modal": "Chiudi la finestra di dialogo", diff --git a/locale/translations/ja_JP.json b/locale/translations/ja_JP.json index 8f88271c..0f5febc8 100644 --- a/locale/translations/ja_JP.json +++ b/locale/translations/ja_JP.json @@ -154,6 +154,7 @@ "page.keyboard_shortcuts.download_content": "オリジナルの内容をダウンロード", "page.keyboard_shortcuts.toggle_bookmark_status": "星を付ける/外す", "page.keyboard_shortcuts.save_article": "記事を保存", + "page.keyboard_shortcuts.scroll_item_to_top": "アイテムを上にスクロール", "page.keyboard_shortcuts.remove_feed": "このフィードを削除", "page.keyboard_shortcuts.go_to_search": "検索フォームにフォーカスを移す", "page.keyboard_shortcuts.close_modal": "モーダルダイアログを閉じる", diff --git a/locale/translations/nl_NL.json b/locale/translations/nl_NL.json index df640143..0e020eb6 100644 --- a/locale/translations/nl_NL.json +++ b/locale/translations/nl_NL.json @@ -155,6 +155,7 @@ "page.keyboard_shortcuts.download_content": "Download originele content", "page.keyboard_shortcuts.toggle_bookmark_status": "Ster toevoegen/weghalen", "page.keyboard_shortcuts.save_article": "Artikel opslaan", + "page.keyboard_shortcuts.scroll_item_to_top": "Scroll artikel naar boven", "page.keyboard_shortcuts.remove_feed": "Verwijder deze feed", "page.keyboard_shortcuts.go_to_search": "Focus instellen op zoekformulier", "page.keyboard_shortcuts.close_modal": "Sluit dialoogscherm", diff --git a/locale/translations/pl_PL.json b/locale/translations/pl_PL.json index d7c594c1..c8184b95 100644 --- a/locale/translations/pl_PL.json +++ b/locale/translations/pl_PL.json @@ -156,6 +156,7 @@ "page.keyboard_shortcuts.download_content": "Pobierz oryginalną zawartość", "page.keyboard_shortcuts.toggle_bookmark_status": "Dodaj/usuń zakładki", "page.keyboard_shortcuts.save_article": "Zapisz artykuł", + "page.keyboard_shortcuts.scroll_item_to_top": "Przewiń artykuł do góry", "page.keyboard_shortcuts.remove_feed": "Usuń ten kanał", "page.keyboard_shortcuts.go_to_search": "Ustaw fokus na formularzu wyszukiwania", "page.keyboard_shortcuts.close_modal": "Zamknij listę skrótów klawiszowych", diff --git a/locale/translations/pt_BR.json b/locale/translations/pt_BR.json index a3dcee3a..8aa9a90a 100644 --- a/locale/translations/pt_BR.json +++ b/locale/translations/pt_BR.json @@ -154,6 +154,7 @@ "page.keyboard_shortcuts.download_content": "Buscar o conteúdo original", "page.keyboard_shortcuts.toggle_bookmark_status": "Marcar ou desmarcar como favorito", "page.keyboard_shortcuts.save_article": "Salvar item", + "page.keyboard_shortcuts.scroll_item_to_top": "Role o item para cima", "page.keyboard_shortcuts.remove_feed": "Remover essa fonte", "page.keyboard_shortcuts.go_to_search": "Ir para o campo de busca", "page.keyboard_shortcuts.close_modal": "Fechar janela", diff --git a/locale/translations/ru_RU.json b/locale/translations/ru_RU.json index 15558dd8..cf93c96e 100644 --- a/locale/translations/ru_RU.json +++ b/locale/translations/ru_RU.json @@ -156,6 +156,7 @@ "page.keyboard_shortcuts.download_content": "Загрузить оригинальное содержимое", "page.keyboard_shortcuts.toggle_bookmark_status": "Переключатель избранного", "page.keyboard_shortcuts.save_article": "Сохранить статью", + "page.keyboard_shortcuts.scroll_item_to_top": "Прокрутите элемент вверх", "page.keyboard_shortcuts.remove_feed": "Удалить эту подписку", "page.keyboard_shortcuts.go_to_search": "Установить фокус в поисковой форме", "page.keyboard_shortcuts.close_modal": "Закрыть модальный диалог", diff --git a/locale/translations/zh_CN.json b/locale/translations/zh_CN.json index 2b6dc6d8..60d715fa 100644 --- a/locale/translations/zh_CN.json +++ b/locale/translations/zh_CN.json @@ -152,6 +152,7 @@ "page.keyboard_shortcuts.download_content": "下载原始内容", "page.keyboard_shortcuts.toggle_bookmark_status": "切换收藏状态", "page.keyboard_shortcuts.save_article": "保存文章", + "page.keyboard_shortcuts.scroll_item_to_top": "滚动到顶部", "page.keyboard_shortcuts.remove_feed": "删除此Feed", "page.keyboard_shortcuts.go_to_search": "将重点放在搜索表单上", "page.keyboard_shortcuts.close_modal": "关闭模态对话窗口", diff --git a/template/common.go b/template/common.go index 9e1783d0..f184fe55 100644 --- a/template/common.go +++ b/template/common.go @@ -459,6 +459,7 @@ SOFTWARE.
  • {{ t "page.keyboard_shortcuts.download_content" }} = d
  • {{ t "page.keyboard_shortcuts.toggle_bookmark_status" }} = f
  • {{ t "page.keyboard_shortcuts.save_article" }} = s
  • +
  • {{ t "page.keyboard_shortcuts.scroll_item_to_top" }} = z + t
  • {{ t "page.keyboard_shortcuts.refresh_all_feeds" }} = R
  • {{ t "page.keyboard_shortcuts.remove_feed" }} = #
  • {{ t "page.keyboard_shortcuts.go_to_search" }} = /
  • @@ -523,7 +524,7 @@ var templateCommonMapChecksums = map[string]string{ "feed_menu": "318d8662dda5ca9dfc75b909c8461e79c86fb5082df1428f67aaf856f19f4b50", "icons": "3dbe754a98f524a227111191d76b8c6944711b13613cc548ee9e9808fe0bffb4", "item_meta": "b7d69c26be12f72f821d7b509a9f910b1f341c2db02f138d5178f72a2c5b7939", - "layout": "affdf6da489d9fbc50a58ffcab0e64d784d8befb32031f1249dee4c1f8d967e1", + "layout": "65767e7dbebe1f7ed42895ecd5a737b0693e4a2ec35e84e3e391f462beb11977", "pagination": "7b61288e86283c4cf0dc83bcbf8bf1c00c7cb29e60201c8c0b633b2450d2911f", "settings_menu": "e2b777630c0efdbc529800303c01d6744ed3af80ec505ac5a5b3f99c9b989156", } diff --git a/template/html/common/layout.html b/template/html/common/layout.html index 2aff3472..bce2d70b 100644 --- a/template/html/common/layout.html +++ b/template/html/common/layout.html @@ -148,6 +148,7 @@
  • {{ t "page.keyboard_shortcuts.download_content" }} = d
  • {{ t "page.keyboard_shortcuts.toggle_bookmark_status" }} = f
  • {{ t "page.keyboard_shortcuts.save_article" }} = s
  • +
  • {{ t "page.keyboard_shortcuts.scroll_item_to_top" }} = z + t
  • {{ t "page.keyboard_shortcuts.refresh_all_feeds" }} = R
  • {{ t "page.keyboard_shortcuts.remove_feed" }} = #
  • {{ t "page.keyboard_shortcuts.go_to_search" }} = /
  • diff --git a/ui/static/js.go b/ui/static/js.go index 5f28665f..019ea0a0 100644 --- a/ui/static/js.go +++ b/ui/static/js.go @@ -3,11 +3,11 @@ package static // import "miniflux.app/ui/static" var Javascripts = map[string]string{ - "app": `!function(){'use strict';class a{static isVisible(a){return a.offsetParent!==null}static openNewTab(b){let a=window.open("");a.opener=null,a.location=b,a.focus()}static scrollPageTo(a){let d=window.pageYOffset,b=document.documentElement.clientHeight,c=d+b,e=a.offsetTop+a.offsetHeight;(c-e<0||c-a.offsetTop>b)&&window.scrollTo(0,a.offsetTop-10)}static getVisibleElements(c){let a=document.querySelectorAll(c),b=[];for(let c=0;c=-1&&this.touch.move.x>=-1){let a=Math.abs(this.touch.move.x-this.touch.start.x),b=Math.abs(this.touch.move.y-this.touch.start.y);if(a>30&&b<70)return this.touch.move.x-this.touch.start.x}return 0}findElement(b){return b.classList.contains("touch-item")?b:a.findParent(b,"touch-item")}onTouchStart(a){if(a.touches===void 0||a.touches.length!==1)return;this.reset(),this.touch.start.x=a.touches[0].clientX,this.touch.start.y=a.touches[0].clientY,this.touch.element=this.findElement(a.touches[0].target)}onTouchMove(a){if(a.touches===void 0||a.touches.length!==1||this.element===null)return;this.touch.move.x=a.touches[0].clientX,this.touch.move.y=a.touches[0].clientY;let b=this.calculateDistance(),c=Math.abs(b);if(c>0){let d=1-(c>75?.9:c/75*.9),e=b>75?75:b<-75?-75:b;this.touch.element.style.opacity=d,this.touch.element.style.transform="translateX("+e+"px)",a.preventDefault()}}onTouchEnd(a){if(a.touches===void 0)return;if(this.touch.element!==null){let a=Math.abs(this.calculateDistance());a>75&&n(this.touch.element),this.touch.element.style.opacity=1,this.touch.element.style.transform="none"}this.reset()}listen(){let e=document.querySelectorAll(".touch-item"),c=a.hasPassiveEventListenerOption();e.forEach(a=>{a.addEventListener("touchstart",a=>this.onTouchStart(a),!!c&&{passive:!0}),a.addEventListener("touchmove",a=>this.onTouchMove(a),!!c&&{passive:!1}),a.addEventListener("touchend",a=>this.onTouchEnd(a),!!c&&{passive:!0}),a.addEventListener("touchcancel",()=>this.reset(),!!c&&{passive:!0})});let d=document.querySelector(".entry-content");if(d){let a={previous:null,next:null};const e=(c,d)=>{const e=a[c];e===null?a[c]=setTimeout(()=>{a[c]=null},200):(d.preventDefault(),b(c))};d.addEventListener("touchend",a=>{a.changedTouches[0].clientX>=d.offsetWidth/2?e("next",a):e("previous",a)},!!c&&{passive:!1}),d.addEventListener("touchmove",b=>{Object.keys(a).forEach(b=>a[b]=null)})}}}class M{constructor(){this.queue=[],this.shortcuts={},this.triggers=[]}on(a,b){this.shortcuts[a]=b,this.triggers.push(a.split(" ")[0])}listen(){document.onkeydown=a=>{let b=this.getKey(a);if(this.isEventIgnored(a,b)||this.isModifierKeyDown(a))return;a.preventDefault(),this.queue.push(b);for(let c in this.shortcuts){let d=c.split(" ");if(d.every((a,b)=>a===this.queue[b])){this.queue=[],this.shortcuts[c](a);return}if(d.length===1&&b===d[0]){this.queue=[],this.shortcuts[c](a);return}}this.queue.length>=2&&(this.queue=[])}}isEventIgnored(a,b){return a.target.tagName==="INPUT"||a.target.tagName==="TEXTAREA"||this.queue.length<1&&!this.triggers.includes(b)}isModifierKeyDown(a){return a.getModifierState("Control")||a.getModifierState("Alt")||a.getModifierState("Meta")}getKey(b){const a={Esc:'Escape',Up:'ArrowUp',Down:'ArrowDown',Left:'ArrowLeft',Right:'ArrowRight'};for(let c in a)if(a.hasOwnProperty(c)&&c===b.key)return a[c];return b.key}}class d{constructor(a){this.callback=null,this.url=a,this.options={method:"POST",cache:"no-cache",credentials:"include",body:null,headers:new Headers({"Content-Type":"application/json","X-Csrf-Token":this.getCsrfToken()})}}withHttpMethod(a){return this.options.method=a,this}withBody(a){return this.options.body=JSON.stringify(a),this}withCallback(a){return this.callback=a,this}getCsrfToken(){let a=document.querySelector("meta[name=X-CSRF-Token]");return a!==null?a.getAttribute("value"):""}execute(){fetch(new Request(this.url,this.options)).then(a=>{this.callback&&this.callback(a)})}}class g{static exists(){return document.getElementById("modal-container")!==null}static open(c){if(g.exists())return;let a=document.createElement("div");a.id="modal-container",a.appendChild(document.importNode(c,!0)),document.body.appendChild(a);let b=document.querySelector("a.btn-close-modal");b!==null&&(b.onclick=a=>{a.preventDefault(),g.close()})}static close(){let a=document.getElementById("modal-container");a!==null&&a.parentNode.removeChild(a)}}function c(a,b,c){let d=document.querySelectorAll(a);d.forEach(a=>{a.onclick=a=>{c||a.preventDefault(),b(a)}})}function L(){let b=document.querySelector(".header nav ul");a.isVisible(b)?b.style.display="none":b.style.display="block";let c=document.querySelector(".header .search");a.isVisible(c)?c.style.display="none":c.style.display="block"}function K(b){let a=b.target;a.tagName==="A"?window.location.href=a.getAttribute("href"):window.location.href=a.querySelector("a").getAttribute("href")}function J(){let a=document.querySelectorAll("form");a.forEach(a=>{a.onsubmit=()=>{let b=a.querySelector("button");b&&(b.innerHTML=b.dataset.labelLoading,b.disabled=!0)}})}function q(b){b.preventDefault(),b.stopPropagation();let c=document.querySelector(".search-toggle-switch");c&&(c.style.display="none");let d=document.querySelector(".search-form");d&&(d.style.display="block");let a=document.getElementById("search-input");a&&(a.focus(),a.value="")}function G(){let a=document.getElementById("keyboard-shortcuts");a!==null&&g.open(a.content)}function p(){let d=a.getVisibleElements(".items .item"),c=[];d.forEach(a=>{a.classList.add("item-status-read"),c.push(parseInt(a.dataset.id,10))}),c.length>0&&j(c,"read",()=>{let a=document.querySelector("a[data-action=markPageAsRead]"),c=!1;a&&(c=a.dataset.showOnlyUnread||!1),c?window.location.reload():b("next",!0)})}function m(b){let c=!b,a=i(b);a&&(n(a,c),e()&&a.classList.contains('current-item')&&k())}function n(b,d){let g=parseInt(b.dataset.id,10),a=b.querySelector("a[data-toggle-status]"),c=a.dataset.value,e=c==="read"?"unread":"read";j([g],e),c==="read"?(a.innerHTML=''+a.dataset.labelRead+'',a.dataset.value="unread",d&&f(a.dataset.toastUnread)):(a.innerHTML=''+a.dataset.labelUnread+'',a.dataset.value="read",d&&f(a.dataset.toastRead)),b.classList.contains("item-status-"+c)&&(b.classList.remove("item-status-"+c),b.classList.add("item-status-"+e))}function E(a){if(a.classList.contains("item-status-unread")){a.classList.remove("item-status-unread"),a.classList.add("item-status-read");let b=parseInt(a.dataset.id,10);j([b],"read")}}function C(){let b=document.body.dataset.refreshAllFeedsUrl,a=new d(b);a.withCallback(()=>{window.location.reload()}),a.withHttpMethod("GET"),a.execute()}function j(c,b,e){let f=document.body.dataset.entriesStatusUrl,a=new d(f);a.withBody({entry_ids:c,status:b}),a.withCallback(e),a.execute(),b==="read"?H(1):I(1)}function r(a){let c=!a,b=i(a);b&&B(b.querySelector("a[data-save-entry]"),c)}function B(a,c){if(!a)return;if(a.dataset.completed)return;let e=a.innerHTML;a.innerHTML=''+a.dataset.labelLoading+'';let b=new d(a.dataset.saveUrl);b.withCallback(()=>{a.innerHTML=e,a.dataset.completed=!0,c&&f(a.dataset.toastDone)}),b.execute()}function t(a){let c=!a,b=i(a);b&&O(b,c)}function O(e,b){let a=e.querySelector("a[data-toggle-bookmark]");if(!a)return;a.innerHTML=''+a.dataset.labelLoading+'';let c=new d(a.dataset.bookmarkUrl);c.withCallback(()=>{a.dataset.value==="star"?(a.innerHTML=''+a.dataset.labelStar+'',a.dataset.value="unstar",b&&f(a.dataset.toastUnstar)):(a.innerHTML=''+a.dataset.labelUnstar+'',a.dataset.value="star",b&&f(a.dataset.toastStar))}),c.execute()}function v(){if(e())return;let a=document.querySelector("a[data-fetch-content-entry]");if(!a)return;let c=a.innerHTML;a.innerHTML=''+a.dataset.labelLoading+'';let b=new d(a.dataset.fetchContentUrl);b.withCallback(b=>{a.innerHTML=c,b.json().then(a=>{a.hasOwnProperty("content")&&(document.querySelector(".entry-content").innerHTML=a.content)})}),b.execute()}function w(d){let b=document.querySelector(".entry h1 a");if(b!==null){d?window.location.href=b.getAttribute("href"):a.openNewTab(b.getAttribute("href"));return}let c=document.querySelector(".current-item a[data-original-link]");if(c!==null){a.openNewTab(c.getAttribute("href"));let b=document.querySelector(".current-item");document.location.href!=document.querySelector('a[data-page=starred]').href&&k(),E(b)}}function x(b){if(e()){let b=document.querySelector(".current-item a[data-comments-link]");b!==null&&a.openNewTab(b.getAttribute("href"))}else{let c=document.querySelector("a[data-comments-link]");if(c!==null){b?window.location.href=c.getAttribute("href"):a.openNewTab(c.getAttribute("href"));return}}}function A(){let a=document.querySelector(".current-item .item-title a");a!==null&&(window.location.href=a.getAttribute("href"))}function z(){let a=document.querySelectorAll("[data-action=remove-feed]");if(a.length===1){let b=a[0],c=new d(b.dataset.url);c.withCallback(()=>{b.dataset.redirectUrl?window.location.href=b.dataset.redirectUrl:window.location.reload()}),c.execute()}}function b(b,c){let a=document.querySelector("a[data-page="+b+"]");a?document.location.href=a.href:c&&window.location.reload()}function h(){e()?F():b("previous")}function l(){e()?k():b("next")}function D(){s()?o():b('feeds')}function o(){if(s()){let a=document.querySelector("span.entry-website a");a!==null&&(window.location.href=a.href)}else{let a=document.querySelector(".current-item a[data-feed-link]");a!==null&&(window.location.href=a.getAttribute("href"))}}function F(){let b=a.getVisibleElements(".items .item");if(b.length===0)return;if(document.querySelector(".current-item")===null){b[0].classList.add("current-item"),b[0].querySelector('.item-header a').focus();return}for(let c=0;c=0?d=b[c-1]:d=b[b.length-1],d.classList.add("current-item"),a.scrollPageTo(d),d.querySelector('.item-header a').focus();break}}function k(){let b=a.getVisibleElements(".items .item");if(b.length===0)return;if(document.querySelector(".current-item")===null){b[0].classList.add("current-item"),b[0].querySelector('.item-header a').focus();return}for(let c=0;cb-a)}function I(a){y(b=>b+a)}function y(a){let b=document.querySelectorAll("span.unread-counter");if(b.forEach(b=>{let c=parseInt(b.textContent,10);b.innerHTML=a(c)}),window.location.href.endsWith('/unread')){let b=parseInt(document.title.split('(')[1],10),c=a(b);document.title=document.title.replace(/(.*?)\(\d+\)(.*?)/,function(d,a,b,e,f){return a+'('+c+')'+b})}}function s(){return document.querySelector("section.entry")!==null}function e(){return document.querySelector(".items")!==null}function i(b){return e()?b?a.findParent(b,"item"):document.querySelector(".current-item"):document.querySelector(".entry")}function u(a,f){a.tagName!='A'&&(a=a.parentNode),a.style.display="none";let e=a.parentNode,b=document.createElement("span"),c=document.createElement("a");c.href="#",c.appendChild(document.createTextNode(a.dataset.labelYes)),c.onclick=d=>{d.preventDefault();let c=document.createElement("span");c.className="loading",c.appendChild(document.createTextNode(a.dataset.labelLoading)),b.remove(),e.appendChild(c),f(a.dataset.url,a.dataset.redirectUrl)};let d=document.createElement("a");d.href="#",d.appendChild(document.createTextNode(a.dataset.labelNo)),d.onclick=c=>{c.preventDefault(),a.style.display="inline",b.remove()},b.className="confirm",b.appendChild(document.createTextNode(a.dataset.labelQuestion+" ")),b.appendChild(c),b.appendChild(document.createTextNode(", ")),b.appendChild(d),e.appendChild(b)}function f(a){if(!a)return;document.querySelector('.toast-wrap .toast-msg').innerHTML=a;let b=document.querySelector('.toast-wrap');b.classList.remove('toastAnimate'),setTimeout(function(){b.classList.add('toastAnimate')},100)}document.addEventListener("DOMContentLoaded",function(){if(J(),!document.querySelector("body[data-disable-keyboard-shortcuts=true]")){let a=new M;a.on("g u",()=>b("unread")),a.on("g b",()=>b("starred")),a.on("g h",()=>b("history")),a.on("g f",()=>D()),a.on("g c",()=>b("categories")),a.on("g s",()=>b("settings")),a.on("ArrowLeft",()=>h()),a.on("ArrowRight",()=>l()),a.on("k",()=>h()),a.on("p",()=>h()),a.on("j",()=>l()),a.on("n",()=>l()),a.on("h",()=>b("previous")),a.on("l",()=>b("next")),a.on("o",()=>A()),a.on("v",()=>w()),a.on("V",()=>w(!0)),a.on("c",()=>x()),a.on("C",()=>x(!0)),a.on("m",()=>m()),a.on("A",()=>p()),a.on("s",()=>r()),a.on("d",()=>v()),a.on("f",()=>t()),a.on("F",()=>o()),a.on("R",()=>C()),a.on("?",()=>G()),a.on("#",()=>z()),a.on("/",a=>q(a)),a.on("Escape",()=>g.close()),a.listen()}let a=new N;if(a.listen(),c("a[data-save-entry]",a=>r(a.target)),c("a[data-toggle-bookmark]",a=>t(a.target)),c("a[data-fetch-content-entry]",()=>v()),c("a[data-action=search]",a=>q(a)),c("a[data-action=markPageAsRead]",()=>u(event.target,()=>p())),c("a[data-toggle-status]",a=>m(a.target)),c("a[data-confirm]",a=>u(a.target,(c,a)=>{let b=new d(c);b.withCallback(()=>{a?window.location.href=a:window.location.reload()}),b.execute()})),document.documentElement.clientWidth<600&&(c(".logo",()=>L()),c(".header nav li",a=>K(a))),"serviceWorker"in navigator){let a=document.getElementById("service-worker-script");a&&navigator.serviceWorker.register(a.src)}window.addEventListener('beforeinstallprompt',c=>{c.preventDefault();let a=c;const b=document.getElementById('prompt-home-screen');if(b){b.style.display="block";const c=document.getElementById('btn-add-to-home-screen');c&&c.addEventListener('click',c=>{c.preventDefault(),a.prompt(),a.userChoice.then(()=>{a=null,b.style.display="none"})})}})})}()`, + "app": `!function(){'use strict';class a{static isVisible(a){return a.offsetParent!==null}static openNewTab(b){let a=window.open("");a.opener=null,a.location=b,a.focus()}static scrollPageTo(a,d){let e=window.pageYOffset,b=document.documentElement.clientHeight,c=e+b,f=a.offsetTop+a.offsetHeight;(d||c-f<0||c-a.offsetTop>b)&&window.scrollTo(0,a.offsetTop-10)}static getVisibleElements(c){let a=document.querySelectorAll(c),b=[];for(let c=0;c=-1&&this.touch.move.x>=-1){let a=Math.abs(this.touch.move.x-this.touch.start.x),b=Math.abs(this.touch.move.y-this.touch.start.y);if(a>30&&b<70)return this.touch.move.x-this.touch.start.x}return 0}findElement(b){return b.classList.contains("touch-item")?b:a.findParent(b,"touch-item")}onTouchStart(a){if(a.touches===void 0||a.touches.length!==1)return;this.reset(),this.touch.start.x=a.touches[0].clientX,this.touch.start.y=a.touches[0].clientY,this.touch.element=this.findElement(a.touches[0].target)}onTouchMove(a){if(a.touches===void 0||a.touches.length!==1||this.element===null)return;this.touch.move.x=a.touches[0].clientX,this.touch.move.y=a.touches[0].clientY;let b=this.calculateDistance(),c=Math.abs(b);if(c>0){let d=1-(c>75?.9:c/75*.9),e=b>75?75:b<-75?-75:b;this.touch.element.style.opacity=d,this.touch.element.style.transform="translateX("+e+"px)",a.preventDefault()}}onTouchEnd(a){if(a.touches===void 0)return;if(this.touch.element!==null){let a=Math.abs(this.calculateDistance());a>75&&n(this.touch.element),this.touch.element.style.opacity=1,this.touch.element.style.transform="none"}this.reset()}listen(){let e=document.querySelectorAll(".touch-item"),c=a.hasPassiveEventListenerOption();e.forEach(a=>{a.addEventListener("touchstart",a=>this.onTouchStart(a),!!c&&{passive:!0}),a.addEventListener("touchmove",a=>this.onTouchMove(a),!!c&&{passive:!1}),a.addEventListener("touchend",a=>this.onTouchEnd(a),!!c&&{passive:!0}),a.addEventListener("touchcancel",()=>this.reset(),!!c&&{passive:!0})});let d=document.querySelector(".entry-content");if(d){let a={previous:null,next:null};const e=(c,d)=>{const e=a[c];e===null?a[c]=setTimeout(()=>{a[c]=null},200):(d.preventDefault(),b(c))};d.addEventListener("touchend",a=>{a.changedTouches[0].clientX>=d.offsetWidth/2?e("next",a):e("previous",a)},!!c&&{passive:!1}),d.addEventListener("touchmove",b=>{Object.keys(a).forEach(b=>a[b]=null)})}}}class M{constructor(){this.queue=[],this.shortcuts={},this.triggers=[]}on(a,b){this.shortcuts[a]=b,this.triggers.push(a.split(" ")[0])}listen(){document.onkeydown=a=>{let b=this.getKey(a);if(this.isEventIgnored(a,b)||this.isModifierKeyDown(a))return;a.preventDefault(),this.queue.push(b);for(let c in this.shortcuts){let d=c.split(" ");if(d.every((a,b)=>a===this.queue[b])){this.queue=[],this.shortcuts[c](a);return}if(d.length===1&&b===d[0]){this.queue=[],this.shortcuts[c](a);return}}this.queue.length>=2&&(this.queue=[])}}isEventIgnored(a,b){return a.target.tagName==="INPUT"||a.target.tagName==="TEXTAREA"||this.queue.length<1&&!this.triggers.includes(b)}isModifierKeyDown(a){return a.getModifierState("Control")||a.getModifierState("Alt")||a.getModifierState("Meta")}getKey(b){const a={Esc:'Escape',Up:'ArrowUp',Down:'ArrowDown',Left:'ArrowLeft',Right:'ArrowRight'};for(let c in a)if(a.hasOwnProperty(c)&&c===b.key)return a[c];return b.key}}class d{constructor(a){this.callback=null,this.url=a,this.options={method:"POST",cache:"no-cache",credentials:"include",body:null,headers:new Headers({"Content-Type":"application/json","X-Csrf-Token":this.getCsrfToken()})}}withHttpMethod(a){return this.options.method=a,this}withBody(a){return this.options.body=JSON.stringify(a),this}withCallback(a){return this.callback=a,this}getCsrfToken(){let a=document.querySelector("meta[name=X-CSRF-Token]");return a!==null?a.getAttribute("value"):""}execute(){fetch(new Request(this.url,this.options)).then(a=>{this.callback&&this.callback(a)})}}class g{static exists(){return document.getElementById("modal-container")!==null}static open(c){if(g.exists())return;let a=document.createElement("div");a.id="modal-container",a.appendChild(document.importNode(c,!0)),document.body.appendChild(a);let b=document.querySelector("a.btn-close-modal");b!==null&&(b.onclick=a=>{a.preventDefault(),g.close()})}static close(){let a=document.getElementById("modal-container");a!==null&&a.parentNode.removeChild(a)}}function c(a,b,c){let d=document.querySelectorAll(a);d.forEach(a=>{a.onclick=a=>{c||a.preventDefault(),b(a)}})}function K(){let b=document.querySelector(".header nav ul");a.isVisible(b)?b.style.display="none":b.style.display="block";let c=document.querySelector(".header .search");a.isVisible(c)?c.style.display="none":c.style.display="block"}function G(b){let a=b.target;a.tagName==="A"?window.location.href=a.getAttribute("href"):window.location.href=a.querySelector("a").getAttribute("href")}function C(){let a=document.querySelectorAll("form");a.forEach(a=>{a.onsubmit=()=>{let b=a.querySelector("button");b&&(b.innerHTML=b.dataset.labelLoading,b.disabled=!0)}})}function u(b){b.preventDefault(),b.stopPropagation();let c=document.querySelector(".search-toggle-switch");c&&(c.style.display="none");let d=document.querySelector(".search-form");d&&(d.style.display="block");let a=document.getElementById("search-input");a&&(a.focus(),a.value="")}function A(){let a=document.getElementById("keyboard-shortcuts");a!==null&&g.open(a.content)}function q(){let d=a.getVisibleElements(".items .item"),c=[];d.forEach(a=>{a.classList.add("item-status-read"),c.push(parseInt(a.dataset.id,10))}),c.length>0&&l(c,"read",()=>{let a=document.querySelector("a[data-action=markPageAsRead]"),c=!1;a&&(c=a.dataset.showOnlyUnread||!1),c?window.location.reload():b("next",!0)})}function x(b){let c=!b,a=h(b);a&&(n(a,c),e()&&a.classList.contains('current-item')&&i())}function n(b,d){let g=parseInt(b.dataset.id,10),a=b.querySelector("a[data-toggle-status]"),c=a.dataset.value,e=c==="read"?"unread":"read";l([g],e),c==="read"?(a.innerHTML=''+a.dataset.labelRead+'',a.dataset.value="unread",d&&f(a.dataset.toastUnread)):(a.innerHTML=''+a.dataset.labelUnread+'',a.dataset.value="read",d&&f(a.dataset.toastRead)),b.classList.contains("item-status-"+c)&&(b.classList.remove("item-status-"+c),b.classList.add("item-status-"+e))}function O(a){if(a.classList.contains("item-status-unread")){a.classList.remove("item-status-unread"),a.classList.add("item-status-read");let b=parseInt(a.dataset.id,10);l([b],"read")}}function L(){let b=document.body.dataset.refreshAllFeedsUrl,a=new d(b);a.withCallback(()=>{window.location.reload()}),a.withHttpMethod("GET"),a.execute()}function l(c,b,e){let f=document.body.dataset.entriesStatusUrl,a=new d(f);a.withBody({entry_ids:c,status:b}),a.withCallback(e),a.execute(),b==="read"?I(1):J(1)}function r(a){let c=!a,b=h(a);b&&E(b.querySelector("a[data-save-entry]"),c)}function E(a,c){if(!a)return;if(a.dataset.completed)return;let e=a.innerHTML;a.innerHTML=''+a.dataset.labelLoading+'';let b=new d(a.dataset.saveUrl);b.withCallback(()=>{a.innerHTML=e,a.dataset.completed=!0,c&&f(a.dataset.toastDone)}),b.execute()}function t(a){let c=!a,b=h(a);b&&B(b,c)}function B(e,b){let a=e.querySelector("a[data-toggle-bookmark]");if(!a)return;a.innerHTML=''+a.dataset.labelLoading+'';let c=new d(a.dataset.bookmarkUrl);c.withCallback(()=>{a.dataset.value==="star"?(a.innerHTML=''+a.dataset.labelStar+'',a.dataset.value="unstar",b&&f(a.dataset.toastUnstar)):(a.innerHTML=''+a.dataset.labelUnstar+'',a.dataset.value="star",b&&f(a.dataset.toastStar))}),c.execute()}function v(){if(e())return;let a=document.querySelector("a[data-fetch-content-entry]");if(!a)return;let c=a.innerHTML;a.innerHTML=''+a.dataset.labelLoading+'';let b=new d(a.dataset.fetchContentUrl);b.withCallback(b=>{a.innerHTML=c,b.json().then(a=>{a.hasOwnProperty("content")&&(document.querySelector(".entry-content").innerHTML=a.content)})}),b.execute()}function w(d){let b=document.querySelector(".entry h1 a");if(b!==null){d?window.location.href=b.getAttribute("href"):a.openNewTab(b.getAttribute("href"));return}let c=document.querySelector(".current-item a[data-original-link]");if(c!==null){a.openNewTab(c.getAttribute("href"));let b=document.querySelector(".current-item");document.location.href!=document.querySelector('a[data-page=starred]').href&&i(),O(b)}}function m(b){if(e()){let b=document.querySelector(".current-item a[data-comments-link]");b!==null&&a.openNewTab(b.getAttribute("href"))}else{let c=document.querySelector("a[data-comments-link]");if(c!==null){b?window.location.href=c.getAttribute("href"):a.openNewTab(c.getAttribute("href"));return}}}function P(){let a=document.querySelector(".current-item .item-title a");a!==null&&(window.location.href=a.getAttribute("href"))}function H(){let a=document.querySelectorAll("[data-action=remove-feed]");if(a.length===1){let b=a[0],c=new d(b.dataset.url);c.withCallback(()=>{b.dataset.redirectUrl?window.location.href=b.dataset.redirectUrl:window.location.reload()}),c.execute()}}function b(b,c){let a=document.querySelector("a[data-page="+b+"]");a?document.location.href=a.href:c&&window.location.reload()}function k(){e()?F():b("previous")}function j(){e()?i():b("next")}function D(){p()?s():b('feeds')}function s(){if(p()){let a=document.querySelector("span.entry-website a");a!==null&&(window.location.href=a.href)}else{let a=document.querySelector(".current-item a[data-feed-link]");a!==null&&(window.location.href=a.getAttribute("href"))}}function F(){let b=a.getVisibleElements(".items .item");if(b.length===0)return;if(document.querySelector(".current-item")===null){b[0].classList.add("current-item"),b[0].querySelector('.item-header a').focus();return}for(let c=0;c=0?d=b[c-1]:d=b[b.length-1],d.classList.add("current-item"),a.scrollPageTo(d),d.querySelector('.item-header a').focus();break}}function i(){let b=a.getVisibleElements(".items .item");if(b.length===0)return;if(document.querySelector(".current-item")===null){b[0].classList.add("current-item"),b[0].querySelector('.item-header a').focus();return}for(let c=0;cb-a)}function J(a){y(b=>b+a)}function y(a){let b=document.querySelectorAll("span.unread-counter");if(b.forEach(b=>{let c=parseInt(b.textContent,10);b.innerHTML=a(c)}),window.location.href.endsWith('/unread')){let b=parseInt(document.title.split('(')[1],10),c=a(b);document.title=document.title.replace(/(.*?)\(\d+\)(.*?)/,function(d,a,b,e,f){return a+'('+c+')'+b})}}function p(){return document.querySelector("section.entry")!==null}function e(){return document.querySelector(".items")!==null}function h(b){return e()?b?a.findParent(b,"item"):document.querySelector(".current-item"):document.querySelector(".entry")}function o(a,f){a.tagName!='A'&&(a=a.parentNode),a.style.display="none";let e=a.parentNode,b=document.createElement("span"),c=document.createElement("a");c.href="#",c.appendChild(document.createTextNode(a.dataset.labelYes)),c.onclick=d=>{d.preventDefault();let c=document.createElement("span");c.className="loading",c.appendChild(document.createTextNode(a.dataset.labelLoading)),b.remove(),e.appendChild(c),f(a.dataset.url,a.dataset.redirectUrl)};let d=document.createElement("a");d.href="#",d.appendChild(document.createTextNode(a.dataset.labelNo)),d.onclick=c=>{c.preventDefault(),a.style.display="inline",b.remove()},b.className="confirm",b.appendChild(document.createTextNode(a.dataset.labelQuestion+" ")),b.appendChild(c),b.appendChild(document.createTextNode(", ")),b.appendChild(d),e.appendChild(b)}function f(a){if(!a)return;document.querySelector('.toast-wrap .toast-msg').innerHTML=a;let b=document.querySelector('.toast-wrap');b.classList.remove('toastAnimate'),setTimeout(function(){b.classList.add('toastAnimate')},100)}document.addEventListener("DOMContentLoaded",function(){if(C(),!document.querySelector("body[data-disable-keyboard-shortcuts=true]")){let a=new M;a.on("g u",()=>b("unread")),a.on("g b",()=>b("starred")),a.on("g h",()=>b("history")),a.on("g f",()=>D()),a.on("g c",()=>b("categories")),a.on("g s",()=>b("settings")),a.on("ArrowLeft",()=>k()),a.on("ArrowRight",()=>j()),a.on("k",()=>k()),a.on("p",()=>k()),a.on("j",()=>j()),a.on("n",()=>j()),a.on("h",()=>b("previous")),a.on("l",()=>b("next")),a.on("z t",()=>z()),a.on("o",()=>P()),a.on("v",()=>w()),a.on("V",()=>w(!0)),a.on("c",()=>m()),a.on("C",()=>m(!0)),a.on("m",()=>x()),a.on("A",()=>q()),a.on("s",()=>r()),a.on("d",()=>v()),a.on("f",()=>t()),a.on("F",()=>s()),a.on("R",()=>L()),a.on("?",()=>A()),a.on("#",()=>H()),a.on("/",a=>u(a)),a.on("Escape",()=>g.close()),a.listen()}let a=new N;if(a.listen(),c("a[data-save-entry]",a=>r(a.target)),c("a[data-toggle-bookmark]",a=>t(a.target)),c("a[data-fetch-content-entry]",()=>v()),c("a[data-action=search]",a=>u(a)),c("a[data-action=markPageAsRead]",()=>o(event.target,()=>q())),c("a[data-toggle-status]",a=>x(a.target)),c("a[data-confirm]",a=>o(a.target,(c,a)=>{let b=new d(c);b.withCallback(()=>{a?window.location.href=a:window.location.reload()}),b.execute()})),document.documentElement.clientWidth<600&&(c(".logo",()=>K()),c(".header nav li",a=>G(a))),"serviceWorker"in navigator){let a=document.getElementById("service-worker-script");a&&navigator.serviceWorker.register(a.src)}window.addEventListener('beforeinstallprompt',c=>{c.preventDefault();let a=c;const b=document.getElementById('prompt-home-screen');if(b){b.style.display="block";const c=document.getElementById('btn-add-to-home-screen');c&&c.addEventListener('click',c=>{c.preventDefault(),a.prompt(),a.userChoice.then(()=>{a=null,b.style.display="none"})})}})})}()`, "service-worker": `self.addEventListener("fetch",a=>{a.request.url.includes("/feed/icon/")&&a.respondWith(caches.open("feed_icons").then(b=>b.match(a.request).then(c=>c||fetch(a.request).then(c=>(b.put(a.request,c.clone()),c)))))})`, } var JavascriptsChecksums = map[string]string{ - "app": "4fbd2da66463adba7faa2179665e33e6146a9080d799465453d9d408734c257c", + "app": "ce4de7e38f23b473e05c110385aee62df045eef7510c9b38e1aa469e8106f4d3", "service-worker": "730f10dc6a52e0bd9271da0c3b0103368893f3feb0a092fd585ac5b7abedb4ac", } diff --git a/ui/static/js/app.js b/ui/static/js/app.js index 043fbd44..8ff3fbd7 100644 --- a/ui/static/js/app.js +++ b/ui/static/js/app.js @@ -475,6 +475,13 @@ function goToNextListItem() { } } +function scrollToCurrentItem() { + let currentItem = document.querySelector(".current-item"); + if (currentItem !== null) { + DomHelper.scrollPageTo(currentItem, true); + } +} + function decrementUnreadCounter(n) { updateUnreadCounterValue((current) => { return current - n; diff --git a/ui/static/js/bootstrap.js b/ui/static/js/bootstrap.js index f652cea8..8b972bbc 100644 --- a/ui/static/js/bootstrap.js +++ b/ui/static/js/bootstrap.js @@ -17,6 +17,7 @@ document.addEventListener("DOMContentLoaded", function () { keyboardHandler.on("n", () => goToNext()); keyboardHandler.on("h", () => goToPage("previous")); keyboardHandler.on("l", () => goToPage("next")); + keyboardHandler.on("z t", () => scrollToCurrentItem()); keyboardHandler.on("o", () => openSelectedItem()); keyboardHandler.on("v", () => openOriginalLink()); keyboardHandler.on("V", () => openOriginalLink(true)); diff --git a/ui/static/js/dom_helper.js b/ui/static/js/dom_helper.js index 903e9a9c..fffa6965 100644 --- a/ui/static/js/dom_helper.js +++ b/ui/static/js/dom_helper.js @@ -10,13 +10,13 @@ class DomHelper { win.focus(); } - static scrollPageTo(element) { + static scrollPageTo(element, evenIfOnScreen) { let windowScrollPosition = window.pageYOffset; let windowHeight = document.documentElement.clientHeight; let viewportPosition = windowScrollPosition + windowHeight; let itemBottomPosition = element.offsetTop + element.offsetHeight; - if (viewportPosition - itemBottomPosition < 0 || viewportPosition - element.offsetTop > windowHeight) { + if (evenIfOnScreen || viewportPosition - itemBottomPosition < 0 || viewportPosition - element.offsetTop > windowHeight) { window.scrollTo(0, element.offsetTop - 10); } }