diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-12-01 14:47:34 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-12-01 14:47:34 +0200 |
commit | b18b380014222131572a186888e6aa035c9c06e1 (patch) | |
tree | d21e066681c67b094ddfa0c67e03b77c39f1780b /src/ui | |
parent | d87edbfc4907b0985b107e1432f73104eb66d356 (diff) |
Subscribing to new headings on a page
When "subscribed" and "headings" tags are used, the subscribed page is tracked for newly added headings (of any kind).
This works for the weiph/pikkulogs out there.
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/documentwidget.c | 35 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 22 |
2 files changed, 43 insertions, 14 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index cca77c15..96440feb 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -171,6 +171,7 @@ struct Impl_DocumentWidget { | |||
171 | const iGmRun * firstVisibleRun; | 171 | const iGmRun * firstVisibleRun; |
172 | const iGmRun * lastVisibleRun; | 172 | const iGmRun * lastVisibleRun; |
173 | iClick click; | 173 | iClick click; |
174 | iString pendingGotoHeading; | ||
174 | float initNormScrollY; | 175 | float initNormScrollY; |
175 | iAnim scrollY; | 176 | iAnim scrollY; |
176 | iAnim sideOpacity; | 177 | iAnim sideOpacity; |
@@ -230,6 +231,7 @@ void init_DocumentWidget(iDocumentWidget *d) { | |||
230 | init_PtrArray(&d->visiblePlayers); | 231 | init_PtrArray(&d->visiblePlayers); |
231 | d->grabbedPlayer = NULL; | 232 | d->grabbedPlayer = NULL; |
232 | d->playerTimer = 0; | 233 | d->playerTimer = 0; |
234 | init_String(&d->pendingGotoHeading); | ||
233 | init_Click(&d->click, d, SDL_BUTTON_LEFT); | 235 | init_Click(&d->click, d, SDL_BUTTON_LEFT); |
234 | addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); | 236 | addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); |
235 | d->menu = NULL; /* created when clicking */ | 237 | d->menu = NULL; /* created when clicking */ |
@@ -259,6 +261,7 @@ void deinit_DocumentWidget(iDocumentWidget *d) { | |||
259 | deinit_Array(&d->outline); | 261 | deinit_Array(&d->outline); |
260 | iRelease(d->media); | 262 | iRelease(d->media); |
261 | iRelease(d->request); | 263 | iRelease(d->request); |
264 | deinit_String(&d->pendingGotoHeading); | ||
262 | deinit_Block(&d->sourceContent); | 265 | deinit_Block(&d->sourceContent); |
263 | deinit_String(&d->sourceMime); | 266 | deinit_String(&d->sourceMime); |
264 | iRelease(d->doc); | 267 | iRelease(d->doc); |
@@ -1070,6 +1073,16 @@ static void scrollTo_DocumentWidget_(iDocumentWidget *d, int documentY, iBool ce | |||
1070 | scroll_DocumentWidget_(d, 0); /* clamp it */ | 1073 | scroll_DocumentWidget_(d, 0); /* clamp it */ |
1071 | } | 1074 | } |
1072 | 1075 | ||
1076 | static void scrollToHeading_DocumentWidget_(iDocumentWidget *d, const char *heading) { | ||
1077 | iConstForEach(Array, h, headings_GmDocument(d->doc)) { | ||
1078 | const iGmHeading *head = h.value; | ||
1079 | if (startsWithCase_Rangecc(head->text, heading)) { | ||
1080 | postCommandf_App("document.goto loc:%p", head->text.start); | ||
1081 | break; | ||
1082 | } | ||
1083 | } | ||
1084 | } | ||
1085 | |||
1073 | static void scrollWideBlock_DocumentWidget_(iDocumentWidget *d, iInt2 mousePos, int delta, | 1086 | static void scrollWideBlock_DocumentWidget_(iDocumentWidget *d, iInt2 mousePos, int delta, |
1074 | int duration) { | 1087 | int duration) { |
1075 | if (delta == 0) { | 1088 | if (delta == 0) { |
@@ -1623,6 +1636,11 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1623 | updateSideIconBuf_DocumentWidget_(d); | 1636 | updateSideIconBuf_DocumentWidget_(d); |
1624 | updateOutline_DocumentWidget_(d); | 1637 | updateOutline_DocumentWidget_(d); |
1625 | postCommandf_App("document.changed url:%s", cstr_String(d->mod.url)); | 1638 | postCommandf_App("document.changed url:%s", cstr_String(d->mod.url)); |
1639 | /* Check for a pending goto. */ | ||
1640 | if (!isEmpty_String(&d->pendingGotoHeading)) { | ||
1641 | scrollToHeading_DocumentWidget_(d, cstr_String(&d->pendingGotoHeading)); | ||
1642 | clear_String(&d->pendingGotoHeading); | ||
1643 | } | ||
1626 | return iFalse; | 1644 | return iFalse; |
1627 | } | 1645 | } |
1628 | else if (equal_Command(cmd, "media.updated") || equal_Command(cmd, "media.finished")) { | 1646 | else if (equal_Command(cmd, "media.updated") || equal_Command(cmd, "media.finished")) { |
@@ -1779,17 +1797,14 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1779 | return iTrue; | 1797 | return iTrue; |
1780 | } | 1798 | } |
1781 | else if (equal_Command(cmd, "document.goto") && document_App() == d) { | 1799 | else if (equal_Command(cmd, "document.goto") && document_App() == d) { |
1782 | const iRangecc heading = range_Command(cmd, "heading"); | 1800 | const char *heading = suffixPtr_Command(cmd, "heading"); |
1783 | if (heading.start) { | 1801 | if (heading) { |
1784 | const char *target = cstr_Rangecc(heading); | 1802 | if (isRequestOngoing_DocumentWidget(d)) { |
1785 | iConstForEach(Array, h, headings_GmDocument(d->doc)) { | 1803 | /* Scroll position set when request finishes. */ |
1786 | const iGmHeading *head = h.value; | 1804 | setCStr_String(&d->pendingGotoHeading, heading); |
1787 | if (startsWithCase_Rangecc(head->text, target)) { | 1805 | return iTrue; |
1788 | /* TODO: A bit lazy here, the code is right down below. */ | ||
1789 | postCommandf_App("document.goto loc:%p", head->text.start); | ||
1790 | break; | ||
1791 | } | ||
1792 | } | 1806 | } |
1807 | scrollToHeading_DocumentWidget_(d, heading); | ||
1793 | return iTrue; | 1808 | return iTrue; |
1794 | } | 1809 | } |
1795 | const char *loc = pointerLabel_Command(cmd, "loc"); | 1810 | const char *loc = pointerLabel_Command(cmd, "loc"); |
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 6bb6d7a1..5baa08f7 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c | |||
@@ -123,6 +123,9 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { | |||
123 | iZap(on); | 123 | iZap(on); |
124 | iConstForEach(PtrArray, i, listEntries_Feeds()) { | 124 | iConstForEach(PtrArray, i, listEntries_Feeds()) { |
125 | const iFeedEntry *entry = i.ptr; | 125 | const iFeedEntry *entry = i.ptr; |
126 | if (isHidden_FeedEntry(entry)) { | ||
127 | continue; /* A hidden entry. */ | ||
128 | } | ||
126 | /* For more items, one can always see "about:feeds". A large number of items | 129 | /* For more items, one can always see "about:feeds". A large number of items |
127 | is a bit difficult to navigate in the sidebar. */ | 130 | is a bit difficult to navigate in the sidebar. */ |
128 | if (numItems_ListWidget(d->list) == 100) { | 131 | if (numItems_ListWidget(d->list) == 100) { |
@@ -151,9 +154,7 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { | |||
151 | if (equal_String(docUrl, &entry->url)) { | 154 | if (equal_String(docUrl, &entry->url)) { |
152 | item->listItem.isSelected = iTrue; /* currently being viewed */ | 155 | item->listItem.isSelected = iTrue; /* currently being viewed */ |
153 | } | 156 | } |
154 | if (!containsUrl_Visited(visited_App(), &entry->url)) { | 157 | item->indent = isUnread_FeedEntry(entry); |
155 | item->indent = 1; /* unread */ | ||
156 | } | ||
157 | set_String(&item->url, &entry->url); | 158 | set_String(&item->url, &entry->url); |
158 | set_String(&item->label, &entry->title); | 159 | set_String(&item->label, &entry->title); |
159 | const iBookmark *bm = get_Bookmarks(bookmarks_App(), entry->bookmarkId); | 160 | const iBookmark *bm = get_Bookmarks(bookmarks_App(), entry->bookmarkId); |
@@ -498,7 +499,20 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, const iSidebarItem *it | |||
498 | } | 499 | } |
499 | case feeds_SidebarMode: | 500 | case feeds_SidebarMode: |
500 | if (!isEmpty_String(&item->url)) { | 501 | if (!isEmpty_String(&item->url)) { |
501 | postCommandf_App("open url:%s", cstr_String(&item->url)); | 502 | const size_t fragPos = indexOf_String(&item->url, '#'); |
503 | if (fragPos != iInvalidPos) { | ||
504 | iString *head = collect_String( | ||
505 | newRange_String((iRangecc){ constBegin_String(&item->url) + fragPos + 1, | ||
506 | constEnd_String(&item->url) })); | ||
507 | postCommandf_App( | ||
508 | "open gotourlheading:%s url:%s", | ||
509 | cstr_String(head), | ||
510 | cstr_Rangecc((iRangecc){ constBegin_String(&item->url), | ||
511 | constBegin_String(&item->url) + fragPos })); | ||
512 | } | ||
513 | else { | ||
514 | postCommandf_App("open url:%s", cstr_String(&item->url)); | ||
515 | } | ||
502 | } | 516 | } |
503 | break; | 517 | break; |
504 | case bookmarks_SidebarMode: | 518 | case bookmarks_SidebarMode: |