Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make selfoss navigable #834

Merged
merged 16 commits into from
Feb 4, 2017
Merged

Make selfoss navigable #834

merged 16 commits into from
Feb 4, 2017

Conversation

niol
Copy link
Collaborator

@niol niol commented Dec 28, 2016

These patches make selfoss navigable using the url hash. This makes the url reflect whats displayed in selfoss. This also makes it possible to reload the item that was open before a browser crash or when the tab containing selfoss was offloaded from memory on a mobile browser.

niol added 4 commits December 22, 2016 15:58
This pages modifies the client ui to make heavy use of location.hash: hash
changes are now responsible for loading the entry list.

Another big change is that the server side template is basically empty of any
data. It is loaded via the same client side code responsible for updating
item lists, tags, stats, etc.
@jtojnar
Copy link
Member

jtojnar commented Dec 29, 2016

For fixing #774, would not it be cleaner to use where id < :id_of_last_loaded_item instead of offset + extra_ids? It could also be slightly faster as we can have index on id. I like the rest of 2f87dd1, though.

@jtojnar
Copy link
Member

jtojnar commented Dec 29, 2016

Regarding the second part, I discovered some edge cases:

  1. Tag names are URL-encoded twice, causing tags using Unicode not to work. For example, 新闻国内 turns into
    /selfoss/?offset=0&itemsPerPage=50&search=&type=unread&tag=%25E6%2596%25B0%25E9%2597%25BB%25E5%259B%25BD%25E5%2586%2585&source=&sourcesNav=false&ajax=true – notice the %25 instead of %.
  2. Visiting item on one of the lower pages does not expand it. We might show the visited item on top, as loading all the preceding items when visiting an older item might not be feasible.
    Now I also see why you choose the extra_ids, though I still think that using the id < :id_of_last_loaded_item might be better than sending the list of all the read items when loading next page.
  3. Visiting source listing does not expand the sources in the sidebar like clicking the item source does.
  4. Item from a source not in a certain tag can be visited through the tag’s URL. This is probably not worthy of worrying about.

I did not check the code in 8b7f8d2 very deeply yet.

@bendem
Copy link

bendem commented Dec 29, 2016

Agreed with @jtojnar, here is some explanation in regard to why offset/limit pagination is considered bad.
https://blog.jooq.org/2016/08/10/why-most-programmers-get-pagination-wrong/

@niol
Copy link
Collaborator Author

niol commented Dec 29, 2016

Point 1, I cannot reproduce with multiple unicode strings using Chromium as browser.
Regarding the cleaner and id comparison, this would not work as we order by datetime and not id and that may not be the same order (a source crawled after but with an older item will have a higher id). I'll run some basic tests to see if seek pagination is worth it regarding performance. It looks very interesting but is not related to fixing that bug.

@jtojnar
Copy link
Member

jtojnar commented Dec 29, 2016

Indeed, it seems to work in Chromium as document.location.hash === "#unread/tag-新闻国内". In Firefox it is "#unread/tag-%E6%96%B0%E9%97%BB%E5%9B%BD%E5%86%85".

As for the seek pagination, my bad. The items would have to be sorted by datetime DESC, id DESC and then filtered using (datetime, id) < (:last_datetime, last_id); index could be created for this column pair.

Although I think the performance difference will be negligible in most installation, as selfoss, by default, collects garbage after 30 days, it would result in code that is much cleaner and thus more prone to bugs, which IMHO is more important value; any performance increase would be a nice bonus.

The problem is explained there :
http://stackoverflow.com/questions/1703552/encoding-of-window-location-hash

As a summary, the hash exposed in JS in Firefox is already URL-encoded, which
is not the case in Chrome for instance.
@jtojnar
Copy link
Member

jtojnar commented Dec 29, 2016

Apparently the Firefox behaviour is correct one, since Location.href ought to return URL’s fragment, which is described as an ASCII string.

Interestingly enough, until 2015 Firefox behaved the same way as Chromium. On the other hand, Safari, IE and old Opera are correctly returning encoded hash, so this should probably be reported as Blink interop bug.

