class ArticlePlaceholder(Tag):
    """
    This template node is used to output article content and
    is also used in the admin to dynamically generate input fields.

    eg: {% article_placeholder "placeholder_name" %}

    {% article_placeholder "footer" or %}
        <a href="/about/">About us</a>
    {% endarticle_placeholder %}

    Keyword arguments:
    name -- the name of the placeholder
    or -- optional argument which if given will make the template tag a block
        tag whose content is shown if the placeholder is empty
    """
    name = 'article_placeholder'
    options = PlaceholderOptions(
        Argument('name', resolve=False),
        MultiValueArgument('extra_bits', required=False, resolve=False),
        blocks=[
            ('endarticle_placeholder', 'nodelist'),
        ],
    )

    def render_tag(self, context, name, extra_bits, nodelist=None):
        request = context.get('request')

        if not request:
            return ''

        validate_placeholder_name(name)

        toolbar = get_toolbar_from_request(request)
        renderer = toolbar.get_content_renderer()
        inherit = False

        try:
            content = renderer.render_page_placeholder(
                slot=name,
                context=context,
                inherit=inherit,
                page=request.current_article,
                nodelist=nodelist,
            )
        except PlaceholderNotFound:
            content = ''

        if not content and nodelist:
            return nodelist.render(context)
        return content

    def get_declaration(self):
        slot = self.kwargs['name'].var.value.strip('"').strip("'")

        return DeclaredPlaceholder(slot=slot, inherit=False)
Example #2
0
class GetPlaceholderPlugins(Tag):
    """
    A template tag that gets plugins from a page's placeholder and sets them as a context variable:

        {% get_placeholder_plugins "logo" page_lookup as varname %}
        {% get_placeholder_plugins "logo" page_lookup as varname or %}
            <div>No content</div>
        {% endget_placeholder_plugins %}

    The page_lookup parameter can be omitted and will default to the current page

        {% get_placeholder_plugins "logo" as varname %}
        {% get_placeholder_plugins "logo" as varname or %}
            <div>No content</div>
        {% endget_placeholder_plugins %}

    This tag can typically be used in association with the block_plugin tag,
    to render the retrieved plugins:

        {% get_placeholder_plugins "logo" page_lookup as plugins %}
        {% blockplugin plugins.0 %}
            <img src="{% thumbnail instance.picture 300x150 %}"/>
        {% endblockplugin %}

    Keyword arguments:
        name: the name of the placeholder
        page_lookup: lookup argument for Page. See `_get_page_by_untyped_arg()`
            for detailed information on the allowed types and their interpretation for the
            `page_lookup` argument.
        varname: context variable name. Output will be added to template context as this variable
            instead of being returned.
        or: optional argument which if given will make the template tag a block
            tag whose content is shown if the placeholder is empty
    """

    name = "get_placeholder_plugins"
    options = PlaceholderOptions(
        Argument("name", resolve=False),
        Argument("page_lookup", required=False, default=None),
        "as",
        Argument("varname", resolve=False),
        MultiValueArgument("extra_bits", required=False, resolve=False),
        blocks=[("endget_placeholder_plugins", "nodelist")],
    )

    # pylint: disable=arguments-differ,too-many-arguments, unused-argument
    def render_tag(
        self, context, name, page_lookup, varname, extra_bits, nodelist=None
    ):
        return get_plugins_render_tag(
            context, name, varname, nodelist, page_lookup, edit=False
        )
Example #3
0
class PlaceholderAttr(Tag):
    name = 'placeholder_attr'
    options = PlaceholderOptions(Argument('name', resolve=False),
                                 Argument('plugin_class_name', resolve=False),
                                 Argument('plugin_attr', resolve=False),
                                 MultiValueArgument('extra_bits',
                                                    required=False,
                                                    resolve=False),
                                 blocks=[
                                     ('endplaceholder', 'nodelist'),
                                 ])

    def render_tag(self,
                   context,
                   name,
                   plugin_class_name,
                   plugin_attr,
                   extra_bits,
                   nodelist=None):
        validate_placeholder_name(name)
        width = None
        for bit in extra_bits:
            if bit == 'inherit':
                pass
            elif bit.isdigit():
                width = int(bit)
                import warnings

                warnings.warn(
                    "The width parameter for the placeholder " +
                    "tag is deprecated.", DeprecationWarning)
        if not 'request' in context:
            return ''
        request = context['request']
        if width:
            context.update({'width': width})

        page = request.current_page
        if not page or page == 'dummy':
            if nodelist:
                return nodelist.render(context)

            return ''

        placeholder = _get_placeholder(page, page, context, name)

        res = get_placholder_attr(placeholder, name, plugin_class_name,
                                  plugin_attr)

        return res
Example #4
0
class RenderGetPlaceholder(Placeholder):
    """
    Render the content of a placeholder to a variable. Can be provided
    with the name of the placholder (i.e. "Header" in the case of a normal
    CMS page) or a template variable containing a placeholder (i.e. myentry.content in the
    case of an external app using a placeholder)

    {% get_placeholder ["string"|placeholder_var] as variable_name %}
    
    e.g.
    {% load extra_cms_tags %}
    {% get_placeholder "My Placeholder" as my_placeholder %}

    {% if my_placeholder %}
    <div>
        {{ my_placeholder }}
    </div>
    {% endif %}
    """
    name = "get_placeholder"

    options = PlaceholderOptions(
        Argument('name', resolve=True),
        MultiValueArgument('extra_bits', required=False, resolve=False),
        'as',
        Argument('varname', resolve=False, required=True),
        blocks=[
            ('endplaceholder', 'nodelist'),
        ],
    )

    def render_tag(self, context, name, extra_bits, varname, nodelist=None):
        if isinstance(name, PlaceholderModel):
            content = name.render(context, None)
        else:
            content = super(RenderGetPlaceholder,
                            self).render_tag(context, name, extra_bits,
                                             nodelist)
        context[varname] = mark_safe(content)
        return ""

    def get_name(self):
        # Fix some template voodoo causing errors
        if isinstance(self.kwargs['name'].var, StringValue):
            return self.kwargs['name'].var.value.strip('"').strip("'")
        return self.kwargs['name'].var.var
Example #5
0
class PlaceholderAsPlugins(Placeholder):
    """
    Like DjangoCMS 'placeholder' but sets the list of linked plugins to a variable name
    instead of rendering the placeholder.
    """

    name = "placeholder_as_plugins"
    options = PlaceholderOptions(
        Argument("name", resolve=False),
        "as",
        Argument("varname", resolve=False),
        MultiValueArgument("extra_bits", required=False, resolve=False),
        blocks=[("endplaceholder_as_plugins", "nodelist")],
    )

    # pylint: disable=arguments-renamed,too-many-arguments
    def render_tag(self, context, name, varname, extra_bits, nodelist=None):
        return get_plugins_render_tag(context, name, varname, nodelist)
Example #6
0
class GetPlaceholderPlugins(Placeholder):
    """
    A template tag that declares a placeholder and sets its plugins as a context variable
    instead of rendering them eg:

        {% get_placeholder_plugins "logo" as varname %}
        {% get_placeholder_plugins "logo" as varname or %}
            <div>No content</div>
        {% endget_placeholder_plugins %}

    This tag can typically be used in association with the block_plugin tag, to customize the
    way it is rendered eg:

        {% get_placeholder_plugins "logo" as plugins %}
        {% blockplugin plugins.0 %}
            <img src="{% thumbnail instance.picture 300x150 %}"/>
        {% endblockplugin %}

    Keyword arguments:
        name: the name of the placeholder
        varname: context variable name. Output will be added to template context as this variable
            instead of being returned.
        or: optional argument which if given will make the template tag a block
            tag whose content is shown if the placeholder is empty

    Note: We must derive from the Placeholder class so that the tag is recognized as a
          placeholder and shown in the structure toolbar.
    """

    name = "get_placeholder_plugins"
    options = PlaceholderOptions(
        Argument("name", resolve=False),
        "as",
        Argument("varname", resolve=False),
        MultiValueArgument("extra_bits", required=False, resolve=False),
        blocks=[("endget_placeholder_plugins", "nodelist")],
    )

    # pylint: disable=arguments-differ,too-many-arguments
    def render_tag(self, context, name, varname, extra_bits, nodelist=None):
        return get_plugins_render_tag(context, name, varname, nodelist)
Example #7
0
class RenderPlaceholder(Placeholder):
    """
    Render the content of a placeholder to a variable.

    {% placeholder "placeholder_name" as variable_name %}
    """
    name = "get_placeholder"

    options = PlaceholderOptions(
        Argument('name', resolve=False),
        MultiValueArgument('extra_bits', required=False, resolve=False),
        'as',
        Argument('varname', resolve=False),
        blocks=[
            ('endplaceholder', 'nodelist'),
        ],
    )

    def render_tag(self, context, name, extra_bits, varname, nodelist=None):
        content = super(RenderPlaceholder,
                        self).render_tag(context, name, extra_bits, nodelist)
        context[varname] = mark_safe(content)
        return ""
