mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-04-30 07:20:49 +08:00
This PR adds several reusable pieces to Core that the
discourse-nested-replies
plugin needs, while keeping them general-purpose enough to be useful to
other
plugins and future Core work.
## Summary
### TopicMetadata component extraction
- Extracts the category chooser, tag chooser, plugin outlets, and
save/cancel controls from `topic.gjs` into a standalone
`<TopicCategoryTagEditor>` component
- The nested-replies plugin reuses this component in its own topic
header, avoiding duplication of ~55 lines of template code
- No behavioral change to the existing topic page
### Value transformers for URL routing
- **`route-to-url`** — applied in `DiscourseURL.routeTo()`, allows
plugins to intercept and rewrite navigation URLs before routing
occurs. Returns early if the transformer nullifies the path.
- **`topic-url-for-post-number`** — applied in `Topic#urlForPostNumber`,
allows plugins to rewrite per-post URLs (e.g. for nested views)
- **`post-share-url`**
### TopicView `PostDependentCache` concern
- Introduces `memoize_for_posts` — a declarative way to register
instance variables that should be cleared when posts are replaced
- Provides `reset_post_collection(posts:)` — an explicit method for
swapping the post collection on a TopicView after initialization,
automatically clearing all registered caches
- Adds `skip_post_loading` initializer option so plugins that supply
their own posts can skip the default post-loading SQL entirely
- 4 specs covering replacement, cache clearing, preload hooks, and
skip_post_loading
---------
Co-authored-by: Isaac Janzen <isaac.janzen@discourse.org>
43 lines
1.7 KiB
Ruby
43 lines
1.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# Extracted from TopicView to make post-dependent memoization self-maintaining.
|
|
#
|
|
# Any method in TopicView (or a plugin) that caches data derived from @posts
|
|
# can register itself with `memoize_for_posts`. When @posts is replaced via
|
|
# `reset_post_collection`, all registered caches are automatically cleared —
|
|
# no hardcoded ivar list required.
|
|
module TopicView::PostDependentCache
|
|
extend ActiveSupport::Concern
|
|
|
|
included do
|
|
# Stores ivar names (as symbols like :@all_post_actions) that should
|
|
# be cleared whenever @posts is replaced.
|
|
class_attribute :post_dependent_ivars, instance_writer: false, default: []
|
|
end
|
|
|
|
class_methods do
|
|
# Register a memoized ivar as post-dependent.
|
|
#
|
|
# memoize_for_posts :all_post_actions
|
|
# memoize_for_posts :primary_group_names, :@group_names
|
|
#
|
|
# The ivar name defaults to `@<method_name>` but can be overridden
|
|
# for cases where the ivar doesn't match the method name.
|
|
def memoize_for_posts(method_name, ivar_name = nil)
|
|
ivar_name ||= :"@#{method_name}"
|
|
# Use += to avoid mutating a parent class's array
|
|
self.post_dependent_ivars = post_dependent_ivars + [ivar_name]
|
|
end
|
|
end
|
|
|
|
# Replaces @posts with a new collection and clears all registered
|
|
# post-dependent caches. Use this instead of writing to @posts directly
|
|
# when you need to swap in a different set of posts (e.g. a plugin that
|
|
# builds its own post tree) after the TopicView has been initialized.
|
|
def reset_post_collection(posts:)
|
|
@posts = posts
|
|
self.class.post_dependent_ivars.each do |ivar|
|
|
remove_instance_variable(ivar) if instance_variable_defined?(ivar)
|
|
end
|
|
end
|
|
end
|