Since the location.href should be encoded everywhere, the proper fix is obtaining the hash using decodeURIComponent(location.href.split('#').splice(1).join('#')) (source). It should be correct as, if I am reading the RFC correctly, URL can only contain one number sign.

Decoding the hash as in d02a159 would fail in non-compliant browsers like chromium when the tag contains a percent sign.

@niol
Copy link
Collaborator Author

niol commented Dec 30, 2016

Regarding seek pagination, I do not understand why id should be included in the ORDER clause and in the comparison. Regarding performance, it seems about 5-10% better.

@bendem
Copy link

bendem commented Dec 30, 2016

Because multiple rows could have the same timestamp, you only want the ones after the last one you got.

@jtojnar
Copy link
Member

jtojnar commented Dec 30, 2016

Indeed.

Paging requires a deterministic sort order.

See a more detailed writeup about the seek pagination:

http://use-the-index-luke.com/sql/partial-results/fetch-next-page

@@ -71,7 +71,7 @@ selfoss.events.navigation = function() {
$(this).addClass('active');

if($(this).hasClass('nav-tags-all')==false) {
location.hash = '#' + selfoss.filter.type + '/tag-' + $(this).find('span').html();
location.hash = '#' + selfoss.filter.type + '/tag-' + $(this).find('span').html().replace('%', '%25');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be encodeURIComponent($(this).find('span').html()). Works both in Chromium and Firefox.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but I had preferred the browsers to show a unencoded string in the address bar. I've also tested with both browers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am afraid that is Chromium issue, Firefox displays the hash decoded. It would be nice if someone with access to Safari could test how it behaves there.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It also works with the firefox I have (Mozilla/5.0 (X11; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0).

@jtojnar
Copy link
Member

jtojnar commented Jan 2, 2017

In a brief inspection it looks really nice. However, 2999994 broke clicking the entry source to get to source listing. Two clicks are now needed.

@jtojnar
Copy link
Member

jtojnar commented Jan 3, 2017

Looks nice.

And while I am nitpicking, when you click the entry source, the source in the sidebar will be highlighted only after the listing finished loading – the other way around than when clicking the source in the sidebar.

@niol
Copy link
Collaborator Author

niol commented Jan 6, 2017

Yes, but the only way to fix this would be to make two AJAX requests: the first to load the source navigation sidebar items, the second to load the new filtered list of items. The current implementation loads both ressources using the same request, which should be a bit faster.

niol added 3 commits January 6, 2017 14:22
Hash is processed asynchroneously, which would cause ajax requests to be sent
with an opened entry on slow devices. This change ensures the hash is processed
in that case.
@SSilence SSilence merged commit ce5fc91 into fossar:master Feb 4, 2017
@SSilence
Copy link
Member

SSilence commented Feb 4, 2017

This changes doesn't work with my sqlite database:

Ein Fehler ist aufgetreten: PDO: no such column: TRUE [selfoss/libs/f3/base.php:2032] Base->error(500,'PDO: no such column: TRUE') [selfoss/daos/mysql/Items.php:286] DB\SQL->exec('SELECT items.id FROM items AS items, sources AS sources WHERE items.source=sources.id AND TRUE LIMIT 1 OFFSET 50',array()) [selfoss/daos/Items.php:83] daos\mysql\Items->get(array('starred'=>false,'offset'=>'0','search'=>'','items'=>50,'offset_from_datetime'=>'','offset_from_id'=>'','itemsPerPage'=>'50','type'=>'newest','tag'=>'','source'=>'','sourcesNav'=>'false','ajax'=>'true')) [selfoss/controllers/Index.php:243] daos\Items->get(array('offset'=>'0','offset_from_datetime'=>'','offset_from_id'=>'','itemsPerPage'=>'50','search'=>'','type'=>'newest','tag'=>'','source'=>'','sourcesNav'=>'false','ajax'=>'true'))

@niol niol mentioned this pull request Feb 6, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants