aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Carl Helmertz <carl.helmertz@elvaco.se>2018-10-14 00:43:09 +0200
committerGravatar Frédéric Guillot <fred@miniflux.net>2018-10-19 20:05:26 -0700
commit15a11c3da98a5375fad22c7cdeaa73d073bb473d (patch)
treea291e9515f95c7987c6a0711c4688998e9908567
parentb8f874a37d5ce57fb139e857b5cbd2276da46714 (diff)
Unsubscribe from feed through link or "#"
After importing old OPML files, you may discover that many feeds are obsolete or uninteresting. You list the feeds entries and determine that you want to unsubscribe. This needs three clicks (edit feed, delete, confirm) and requires moving the mouse to hit the different targets. This quickly becomes tiring, if you are up to possibly deleting hundreds of feeds. One mediation, introduced in this commit, is to add an unsubscribe link to each feed's entry listing view, and also adding a keyboard shortcut. The keyboard shortcut "#" is: * longer than one keystroke (requires shift) * hard to type by accident * used in Google products (thanks for the hint @fguillot) In an effort to try to reduce the number of accidental feed unsubscriptions.
-rw-r--r--generate.go1
-rwxr-xr-xlocale/translations.go21
-rw-r--r--locale/translations/de_DE.json1
-rw-r--r--locale/translations/en_US.json1
-rw-r--r--locale/translations/fr_FR.json1
-rw-r--r--locale/translations/nl_NL.json1
-rwxr-xr-xlocale/translations/pl_PL.json1
-rw-r--r--locale/translations/ru_RU.json1
-rw-r--r--locale/translations/zh_CN.json1
-rw-r--r--template/common.go3
-rw-r--r--template/html/common/layout.html1
-rw-r--r--template/html/edit_feed.html3
-rw-r--r--template/html/feed_entries.html11
-rw-r--r--template/views.go19
-rw-r--r--ui/static/js.go6
-rw-r--r--ui/static/js/bootstrap.js1
-rw-r--r--ui/static/js/feed_handler.js7
-rw-r--r--ui/static/js/nav_handler.js14
18 files changed, 80 insertions, 14 deletions
diff --git a/generate.go b/generate.go
index a06b68e..ac1c3cd 100644
--- a/generate.go
+++ b/generate.go
@@ -194,6 +194,7 @@ func main() {
"ui/static/js/request_builder.js",
"ui/static/js/unread_counter_handler.js",
"ui/static/js/entry_handler.js",
+ "ui/static/js/feed_handler.js",
"ui/static/js/confirm_handler.js",
"ui/static/js/menu_handler.js",
"ui/static/js/modal_handler.js",
diff --git a/locale/translations.go b/locale/translations.go
index 5c070cb..97614e1 100755
--- a/locale/translations.go
+++ b/locale/translations.go
@@ -128,6 +128,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.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",
"page.users.title": "Benutzer",
@@ -417,6 +418,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.remove_feed": "Remove this feed",
"page.keyboard_shortcuts.go_to_search": "Set focus on search form",
"page.keyboard_shortcuts.close_modal": "Close modal dialog",
"page.users.title": "Users",
@@ -686,6 +688,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.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",
"page.users.title": "Utilisateurs",
@@ -976,6 +979,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.remove_feed": "Verwijder deze feed",
"page.keyboard_shortcuts.go_to_search": "Focus instellen op zoekformulier",
"page.keyboard_shortcuts.close_modal": "Sluit dialoogscherm",
"page.users.title": "Gebruikers",
@@ -1264,6 +1268,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.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",
"page.users.title": "Użytkownicy",
@@ -1559,6 +1564,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.remove_feed": "Удалить эту подписку",
"page.keyboard_shortcuts.go_to_search": "Установить фокус в поисковой форме",
"page.keyboard_shortcuts.close_modal": "Закрыть модальный диалог",
"page.users.title": "Пользователи",
@@ -1832,6 +1838,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.remove_feed": "删除此Feed",
"page.keyboard_shortcuts.go_to_search": "将重点放在搜索表单上",
"page.keyboard_shortcuts.close_modal": "关闭模态对话窗口",
"page.users.title": "用户",
@@ -1991,11 +1998,11 @@ var translations = map[string]string{
}
var translationsChecksums = map[string]string{
- "de_DE": "099dea24a10c4f842674db2ae44f99e99b9c880a6f83e3a42502603fa228fd32",
- "en_US": "c23d1f16d1dbea72c1e1ba558c7a9c25e0ee8ffda420d50c998efe2fb4d9aa55",
- "fr_FR": "a5afa30bb63cba48fe0c2114a5e0bcb62dee7f1df0eb5748524decd280c80970",
- "nl_NL": "b1e548c2b21f013b1b54a07df7df7c06c776cbd7d26fc1fed288bd6970e99c3c",
- "pl_PL": "8cb856dede8b4f75e4c6aeb0a45f09507c5010f782692e887aae357e99674218",
- "ru_RU": "0544db0800811fc678521b2e9a7141380919b9ae259b3158524619bf120600ab",
- "zh_CN": "92687fecfaaf74489714c52903987e7027d8c1cda45b60aa081f7b2165ccaed5",
+ "de_DE": "67d3a4bb4e3985ff62882ad0dc73dd86137e474d3e33d41162701a7228913b0a",
+ "en_US": "db7298b54554207287e2ba15de03646164774368dad54e00197f0162d541643f",
+ "fr_FR": "fb08492db1984800e5e095f0f784b9b430caa8172c7e0ecbbbc7de08f4adfa60",
+ "nl_NL": "3bdd3e0150878bc9c196300c7cacb30efd01b7b5df3926950c443d01084b9cee",
+ "pl_PL": "b81ddb5c5955b043c571701f84d9f3f0a75574e69240c458c7a42f3a20a5aa7e",
+ "ru_RU": "343393224e21437009e047deb728e4ed036646ed3e4df6101a6bc3cd084b9996",
+ "zh_CN": "74aefbf6be418ea198fa70d6ed5c7dd8bb3b7b112d9c3f90ebff41fba8c314a3",
}
diff --git a/locale/translations/de_DE.json b/locale/translations/de_DE.json
index cddd8b3..d5bbad0 100644
--- a/locale/translations/de_DE.json
+++ b/locale/translations/de_DE.json
@@ -123,6 +123,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.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",
"page.users.title": "Benutzer",
diff --git a/locale/translations/en_US.json b/locale/translations/en_US.json
index 4a85fff..83367be 100644
--- a/locale/translations/en_US.json
+++ b/locale/translations/en_US.json
@@ -123,6 +123,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.remove_feed": "Remove this feed",
"page.keyboard_shortcuts.go_to_search": "Set focus on search form",
"page.keyboard_shortcuts.close_modal": "Close modal dialog",
"page.users.title": "Users",
diff --git a/locale/translations/fr_FR.json b/locale/translations/fr_FR.json
index 5138b3d..9b2f47d 100644
--- a/locale/translations/fr_FR.json
+++ b/locale/translations/fr_FR.json
@@ -123,6 +123,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.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",
"page.users.title": "Utilisateurs",
diff --git a/locale/translations/nl_NL.json b/locale/translations/nl_NL.json
index b458b5b..ad54220 100644
--- a/locale/translations/nl_NL.json
+++ b/locale/translations/nl_NL.json
@@ -124,6 +124,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.remove_feed": "Verwijder deze feed",
"page.keyboard_shortcuts.go_to_search": "Focus instellen op zoekformulier",
"page.keyboard_shortcuts.close_modal": "Sluit dialoogscherm",
"page.users.title": "Gebruikers",
diff --git a/locale/translations/pl_PL.json b/locale/translations/pl_PL.json
index a7b3513..d9d4678 100755
--- a/locale/translations/pl_PL.json
+++ b/locale/translations/pl_PL.json
@@ -125,6 +125,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.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",
"page.users.title": "Użytkownicy",
diff --git a/locale/translations/ru_RU.json b/locale/translations/ru_RU.json
index 738af46..ef1a200 100644
--- a/locale/translations/ru_RU.json
+++ b/locale/translations/ru_RU.json
@@ -125,6 +125,7 @@
"page.keyboard_shortcuts.download_content": "Загрузить оригинальное содержимое",
"page.keyboard_shortcuts.toggle_bookmark_status": "Переключатель избранного",
"page.keyboard_shortcuts.save_article": "Сохранить статью",
+ "page.keyboard_shortcuts.remove_feed": "Удалить эту подписку",
"page.keyboard_shortcuts.go_to_search": "Установить фокус в поисковой форме",
"page.keyboard_shortcuts.close_modal": "Закрыть модальный диалог",
"page.users.title": "Пользователи",
diff --git a/locale/translations/zh_CN.json b/locale/translations/zh_CN.json
index 1efa6b7..1501641 100644
--- a/locale/translations/zh_CN.json
+++ b/locale/translations/zh_CN.json
@@ -121,6 +121,7 @@
"page.keyboard_shortcuts.download_content": "下载原始内容",
"page.keyboard_shortcuts.toggle_bookmark_status": "切换收藏状态",
"page.keyboard_shortcuts.save_article": "保存文章",
+ "page.keyboard_shortcuts.remove_feed": "删除此Feed",
"page.keyboard_shortcuts.go_to_search": "将重点放在搜索表单上",
"page.keyboard_shortcuts.close_modal": "关闭模态对话窗口",
"page.users.title": "用户",
diff --git a/template/common.go b/template/common.go
index bfd3f7a..1afb9f1 100644
--- a/template/common.go
+++ b/template/common.go
@@ -208,6 +208,7 @@ var templateCommonMap = map[string]string{
<li>{{ t "page.keyboard_shortcuts.download_content" }} = <strong>d</strong></li>
<li>{{ t "page.keyboard_shortcuts.toggle_bookmark_status" }} = <strong>f</strong></li>
<li>{{ t "page.keyboard_shortcuts.save_article" }} = <strong>s</strong></li>
+ <li>{{ t "page.keyboard_shortcuts.remove_feed" }} = <strong>#</strong></li>
<li>{{ t "page.keyboard_shortcuts.go_to_search" }} = <strong>/</strong></li>
<li>{{ t "page.keyboard_shortcuts.close_modal" }} = <strong>Esc</strong></li>
</ul>
@@ -243,6 +244,6 @@ var templateCommonMap = map[string]string{
var templateCommonMapChecksums = map[string]string{
"entry_pagination": "4faa91e2eae150c5e4eab4d258e039dfdd413bab7602f0009360e6d52898e353",
"item_meta": "34deb081a054f2948ad808bdb2c8603d6ab00c58f2f50c4ead0b47ae092888eb",
- "layout": "d1795cedbbc0fc6ec7a5e31039e10b8361b7a74bcca74d860f127ac159036ab6",
+ "layout": "69ba8db45fde768cf71bab7dba60cece39968a185cec58850582dec11668efec",
"pagination": "3386e90c6e1230311459e9a484629bc5d5bf39514a75ef2e73bbbc61142f7abb",
}
diff --git a/template/html/common/layout.html b/template/html/common/layout.html
index a79032d..cf49fa5 100644
--- a/template/html/common/layout.html
+++ b/template/html/common/layout.html
@@ -134,6 +134,7 @@
<li>{{ t "page.keyboard_shortcuts.download_content" }} = <strong>d</strong></li>
<li>{{ t "page.keyboard_shortcuts.toggle_bookmark_status" }} = <strong>f</strong></li>
<li>{{ t "page.keyboard_shortcuts.save_article" }} = <strong>s</strong></li>
+ <li>{{ t "page.keyboard_shortcuts.remove_feed" }} = <strong>#</strong></li>
<li>{{ t "page.keyboard_shortcuts.go_to_search" }} = <strong>/</strong></li>
<li>{{ t "page.keyboard_shortcuts.close_modal" }} = <strong>Esc</strong></li>
</ul>
diff --git a/template/html/edit_feed.html b/template/html/edit_feed.html
index b827435..73a2e27 100644
--- a/template/html/edit_feed.html
+++ b/template/html/edit_feed.html
@@ -92,6 +92,7 @@
<div class="alert alert-error">
<a href="#"
data-confirm="true"
+ data-action="remove-feed"
data-label-question="{{ t "confirm.question" }}"
data-label-yes="{{ t "confirm.yes" }}"
data-label-no="{{ t "confirm.no" }}"
@@ -101,4 +102,4 @@
</div>
{{ end }}
-{{ end }} \ No newline at end of file
+{{ end }}
diff --git a/template/html/feed_entries.html b/template/html/feed_entries.html
index a85cffc..cdc435c 100644
--- a/template/html/feed_entries.html
+++ b/template/html/feed_entries.html
@@ -15,6 +15,17 @@
<li>
<a href="{{ route "editFeed" "feedID" .feed.ID }}">{{ t "menu.edit_feed" }}</a>
</li>
+ <li>
+ <a href="#"
+ data-confirm="true"
+ data-action="remove-feed"
+ data-label-question="{{ t "confirm.question" }}"
+ data-label-yes="{{ t "confirm.yes" }}"
+ data-label-no="{{ t "confirm.no" }}"
+ data-label-loading="{{ t "confirm.loading" }}"
+ data-url="{{ route "removeFeed" "feedID" .feed.ID }}"
+ data-redirect-url="{{ route "feeds" }}">{{ t "action.remove_feed" }}</a>
+ </li>
</ul>
</section>
diff --git a/template/views.go b/template/views.go
index 0dc2671..3a01ec1 100644
--- a/template/views.go
+++ b/template/views.go
@@ -492,6 +492,7 @@ var templateViewsMap = map[string]string{
<div class="alert alert-error">
<a href="#"
data-confirm="true"
+ data-action="remove-feed"
data-label-question="{{ t "confirm.question" }}"
data-label-yes="{{ t "confirm.yes" }}"
data-label-no="{{ t "confirm.no" }}"
@@ -501,7 +502,8 @@ var templateViewsMap = map[string]string{
</div>
{{ end }}
-{{ end }}`,
+{{ end }}
+`,
"edit_user": `{{ define "title"}}{{ t "page.edit_user.title" .selected_user.Username }}{{ end }}
{{ define "content"}}
@@ -696,6 +698,17 @@ var templateViewsMap = map[string]string{
<li>
<a href="{{ route "editFeed" "feedID" .feed.ID }}">{{ t "menu.edit_feed" }}</a>
</li>
+ <li>
+ <a href="#"
+ data-confirm="true"
+ data-action="remove-feed"
+ data-label-question="{{ t "confirm.question" }}"
+ data-label-yes="{{ t "confirm.yes" }}"
+ data-label-no="{{ t "confirm.no" }}"
+ data-label-loading="{{ t "confirm.loading" }}"
+ data-url="{{ route "removeFeed" "feedID" .feed.ID }}"
+ data-redirect-url="{{ route "feeds" }}">{{ t "action.remove_feed" }}</a>
+ </li>
</ul>
</section>
@@ -1377,10 +1390,10 @@ var templateViewsMapChecksums = map[string]string{
"create_category": "6b22b5ce51abf4e225e23a79f81be09a7fb90acb265e93a8faf9446dff74018d",
"create_user": "1e940be3afefc0a5c6273bbadcddc1e29811e9548e5227ac2adfe697ca5ce081",
"edit_category": "daf073d2944a180ce5aaeb80b597eb69597a50dff55a9a1d6cf7938b48d768cb",
- "edit_feed": "191c4c1f73e9f8d16938ec8cbd29afc7d7d1d17777394094bcf414ab198d9e51",
+ "edit_feed": "ab30c31a4385a7b16c54baa78bdcb93a57181ed1c5018ce097d7eb50673bb995",
"edit_user": "f4f99412ba771cfca2a2a42778b023b413c5494e9a287053ba8cf380c2865c5f",
"entry": "2ea9fee1ae5513ef1abb5923221c2ef1212e26d3bb651da66069ce8a336cbb7c",
- "feed_entries": "814b58b106313d53f2929e5257c79e47a7e09d715e493f150d9dc3a8c97eaa4e",
+ "feed_entries": "0f3d02d820475a3b0e165e10be2bf39fa5ab6a9dc5b0945c9ad886434e64e6ca",
"feeds": "31acc253c547a6cce5710d72a6f6b3b396162ecd5e5af295b2cf47c1ff55bd06",
"history_entries": "b65ca1d85615caa7c314a33f1cb997aa3477a79e66b9894b2fd387271ad467d2",
"import": "8349e47a783bb40d8e9248b4771656e5f006185e11079e1c4680dd52633420ed",
diff --git a/ui/static/js.go b/ui/static/js.go
index 90d78f0..5ffc0b8 100644
--- a/ui/static/js.go
+++ b/ui/static/js.go
@@ -56,6 +56,7 @@ static saveEntry(element){if(element.dataset.completed){return;}
element.innerHTML=element.dataset.labelLoading;let request=new RequestBuilder(element.dataset.saveUrl);request.withCallback(()=>{element.innerHTML=element.dataset.labelDone;element.dataset.completed=true;});request.execute();}
static fetchOriginalContent(element){if(element.dataset.completed){return;}
element.innerHTML=element.dataset.labelLoading;let request=new RequestBuilder(element.dataset.fetchContentUrl);request.withCallback((response)=>{element.innerHTML=element.dataset.labelDone;element.dataset.completed=true;response.json().then((data)=>{if(data.hasOwnProperty("content")){document.querySelector(".entry-content").innerHTML=data.content;}});});request.execute();}}
+class FeedHandler{static unsubscribe(feedUrl,callback){let request=new RequestBuilder(feedUrl);request.withCallback(callback);request.execute();}}
class ConfirmHandler{executeRequest(url,redirectURL){let request=new RequestBuilder(url);request.withCallback(()=>{if(redirectURL){window.location.href=redirectURL;}else{window.location.reload();}});request.execute();}
handle(event){let questionElement=document.createElement("span");let linkElement=event.target;let containerElement=linkElement.parentNode;linkElement.style.display="none";let yesElement=document.createElement("a");yesElement.href="#";yesElement.appendChild(document.createTextNode(linkElement.dataset.labelYes));yesElement.onclick=(event)=>{event.preventDefault();let loadingElement=document.createElement("span");loadingElement.className="loading";loadingElement.appendChild(document.createTextNode(linkElement.dataset.labelLoading));questionElement.remove();containerElement.appendChild(loadingElement);this.executeRequest(linkElement.dataset.url,linkElement.dataset.redirectUrl);};let noElement=document.createElement("a");noElement.href="#";noElement.appendChild(document.createTextNode(linkElement.dataset.labelNo));noElement.onclick=(event)=>{event.preventDefault();linkElement.style.display="inline";questionElement.remove();};questionElement.className="confirm";questionElement.appendChild(document.createTextNode(linkElement.dataset.labelQuestion+" "));questionElement.appendChild(yesElement);questionElement.appendChild(document.createTextNode(", "));questionElement.appendChild(noElement);containerElement.appendChild(questionElement);}}
class MenuHandler{clickMenuListItem(event){let element=event.target;if(element.tagName==="A"){window.location.href=element.getAttribute("href");}else{window.location.href=element.querySelector("a").getAttribute("href");}}
@@ -80,6 +81,7 @@ toggleBookmarkLink(parent){let bookmarkLink=parent.querySelector("a[data-toggle-
openOriginalLink(){let entryLink=document.querySelector(".entry h1 a");if(entryLink!==null){DomHelper.openNewTab(entryLink.getAttribute("href"));return;}
let currentItemOriginalLink=document.querySelector(".current-item a[data-original-link]");if(currentItemOriginalLink!==null){DomHelper.openNewTab(currentItemOriginalLink.getAttribute("href"));let currentItem=document.querySelector(".current-item");this.goToNextListItem();EntryHandler.markEntryAsRead(currentItem);}}
openSelectedItem(){let currentItemLink=document.querySelector(".current-item .item-title a");if(currentItemLink!==null){window.location.href=currentItemLink.getAttribute("href");}}
+unsubscribeFromFeed(){let unsubscribeLinks=document.querySelectorAll("[data-action=remove-feed]");if(unsubscribeLinks.length===1){let unsubscribeLink=unsubscribeLinks[0];FeedHandler.unsubscribe(unsubscribeLink.dataset.url,()=>{if(unsubscribeLink.dataset.redirectUrl){window.location.href=unsubscribeLink.dataset.redirectUrl;}else{window.location.reload();}});}}
goToPage(page,fallbackSelf){let element=document.querySelector("a[data-page="+page+"]");if(element){document.location.href=element.href;}else if(fallbackSelf){window.location.reload();}}
goToPrevious(){if(this.isListView()){this.goToPreviousListItem();}else{this.goToPage("previous");}}
goToNext(){if(this.isListView()){this.goToNextListItem();}else{this.goToPage("next");}}
@@ -93,13 +95,13 @@ for(let i=0;i<items.length;i++){if(items[i].classList.contains("current-item")){
break;}}}
isListView(){return document.querySelector(".items")!==null;}}
class LinkStateHandler{static flip(element){let labelElement=document.createElement("span");labelElement.className="link-flipped-state";labelElement.appendChild(document.createTextNode(element.dataset.labelNewState));element.parentNode.appendChild(labelElement);element.parentNode.removeChild(element);}}
-document.addEventListener("DOMContentLoaded",function(){FormHandler.handleSubmitButtons();let touchHandler=new TouchHandler();touchHandler.listen();let navHandler=new NavHandler();let keyboardHandler=new KeyboardHandler();keyboardHandler.on("g u",()=>navHandler.goToPage("unread"));keyboardHandler.on("g b",()=>navHandler.goToPage("starred"));keyboardHandler.on("g h",()=>navHandler.goToPage("history"));keyboardHandler.on("g f",()=>navHandler.goToPage("feeds"));keyboardHandler.on("g c",()=>navHandler.goToPage("categories"));keyboardHandler.on("g s",()=>navHandler.goToPage("settings"));keyboardHandler.on("ArrowLeft",()=>navHandler.goToPrevious());keyboardHandler.on("ArrowRight",()=>navHandler.goToNext());keyboardHandler.on("j",()=>navHandler.goToPrevious());keyboardHandler.on("p",()=>navHandler.goToPrevious());keyboardHandler.on("k",()=>navHandler.goToNext());keyboardHandler.on("n",()=>navHandler.goToNext());keyboardHandler.on("h",()=>navHandler.goToPage("previous"));keyboardHandler.on("l",()=>navHandler.goToPage("next"));keyboardHandler.on("o",()=>navHandler.openSelectedItem());keyboardHandler.on("v",()=>navHandler.openOriginalLink());keyboardHandler.on("m",()=>navHandler.toggleEntryStatus());keyboardHandler.on("A",()=>navHandler.markPageAsRead());keyboardHandler.on("s",()=>navHandler.saveEntry());keyboardHandler.on("d",()=>navHandler.fetchOriginalContent());keyboardHandler.on("f",()=>navHandler.toggleBookmark());keyboardHandler.on("?",()=>navHandler.showKeyboardShortcuts());keyboardHandler.on("/",(e)=>navHandler.setFocusToSearchInput(e));keyboardHandler.on("Escape",()=>ModalHandler.close());keyboardHandler.listen();let mouseHandler=new MouseHandler();mouseHandler.onClick("a[data-save-entry]",(event)=>{EntryHandler.saveEntry(event.target);});mouseHandler.onClick("a[data-toggle-bookmark]",(event)=>{EntryHandler.toggleBookmark(event.target);});mouseHandler.onClick("a[data-toggle-status]",(event)=>{let currentItem=DomHelper.findParent(event.target,"entry");if(!currentItem){currentItem=DomHelper.findParent(event.target,"item");}
+document.addEventListener("DOMContentLoaded",function(){FormHandler.handleSubmitButtons();let touchHandler=new TouchHandler();touchHandler.listen();let navHandler=new NavHandler();let keyboardHandler=new KeyboardHandler();keyboardHandler.on("g u",()=>navHandler.goToPage("unread"));keyboardHandler.on("g b",()=>navHandler.goToPage("starred"));keyboardHandler.on("g h",()=>navHandler.goToPage("history"));keyboardHandler.on("g f",()=>navHandler.goToPage("feeds"));keyboardHandler.on("g c",()=>navHandler.goToPage("categories"));keyboardHandler.on("g s",()=>navHandler.goToPage("settings"));keyboardHandler.on("ArrowLeft",()=>navHandler.goToPrevious());keyboardHandler.on("ArrowRight",()=>navHandler.goToNext());keyboardHandler.on("j",()=>navHandler.goToPrevious());keyboardHandler.on("p",()=>navHandler.goToPrevious());keyboardHandler.on("k",()=>navHandler.goToNext());keyboardHandler.on("n",()=>navHandler.goToNext());keyboardHandler.on("h",()=>navHandler.goToPage("previous"));keyboardHandler.on("l",()=>navHandler.goToPage("next"));keyboardHandler.on("o",()=>navHandler.openSelectedItem());keyboardHandler.on("v",()=>navHandler.openOriginalLink());keyboardHandler.on("m",()=>navHandler.toggleEntryStatus());keyboardHandler.on("A",()=>navHandler.markPageAsRead());keyboardHandler.on("s",()=>navHandler.saveEntry());keyboardHandler.on("d",()=>navHandler.fetchOriginalContent());keyboardHandler.on("f",()=>navHandler.toggleBookmark());keyboardHandler.on("?",()=>navHandler.showKeyboardShortcuts());keyboardHandler.on("#",()=>navHandler.unsubscribeFromFeed());keyboardHandler.on("/",(e)=>navHandler.setFocusToSearchInput(e));keyboardHandler.on("Escape",()=>ModalHandler.close());keyboardHandler.listen();let mouseHandler=new MouseHandler();mouseHandler.onClick("a[data-save-entry]",(event)=>{EntryHandler.saveEntry(event.target);});mouseHandler.onClick("a[data-toggle-bookmark]",(event)=>{EntryHandler.toggleBookmark(event.target);});mouseHandler.onClick("a[data-toggle-status]",(event)=>{let currentItem=DomHelper.findParent(event.target,"entry");if(!currentItem){currentItem=DomHelper.findParent(event.target,"item");}
if(currentItem){EntryHandler.toggleEntryStatus(currentItem);}});mouseHandler.onClick("a[data-fetch-content-entry]",(event)=>{EntryHandler.fetchOriginalContent(event.target);});mouseHandler.onClick("a[data-on-click=markPageAsRead]",()=>navHandler.markPageAsRead());mouseHandler.onClick("a[data-confirm]",(event)=>{(new ConfirmHandler()).handle(event);});mouseHandler.onClick("a[data-action=search]",(event)=>{navHandler.setFocusToSearchInput(event);});mouseHandler.onClick("a[data-link-state=flip]",(event)=>{LinkStateHandler.flip(event.target);},true);if(document.documentElement.clientWidth<600){let menuHandler=new MenuHandler();mouseHandler.onClick(".logo",()=>menuHandler.toggleMainMenu());mouseHandler.onClick(".header nav li",(event)=>menuHandler.clickMenuListItem(event));}
if("serviceWorker"in navigator){let scriptElement=document.getElementById("service-worker-script");if(scriptElement){navigator.serviceWorker.register(scriptElement.src);}}});})();`,
"sw": `'use strict';self.addEventListener("fetch",(event)=>{if(event.request.url.includes("/feed/icon/")){event.respondWith(caches.open("feed_icons").then((cache)=>{return cache.match(event.request).then((response)=>{return response||fetch(event.request).then((response)=>{cache.put(event.request,response.clone());return response;});});}));}});`,
}
var JavascriptsChecksums = map[string]string{
- "app": "205a1e308450a89d71ecf7d278718fd030a13d97cd1b49f75855029cc5ff613c",
+ "app": "6d1dc775cab31cdb7275e38c32c4ae714e330df897c7515e84e021878359e3d5",
"sw": "55fffa223919cc18572788fb9c62fccf92166c0eb5d3a1d6f91c31f24d020be9",
}
diff --git a/ui/static/js/bootstrap.js b/ui/static/js/bootstrap.js
index a89799a..3c2bb35 100644
--- a/ui/static/js/bootstrap.js
+++ b/ui/static/js/bootstrap.js
@@ -28,6 +28,7 @@ document.addEventListener("DOMContentLoaded", function() {
keyboardHandler.on("d", () => navHandler.fetchOriginalContent());
keyboardHandler.on("f", () => navHandler.toggleBookmark());
keyboardHandler.on("?", () => navHandler.showKeyboardShortcuts());
+ keyboardHandler.on("#", () => navHandler.unsubscribeFromFeed());
keyboardHandler.on("/", (e) => navHandler.setFocusToSearchInput(e));
keyboardHandler.on("Escape", () => ModalHandler.close());
keyboardHandler.listen();
diff --git a/ui/static/js/feed_handler.js b/ui/static/js/feed_handler.js
new file mode 100644
index 0000000..1d4190f
--- /dev/null
+++ b/ui/static/js/feed_handler.js
@@ -0,0 +1,7 @@
+class FeedHandler {
+ static unsubscribe(feedUrl, callback) {
+ let request = new RequestBuilder(feedUrl);
+ request.withCallback(callback);
+ request.execute();
+ }
+}
diff --git a/ui/static/js/nav_handler.js b/ui/static/js/nav_handler.js
index 5d2474b..5f611e0 100644
--- a/ui/static/js/nav_handler.js
+++ b/ui/static/js/nav_handler.js
@@ -129,6 +129,20 @@ class NavHandler {
}
}
+ unsubscribeFromFeed() {
+ let unsubscribeLinks = document.querySelectorAll("[data-action=remove-feed]");
+ if (unsubscribeLinks.length === 1) {
+ let unsubscribeLink = unsubscribeLinks[0];
+ FeedHandler.unsubscribe(unsubscribeLink.dataset.url, () => {
+ if (unsubscribeLink.dataset.redirectUrl) {
+ window.location.href = unsubscribeLink.dataset.redirectUrl;
+ } else {
+ window.location.reload();
+ }
+ });
+ }
+ }
+
/**
* @param {string} page Page to redirect to.
* @param {boolean} fallbackSelf Refresh actual page if the page is not found.