Example #8
0
class PagePlaceholder(Placeholder):
    """
    This template node is used to output page content and
    is also used in the admin to dynamically generate input fields.
    eg:
    {% page_placeholder "sidebar" page_lookup %}
    {% page_placeholder "sidebar" page_lookup inherit %}
    {% page_placeholder "sidebar" page_lookup as varname %}
    {% page_placeholder "sidebar" page_lookup or %}
        <div>No content</div>
    {% endpage_placeholder %}
    Keyword arguments:
        name: the name of the placeholder
        page_lookup: lookup argument for Page. See _get_page_by_untyped_arg() for detailed
            information on the allowed types and their interpretation for the page_lookup argument.
        inherit : optional argument which if given will result in inheriting
            the content of the placeholder with the same name on parent pages
        varname: context variable name. Output will be added to template context as this variable
            instead of being returned.
        or: optional argument which if given will make the template tag a block
            tag whose content is shown if the placeholder is empty
    """

    name = "page_placeholder"
    options = PlaceholderOptions(
        Argument("name", resolve=False),
        Argument("page_lookup"),
        MultiValueArgument("extra_bits", required=False, resolve=False),
        blocks=[("endpage_placeholder", "nodelist")],
    )

    # pylint: disable=arguments-differ,too-many-arguments
    def render_tag(self,
                   context,
                   name,
                   page_lookup,
                   extra_bits,
                   nodelist=None):
        validate_placeholder_name(name)

        request = context.get("request")

        if request:
            page = _get_page_by_untyped_arg(page_lookup, request,
                                            get_site_id(None))

            toolbar = get_toolbar_from_request(request)
            renderer = toolbar.get_content_renderer()

            inherit = "inherit" in extra_bits

            # A placeholder is only editable on its own page
            editable = page == request.current_page

            try:
                content = renderer.render_page_placeholder(
                    slot=name,
                    context=context,
                    inherit=inherit,
                    page=page,
                    nodelist=nodelist,
                    editable=editable,
                )
            except PlaceholderNotFound:
                content = ""
        else:
            content = ""

        if not content and nodelist:
            content = nodelist.render(context)

        if "as" in extra_bits:
            try:
                varname = extra_bits[extra_bits.index("as") + 1]
            except IndexError:
                raise template.TemplateSyntaxError(
                    'the "as" word should be followed by the variable name')
            context[varname] = content
            return ""

        return content
class StaticAlias(Tag):
    """
    This template node is used to render Alias contents and is designed to be a
    replacement for the CMS Static Placeholder.

    eg: {% static_alias "identifier_text" %}
    eg: {% static_alias "identifier_text" site %}

    Keyword arguments:
    static_code -- the unique identifier of the Alias
    site -- If site is supplied an Alias instance will be created per site.
    """
    name = 'static_alias'
    options = PlaceholderOptions(
        Argument('static_code', resolve=False),
        MultiValueArgument('extra_bits', required=False, resolve=False),
        blocks=[
            ('endstatic_alias', 'nodelist'),
        ],
    )

    def _get_alias(self, request, static_code, extra_bits):
        alias_filter_kwargs = {
            'static_code': static_code,
        }
        # Site
        current_site = get_current_site()
        if 'site' in extra_bits:
            alias_filter_kwargs['site'] = current_site
        else:
            alias_filter_kwargs['site_id__isnull'] = True

        # Try and find an Alias to render
        alias = Alias.objects.filter(**alias_filter_kwargs).first()
        # If there is no alias found we need to create one
        if not alias:

            # If versioning is enabled we can only create the records with a logged in user / staff member
            if is_versioning_enabled() and not request.user.is_authenticated:
                return None

            language = get_default_language_for_site(current_site)
            # Parlers get_or_create doesn't work well with translations, so we must perform our own get or create
            default_category = Category.objects.filter(translations__name=DEFAULT_STATIC_ALIAS_CATEGORY_NAME).first()
            if not default_category:
                default_category = Category.objects.create(name=DEFAULT_STATIC_ALIAS_CATEGORY_NAME)

            alias_creation_kwargs = {
                'static_code': static_code,
                'creation_method': Alias.CREATION_BY_TEMPLATE
            }
            # Site
            if 'site' in extra_bits:
                alias_creation_kwargs['site'] = current_site

            alias = Alias.objects.create(category=default_category, **alias_creation_kwargs)
            alias_content = AliasContent.objects.create(
                alias=alias,
                name=static_code,
                language=language,
            )

            if is_versioning_enabled():
                from djangocms_versioning.models import Version

                Version.objects.create(content=alias_content, created_by=request.user)

        return alias

    def render_tag(self, context, static_code, extra_bits, nodelist=None):
        request = context.get('request')

        if not static_code or not request:
            # an empty string was passed in or the variable is not available in the context
            if nodelist:
                return nodelist.render(context)
            return ''

        validate_placeholder_name(static_code)

        toolbar = get_toolbar_from_request(request)
        renderer = toolbar.get_content_renderer()
        alias = self._get_alias(request, static_code, extra_bits)

        if not alias:
            return ''

        # Get draft contents in edit or preview mode?
        get_draft_content = False
        if toolbar.edit_mode_active or toolbar.preview_mode_active:
            get_draft_content = True

        language = get_language_from_request(request)
        placeholder = alias.get_placeholder(language=language, show_draft_content=get_draft_content)

        if placeholder:
            content = renderer.render_placeholder(
                placeholder=placeholder,
                context=context,
                nodelist=nodelist,
            )
            return content
        return ''
