Template tags do not accept variable as argument #149

Open
adrien-delhorme opened this Issue Apr 2, 2012 · 3 comments

3 participants

@adrien-delhorme

For example, when I pass STATIC_URL to the facebook_button tag:

{% facebook_button STATIC_URL %}

the HTML output is:

<input type="image" onclick="this.form.submit();" src="TATIC_UR" />

To make it work, I changed the line 11 into socialregistration/templatetags/__init__.py by:

return ButtonTag(template, parser.compile_filter(bits[1]))

and the line 27 by:

return template.loader.render_to_string(self.template, {'button': self.button.resolve(context)}, context)

But this patch does not work for openID button.

So here is my full patch for socialregistration/templatetags/__init__.py:

from django import template
from django.utils.translation import ugettext_lazy as _

register = template.Library()

def button(template):
    def tag(parser, token):
        bits = token.split_contents()
        try:
            # Is a provider and a custom button passed in?
            return ButtonTag(template, parser.compile_filter(bits[2]), parser.compile_filter(bits[1]))
        except IndexError:
            try:
                # Is a custom button passed in?
                return ButtonTag(template, parser.compile_filter(bits[1]))
            except IndexError:
                # No custom button
                return ButtonTag(template)
    return tag

class ButtonTag(template.Node):
    def __init__(self, template, button = None, provider=None):
        self.template = template
        self.button = button
        self.provider = provider

    def render(self, context):
        if not 'request' in context:
            raise AttributeError(_("Please add 'django.core.context_processors.request' "
                "'to your settings.TEMPLATE_CONTEXT_PROCESSORS'"))

        dict = {'button': self.button.resolve(context)}
        if self.provider:
            dict.update(provider=self.provider.resolve(context))

        return template.loader.render_to_string(self.template, dict, context)

and socialregistration/contrib/openid/templatetags/openid.py is just like facebook.py:

from django import template

from socialregistration.templatetags import button

register = template.Library()

register.tag('openid_form', button('socialregistration/openid/form.html'))
@flashingpumpkin

Hi

I'll have a look as soon as possible

Cheers

@zalmoxis

I did not notice this issue and implemented my own version. I actually needed to mix context variables with strings like:
{% facebook_button STATIC_URL "images/tiny_facebook.png" %}

The implementation should be able to handle an arbitrary number of variables and strings. I did not add any tests, but the current facebook tests were passing. Could someone also chime in on how I could run all tests? The tests.py classes inherit from object and not TestCase. Sorry for the noob question. I didn't find info on running the tests in the documentation.

Here it is:

from django import template
from django.utils.translation import ugettext_lazy as _

register = template.Library()

def button(template_name):
    def tag(parser, token):
        bits = token.split_contents()
        if len(bits) > 1:
            return ButtonTag(template_name, *bits[1:])
        else:
            # No custom button
            return ButtonTag(template_name)
    return tag

class ButtonTag(template.Node):
    def __init__(self, template_name, *input):
        self.template = template_name
        self.input = input

    def render(self, context):
        output = []
        for bit in self.input:
            if not (bit[0] == bit[-1] and bit[0] in ('"', "'")):
                output.append(template.Variable(bit).resolve(context))
            else:
                output.append(bit[1:-1])
        self.button = ''.join(output)

        if not 'request' in context:
            raise AttributeError(_("Please add 'django.core.context_processors.request' "
                "'to your settings.TEMPLATE_CONTEXT_PROCESSORS'"))

        return template.loader.render_to_string(self.template, {'button': self.button, 'next': context.get('next', None)}, context)

You can pull from: https://bitbucket.org/dori/django-socialregistration/
Sorry about the bitbucket/mercurial ....

@zalmoxis

I have modified the openid_form tag to be able to work the same way:

def openid_form(context, provider=None, *params):
    button = ''.join(params)
    return {
        'provider': provider,
        'button': button,
        'request': context['request']
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment