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

Let developer specify a root page for a PageChooserPanel #3322

Open
shezi opened this issue Feb 1, 2017 · 3 comments
Open

Let developer specify a root page for a PageChooserPanel #3322

shezi opened this issue Feb 1, 2017 · 3 comments
Labels
component:Choosers Modal choosers for Page, Snippet and other models type:Enhancement

Comments

@shezi
Copy link

shezi commented Feb 1, 2017

We have a situation where a client has a deep page structure with several similar departments, each with similar sub-pages. They want to make linking of specific sub-pages to the "department index" easier with a page chooser. That page chooser should be anchored to the current page and only show sub-pages of that page (still of a certain type).

It would be nice if we could specify the root page of a PageChooserPanel and set it to the current page dynamically.

@shezi
Copy link
Author

shezi commented Feb 1, 2017

Related, but not the same: #670 and #2756 and #1250

@gasman gasman added this to the some-day milestone Feb 1, 2017
@an-ant0ni0
Copy link

We encounter the very same issue.
I found so far a hacky javascript solution which is not working anymore: https://stackoverflow.com/a/65441715

Another possibility is to use the on_instance_bound hook (https://stackoverflow.com/a/59905949):

class InstanceAwareStreamFieldPanel(StreamFieldPanel):
    def on_instance_bound(self):
        if not self.form:
            return
        widget = self.form[self.field_name].field.widget

        for _, child_block in widget.block_def.child_blocks.items():
            self.recursive(child_block)

    def recursive(self, block):
        if hasattr(block, "widget") and isinstance(block.widget, AdminChildPageChooser):
            block.widget = AdminChildPageChooser(
                target_models=block.widget.target_models,
                can_choose_root=block.widget.can_choose_root,
                page_instance_id=self.instance.id,
            )

        if hasattr(block, "child_block"):
            self.recursive(block.child_block)

        if not hasattr(block, "child_blocks"):
            return
        for _, child_block in block.child_blocks.items():
            self.recursive(child_block)

Then extending the AdminPageChooser and the PageChooserBlock to render a different template:

class AdminChildPageChooser(AdminPageChooser):
    def __init__(self, **kwargs):
        self.page_instance_id = kwargs.pop("page_instance_id", None)
        super().__init__(**kwargs)

    def render_html(self, name, value_data, attrs):
        value_data = value_data or {}

        return render_to_string(
            "wagtailadmin/child_page_chooser.html",
            {
                "widget": self,
                "original_field_html": "",
                "attrs": attrs,
                "value": bool(
                    value_data
                ),  # only used by chooser.html to identify blank values
                "display_title": value_data.get("display_title", ""),
                "edit_url": value_data.get("edit_url", ""),
                "page_instance_id": self.page_instance_id,
            },
        )


class ChildPageChooserBlock(blocks.PageChooserBlock):
    def __init__(
        self,
        page_type=None,
        can_choose_root=False,
        target_model=None,
        **kwargs,
    ):
        self.page_instance_id = kwargs.pop("page_instance_id", None)

        super().__init__(
            page_type=page_type,
            can_choose_root=can_choose_root,
            target_model=target_model,
            **kwargs,
        )

    @cached_property
    def widget(self):
        return AdminChildPageChooser(
            target_models=self.target_models,
            can_choose_root=self.can_choose_root,
            page_instance_id=self.page_instance_id,
        )

child_page_chooser.html:

{% extends "wagtailadmin/widgets/chooser.html" %}
{% load wagtailadmin_tags %}

{% block unchosen_icon %}{% icon name="doc-empty-inverse" %}{% endblock unchosen_icon %}
{% block chosen_icon %}{% icon name="doc-empty-inverse" %}{% endblock chosen_icon %}
{% block chooser_attributes %}
  {% if page_instance_id %}
    data-chooser-url="{% url 'wagtailadmin_choose_page_child' page_instance_id %}"
  {% else %}
    data-chooser-url="{% url 'wagtailadmin_choose_page' %}"
  {% endif %}
{% endblock %}

The rendered html will be cached, so it only works for the first time.
Also the iteration to find the correct widgets to replace in the on_instance_bound hook and the code duplication is quite nasty.

Long story short: We would really appreciate a clean api to set the root page for the PageChooser.

@an-ant0ni0
Copy link

We found a solution for our needs with https://github.com/wagtail/wagtail-generic-chooser.
Not sure, why we do not found this excellent toolkit earlier.

@gasman gasman removed this from the some-day milestone Mar 30, 2022
@lb- lb- added the component:Choosers Modal choosers for Page, Snippet and other models label Apr 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component:Choosers Modal choosers for Page, Snippet and other models type:Enhancement
Projects
None yet
Development

No branches or pull requests

4 participants