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)
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 )
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
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
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)
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)
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 ""
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 ''
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