1
1
import json
2
2
3
3
from classytags .arguments import Argument , MultiKeywordArgument
4
- from classytags .core import Options
4
+ from classytags .core import Options , Tag
5
5
from classytags .helpers import AsTag
6
6
from cms .templatetags .cms_tags import render_plugin
7
7
from django import template
@@ -113,11 +113,35 @@ def user_message(context, message):
113
113
return {}
114
114
115
115
116
+ @register .tag
117
+ class SlotTag (Tag ):
118
+ name = "slot"
119
+ options = Options (
120
+ Argument ("slot_name" , required = True ),
121
+ blocks = [("endslot" , "nodelist" )],
122
+ )
123
+
124
+ def render_tag (self , context , slot_name , nodelist ):
125
+ return ""
126
+
127
+
116
128
class DummyPlugin :
117
- def __init__ (self , nodelist ) :
129
+ def __init__ (self , nodelist , plugin_type , slot_name : str | None = None ) -> "DummyPlugin" :
118
130
self .nodelist = nodelist
131
+ self .plugin_type = (f"{ plugin_type } { slot_name .capitalize ()} Plugin" ) if slot_name else "DummyPlugin"
132
+ if slot_name is None :
133
+ self .parse_slots (nodelist , plugin_type )
119
134
super ().__init__ ()
120
135
136
+ def parse_slots (self , nodelist , plugin_type ):
137
+ self .slots = [self ]
138
+ for node in nodelist :
139
+ if isinstance (node , SlotTag ):
140
+ self .slots .append (DummyPlugin (node .nodelist , plugin_type , node .kwargs .get ("slot_name" )))
141
+
142
+ def get_instances (self ):
143
+ return self .slots
144
+
121
145
122
146
class Plugin (AsTag ):
123
147
name = "plugin"
@@ -134,9 +158,9 @@ def message(self, message):
134
158
135
159
def get_value (self , context , name , kwargs , nodelist ):
136
160
if name not in plugin_tag_pool :
137
- return self .message (f" Plugin \ "{ name } \ " not found in pool for plugins usable with {{% plugin %}}" )
161
+ return self .message (f' Plugin "{ name } " not found in pool for plugins usable with {{% plugin %}}' )
138
162
context .push ()
139
- instance = ( plugin_tag_pool [name ]["defaults" ])
163
+ instance = plugin_tag_pool [name ]["defaults" ]
140
164
plugin_class = plugin_tag_pool [name ]["class" ]
141
165
if issubclass (plugin_class , CMSUIPlugin ):
142
166
#
@@ -148,29 +172,70 @@ def get_value(self, context, name, kwargs, nodelist):
148
172
# Call render method of plugin
149
173
context = plugin_class ().render (context , context ["instance" ], None )
150
174
# Replace inner plugins with the nodelist, i.e. the content within the plugin tag
151
- context ["instance" ].child_plugin_instances = [DummyPlugin (nodelist )]
175
+ context ["instance" ].child_plugin_instances = DummyPlugin (
176
+ nodelist , context ["instance" ].plugin_type
177
+ ).get_instances ()
152
178
# ... and redner
153
179
result = plugin_tag_pool [name ]["template" ].render (context .flatten ())
154
180
context .pop ()
155
181
return result
156
182
157
183
158
- register .tag (Plugin .name , Plugin )
184
+ class RenderChildPluginsTag (Tag ):
185
+ """
186
+ This template node is used to render child plugins of a plugin
187
+ instance. It allows for selection of certain plugin types.
159
188
189
+ e.g.: {% childplugins instance %}
160
190
161
- @register .simple_tag (takes_context = True )
162
- def render_child_plugins (context , instance , plugin_type = None ):
163
- """Renders the child plugins of a plugin instance"""
164
- if not instance .child_plugin_instances :
165
- return ""
166
- context .push ()
167
- context ["parent" ] = instance
168
- result = ""
169
- for child in instance .child_plugin_instances :
170
- if isinstance (child , DummyPlugin ):
171
- result += child .nodelist .render (context )
172
- else :
173
- if plugin_type and child .plugin_type == plugin_type :
174
- result += render_plugin (context , child )
175
- context .pop ()
176
- return result if result else getattr (instance , "simple_content" , "" )
191
+ {% childplugins instance "LinkPlugin" %}
192
+
193
+ {% placeholder "footer" inherit or %}
194
+ <a href="/about/">About us</a>
195
+ {% endplaceholder %}
196
+
197
+ Keyword arguments:
198
+ name -- the name of the placeholder
199
+ inherit -- optional argument which if given will result in inheriting
200
+ the content of the placeholder with the same name on parent pages
201
+ or -- optional argument which if given will make the template tag a block
202
+ tag whose content is shown if the placeholder is empty
203
+ """
204
+
205
+ name = "childplugins"
206
+ options = Options (
207
+ # PlaceholderOptions parses until the "endchildplugins" tag is found if
208
+ # the "or" option is given
209
+ Argument ("instance" , required = True ),
210
+ Argument ("plugin_type" , required = False ),
211
+ blocks = [("endchildplugins" , "nodelist" )],
212
+ )
213
+
214
+ def render_tag (self , context , instance , plugin_type , nodelist ):
215
+ context .push ()
216
+ context ["parent" ] = instance
217
+ content = ""
218
+ if plugin_type and not plugin_type .endswith ("Plugin" ):
219
+ plugin_type = f"{ instance .__class__ .__name__ } { plugin_type .capitalize ()} Plugin"
220
+ for node in nodelist :
221
+ print (type (node ), getattr (node , "args" , None ), getattr (node , "kwargs" , None ), plugin_type )
222
+ for child in instance .child_plugin_instances :
223
+ if not plugin_type or child .plugin_type == plugin_type :
224
+ if isinstance (child , DummyPlugin ):
225
+ content += child .nodelist .render (context )
226
+ else :
227
+ for grand_child in child .child_plugin_instances :
228
+ content += render_plugin (context , grand_child )
229
+ content = content or getattr (instance , "simple_content" , "" )
230
+ print (f"{ content .strip ()= } " )
231
+
232
+ if not content .strip () and nodelist :
233
+ # "or" parameter given
234
+ return nodelist .render (context )
235
+
236
+ context .pop ()
237
+ return content
238
+
239
+
240
+ register .tag (Plugin .name , Plugin )
241
+ register .tag (RenderChildPluginsTag .name , RenderChildPluginsTag )
0 commit comments