1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

from django import template

from django.template import Template, TemplateSyntaxError

from django.core.files.storage import FileSystemStorage

from django.forms import Widget, Textarea, ImageField, CharField

from django.forms import TextInput

from django.conf import settings as global_settings

from django.utils.translation import ugettext_lazy as _

from django.utils.safestring import SafeUnicode, mark_safe

from django.template.loader import render_to_string

 

from pages.widgets_registry import get_widget

from pages import settings

from pages.models import Content, Page

import os

import time

import re

 

def parse_placeholder(parser, token):

    """Parser that understand all the placeholder's parameters."""

    bits = token.split_contents()

    count = len(bits)

    error_string = '%r tag requires at least one argument' % bits[0]

    if count <= 1:

        raise template.TemplateSyntaxError(error_string)

    name = bits[1]

    remaining = bits[2:]

    params = {}

    while remaining:

        bit = remaining[0]

        if bit not in ('as', 'on', 'with', 'parsed'):

            raise template.TemplateSyntaxError(

                "%r is not an correct option for a placeholder" % bit)

        if bit in ('as', 'on', 'with'):

            if len(remaining) < 2:

                raise template.TemplateSyntaxError(

                "Placeholder option '%s' need a parameter" % bit)

            if bit == 'as':

                params['as_varname'] = remaining[1]

            if bit == 'with':

                params['widget'] = remaining[1]

            if bit == 'on':

                params['page'] = remaining[1]

            remaining = remaining[2:]

        else:

            params['parsed'] = True

            remaining = remaining[1:]

    return name, params

 

 

class PlaceholderNode(template.Node):

    """This template node is used to output page content and

    dynamically generate input fields in the admin.

 

    :param name: the name of the placeholder you want to show/create

    :param page: the optional page object

    :param widget: the widget you want to use in the admin interface. Take

        a look into :mod:`pages.widgets` to see which widgets

        are available.

    :param parsed: if the ``parsed`` word is given, the content of the

        placeholder is evaluated as template code, within the current context.

    :param as_varname: if ``as_varname`` is defined, no value will be returned.

        A variable will be created in the context with the defined name.

    """

 

    field = CharField

 

    def __init__(self, name, page=None, widget=TextInput, parsed=False, as_varname=None):

        self.page = page or 'current_page'

        self.name = name

        self.widget = widget

        self.parsed = parsed

        self.as_varname = as_varname

        self.found_in_block = None

 

    def get_widget(self, page, language, fallback=Textarea):

        """Given the name of a placeholder return a ``Widget`` subclass

        like Textarea or TextInput."""

        is_str = type(self.widget) == type(str())

        is_unicode =  type(self.widget) == type(unicode())

        if is_str or is_unicode:

            widget = get_widget(self.widget)

        else:

            widget = self.widget

        try:

            return widget(page=page, language=language)

        except:

            pass

        return widget()

 

    def get_field(self, page, language, initial=None):

        """The field that will be shown within the admin."""

        if self.parsed:

            help_text = _('Note: This field is evaluated as template code.')

        else:

            help_text = ""

        widget = self.get_widget(page, language)

        return self.field(widget=widget, initial=initial,

                    help_text=help_text, required=False)

 

    def save(self, page, language, data, change):

        """Actually save the placeholder data into the Content object."""

        # the page is being changed

        if change:

            # we need create a new content if revision is enabled

            if(settings.PAGE_CONTENT_REVISION and self.name

                not in settings.PAGE_CONTENT_REVISION_EXCLUDE_LIST):

                Content.objects.create_content_if_changed(

                    page,

                    language,

                    self.name,

                    data

                )

            else:

                Content.objects.set_or_create_content(

                    page,

                    language,

                    self.name,

                    data

                )

        # the page is being added

        else:

            Content.objects.set_or_create_content(

                page,

                language,

                self.name,

                data

            )

 

    def get_content(self, context):

        if not self.page in context:

            return ''

        # current_page can be set to None

        if not context[self.page]:

            return ''

 

        lang = context.get('lang', settings.PAGE_DEFAULT_LANGUAGE)

        content = Content.objects.get_content(context[self.page], lang,

                                              self.name, True)

        return content

 

    def render(self, context):

        """Output the content of the node in the template."""

        content = self.get_content(context)

        if not content:

            return ''

        if self.parsed:

            try:

                t = template.Template(content, name=self.name)

                content = mark_safe(t.render(context))

            except template.TemplateSyntaxError, error:

                if global_settings.DEBUG:

                    error = PLACEHOLDER_ERROR % {

                        'name': self.name,

                        'error': error,

                    }

                    if self.as_varname is None:

                        return error

                    context[self.as_varname] = error

                    return ''

                else:

                    return ''

        if self.as_varname is None:

            return content

        context[self.as_varname] = content

        return ''

 

    def __repr__(self):

        return "<Placeholder Node: %s>" % self.name

 

 

class ImagePlaceholderNode(PlaceholderNode):

 

    widget = 'ImageInput'

 

    def get_field(self, page, language, initial=None):

        help_text = ""

        widget = self.get_widget(page, language)

        return ImageField(

            widget=widget,

            initial=initial,

            help_text=help_text,

            required=False

        )

 

    def save(self, page, language, data, change):

        filename = ""

        if page and page.id and data:

            storage = FileSystemStorage()

            filename = os.path.join('upload', 'page_'+str(page.id),

                self.name + '-' + str(time.time()))

            filename = storage.save(filename, data)

            super(ImagePlaceholderNode, self).save(

                page,

                language,

                filename,

                change

            )

 

class VideoPlaceholderNode(PlaceholderNode):

 

    def render(self, context):

        content = self.get_content(context)

        if not content:

            return ''

        if content:

            video_url = content

            m = re.search('youtube\.com\/watch\?v=([^&]+)', content)

            if m:

                video_url = 'http://www.youtube.com/v/'+m.group(1)

            context = {'video_url': video_url}

            renderer = render_to_string('pages/embed.html', context)

            return mark_safe(renderer)

        return ''