Is there an event that fires when topic-lists are reloaded?

AI-generated summary

The discussion revolves around implementing a Masonry grid for topic lists in Discourse. Johani initially asks if there’s a native event that fires when the topic list is reloaded, which can be used to trigger Masonry’s layout function.

Mittineague suggests using jQuery’s ajaxComplete function, while angus proposes adding an observer to the topic-list component to watch for changes in topics.[]. Johani implements both solutions and shares the code.

Merefield expresses interest in replicating the effect and asks for the complete code changes. Dax notes that the Masonry theme has been deprecated in favor of the Tiles Image Gallery theme.

Merefield attempts to recreate the effect using CSS Grid and modifies the topic-list.hbs and topic-list-item.raw.hbs templates. However, they encounter an issue with an extra <tr> tag being generated and eventually resolve it by modifying the topic-list-item.js.es6 file.

Key takeaways:

  • Use jQuery’s ajaxComplete function or add an observer to the topic-list component to trigger Masonry’s layout function.
  • The Masonry theme has been deprecated in favor of the Tiles Image Gallery theme.
  • To recreate the effect, modify the topic-list.hbs and topic-list-item.raw.hbs templates to use CSS Grid and adjust the JavaScript code accordingly.

Excuse the butchered terminology :sunflower:


I’m trying to use masonry in combination with the topic list previews plugin to create a grid topic list like so:

When new items are added to a masonry grid or the topic-list in this case the current items need to be “reshuffled” and resized in some sense so that everything fits.

Masonry handles that with a native function or .layout() which recalculates the grid and arranges the items when called.

In order to make masonry aware of new items or topics being added to the topic list, I would like to trigger .layout() when this is clicked:

So here’s the question.

Is there a native Discourse event that fires when the the link to reload the topic list is clicked that I can bind masonry to?

Maybe you could use jQuery ajaxComplete ?

Another way is to add an observer in the topic-list component that observes topics.[] and re-runs masonry after render. i.e. something like:

withPluginApi(0.8.16, () api => {
  api.modifyClass('component:topic-list', {
     masonryObserver: function() {
        // update masonry here, probably wrapped in Ember.run.scheduleOnce('afterRender', () => {})
     }.observes('topics.[]')
  })
})

YES! :grin::champagne::boom:

That was amazingly helpful @Mittineague

thank you so much!

I ended up using:

$(document).ajaxComplete(function() {
	$(".topic-list").imagesLoaded(function() {
		$(".topic-list")
			.masonry("reloadItems")
			.masonry();
	});
});

and I would have stopped right there, however @angus was kind enough to provide what I believe is a more orthodox / targeted method for doing this in the context of Discourse here:


This feels like the right way to go about this, thank you so much @angus :grin::champagne:

I’m not sure how to go about this part:

probably wrapped in Ember.run.scheduleOnce('afterRender', () =&gt; {})

But will read further about Ember Voodoo and try again. :sweat_smile:

For now here’s what I ended up with based on your generous help and my basic understanding:

<script type="text/discourse-plugin" version="0.8.16">
    api.modifyClass("component:topic-list", {
	    masonryObserver: function() {
	    	$(".topic-list").imagesLoaded(function() {
		    	$(".topic-list")
			    	.masonry("reloadItems")
			    	.masonry();
	    	});
    	}.observes("topics.[]")
    });
</script>

And here’s the result:

https://giant.gfycat.com/FeistyFormalBoa.webm

Thank you so much :heart:

I’ve been messing with TLP and CSS to try and create a similar effect … but kept coming up against the limitation of the table layout (particularly the row alignment restriction). The use of masonry is great!

Are you able to share the complete inventory of changes for this look, @Johani?

Thanks!

Masonry theme has been deprecated in favor of Tiles Image Gallery.
You should be able to see the changes here https://meta.discourse.org/t/deprecated-discourse-masonry-gallery-theme-component/79076 and here https://github.com/hnb-ku/discourse-masonry-gallery

This is a lot more than the images gallery (love that too, though, btw) This is an alternative for the topic list feed, no? Is there a public repository for what’s shown here?

I think the key thing here is that TLP uses a table, just like vanilla discourse, … so looks like I just have to modify topic-list-item and topic-list :slight_smile: :

<tbody>
  {{#each filteredTopics as |topic|}}
    {{topic-list-item topic=topic
<SNIP>
                      tagsForUser=tagsForUser}}
    {{raw "list/visited-line" lastVisitedTopic=lastVisitedTopic topic=topic}}
  {{/each}}
</tbody>

etc.

masonry uses css grid presumably, which uses div tags … so I’m going with the assumption these were altered to use div tags … having a go myself but all pointers appreciated! (but I did find this guide which is very handy!)

OK I’ve reached a bit of an impasse:

I’ve edited both

  • topic-list.hbs: (added to TLP plug-in so I can change tbody to div)
{{#if socialStyle}}
<div class='grid'>
  {{#each filteredTopics as |topic|}}
    {{topic-list-item topic=topic
                      bulkSelectEnabled=bulkSelectEnabled

and:

  • topic-list-item.raw.hbs (taken from TLP plug-in but edited)
{{#if socialStyle}}
<div class='grid-item'>
    {{raw "list/topic-list-title" topic=topic socialStyle=socialStyle showTopicPostBadges=showTopicPostBadges}}
    {{#if showThumbnail}}
      {{raw "list/topic-thumbnail" topic=topic thumbnails=thumbnails category=category}}
      {{/if}}

But I still end up with a <tr> tag being added between them and can’t see where it’s being generated?:

Could this be being added by the javascript in topic-list-item.js.es6? Most definitely.

Attempting to overwrite with this in the initialiser:

api.modifyClass('component:topic-list-item', {
  tagName: 'div'
});

So I now have this working …