Example #10
0
class GetPlaceholderPlugins(Placeholder):
    """
    A template tag that declares a placeholder and sets its plugins as a context variable
    instead of rendering them eg:

        {% get_placeholder_plugins "logo" as varname %}
        {% get_placeholder_plugins "logo" page_lookup as varname %}
        {% get_placeholder_plugins "logo" page_lookup as varname or %}
            <div>No content</div>
        {% endget_placeholder_plugins %}

    This tag can typically be used in association with the block_plugin tag, in a placeholder
    limited to one plugin, to customize the way it is rendered eg:

        {% get_placeholder_plugins "logo" page_lookup as plugins %}
        {% blockplugin plugins.0 %}
            <img src="{% thumbnail instance.picture 300x150 %}"/>
        {% endblockplugin %}

    Keyword arguments:
        name: the name of the placeholder
        page_lookup[optional]: lookup argument for Page. See `_get_page_by_untyped_arg()`
            for detailed information on the allowed types and their interpretation for the
            `page_lookup` argument.
        varname: context variable name. Output will be added to template context as this variable
            instead of being returned.
        or: optional argument which if given will make the template tag a block
            tag whose content is shown if the placeholder is empty

    Note: We must derive from the Placeholder class so that the tag is recognized as a
          placeholder and shown in the structure toolbar.
    """

    name = "get_placeholder_plugins"
    options = PlaceholderOptions(
        Argument("name", resolve=False),
        Argument("page_lookup", required=False),
        "as",
        Argument("varname", resolve=False),
        MultiValueArgument("extra_bits", required=False, resolve=False),
        blocks=[("endget_placeholder_plugins", "nodelist")],
    )

    # pylint: disable=arguments-differ,too-many-arguments
    def render_tag(self,
                   context,
                   name,
                   page_lookup,
                   varname,
                   extra_bits,
                   nodelist=None):
        """
        Retrieves the placeholder's plugins and set them as a variable in the template context.
        If the placeholder is empty, render the block as fallback content and return the
        resulting HTML.
        If the placholder is editable, the edit script and markup are added to the HTML content.
        """
        content = ""
        request = context.get("request")

        if request:

            page = _get_page_by_untyped_arg(page_lookup, request,
                                            get_site_id(None))

            try:
                placeholder = page.placeholders.get(slot=name)
            except ObjectDoesNotExist:
                context[varname] = []
                return ""
            else:
                context[varname] = [
                    cms_plugin.get_plugin_instance()[0]
                    for cms_plugin in get_plugins(
                        request, placeholder, template=page.get_template())
                ]

            # Default content if there is no plugins in the placeholder
            if not context[varname] and nodelist:
                content = nodelist.render(context)

            # Add the edit script and markup to the content, only if the placeholder is editable
            # and the visited page is the one on which the placeholder is declared.
            toolbar = get_toolbar_from_request(request)
            if placeholder.page == request.current_page and toolbar.edit_mode_active:
                renderer = toolbar.get_content_renderer()
                data = renderer.get_editable_placeholder_context(placeholder,
                                                                 page=page)
                data["content"] = content
                content = renderer.placeholder_edit_template.format(**data)

        return content