fix prelude/requirements system
authorThierry Parmentelat <thierry.parmentelat@inria.fr>
Wed, 19 Dec 2012 13:32:58 +0000 (14:32 +0100)
committerThierry Parmentelat <thierry.parmentelat@inria.fr>
Wed, 19 Dec 2012 13:32:58 +0000 (14:32 +0100)
engine/composite.py
engine/plugin.py
engine/prelude.py
engine/templates/header-prelude.html [new file with mode: 0644]
engine/views.py
plugins/simplelist.py
plugins/slicelist.py [new file with mode: 0644]
plugins/templates/simplelist.html
static/js/need-datatables.js [deleted file]
static/js/with-datatables.js [new file with mode: 0644]
templates/layout-myslice.html

index c89abc1..71f358d 100644 (file)
@@ -3,8 +3,8 @@ from engine.plugin import Plugin
 class Composite (Plugin):
 
     def __init__ (self, sons=[], *args, **kwds):
-        self.sons=sons
         Plugin.__init__ (self, *args, **kwds)
+        self.sons=sons
         
     def insert (self, plugin):
         self.sons.append(plugin)
index 5de2d76..3b52c80 100644 (file)
@@ -8,6 +8,13 @@ from django.template.loader import render_to_string
 
 from engine.prelude import Prelude
 
+# set to
+# . False : silent
+# [ 'SliceList', 'TabbedView' ] : to debug these classes
+# True : to debug all slices
+
+DEBUG= [ 'SliceList' ]
+
 class Plugin:
 
     uid=0
@@ -23,7 +30,14 @@ class Plugin:
         # e.g. SimpleList (list=[1,2,3]) => _settings = { 'list':[1,2,3] }
         # our own settings are not made part of _settings but could be..
         self._settings=settings
-#        print "Created plugin with settings %s"%self._settings.keys()
+        if self.need_debug():
+            print "Plugin.__init__ Created plugin with settings %s"%self._settings.keys()
+
+    # subclasses might handle some fields in their own way, 
+    # in which case this call is needed to capture that setting
+    # see e.g. SimpleList or SliceList for an example of that
+    def add_to_settings (self, setting_name):
+        self._settings[setting_name]=getattr(self,setting_name)
 
     def classname (self): 
         try:    return self.__class__.__name__
@@ -38,6 +52,12 @@ class Plugin:
     def is_hidable (self): return self.hidable
     def is_hidden_by_default (self): return self.hidden_by_default
 
+    ##########
+    def need_debug (self):
+        if not DEBUG:           return False
+        if DEBUG is True:       return True
+        else:                   return self.classname() in DEBUG
+
     # returns the html code for that plugin
     # in essence, wraps the results of self.render_content ()
     def render (self, request):
@@ -49,10 +69,11 @@ class Plugin:
         # call render_content
         plugin_content = self.render_content (request)
         # expose _settings in json format to js
-        settings_json = json.dumps(self._settings, separators=(',',':'))
+        settings_json = json.dumps (self._settings, separators=(',',':'))
 
         result = render_to_string ('widget-plugin.html',
-                                   {'uuid':uuid, 'classname':classname,
+                                   {'uuid':uuid, 
+                                    'classname':classname,
                                     'visible':self.is_visible(),
                                     'hidable':self.is_hidable(),
                                     'hidden':self.is_hidden_by_default(),
@@ -63,7 +84,10 @@ class Plugin:
         # handle requirements() if defined on this class
         try: 
             self.handle_requirements (request, self.requirements())
-        except: 
+        except AttributeError: 
+            # most likely the object does not have that method defined, which is fine
+            pass
+        except:
             import traceback
             traceback.print_exc()
             pass
@@ -83,10 +107,12 @@ class Plugin:
         # xxx we might need to check that this does not overwrite env..
         env.update(self._settings)
         result=render_to_string (template, env)
-        print "%s.render_content: BEG --------------------"%self.classname()
-        print "env=%s"%env.keys()
-        print result
-        print "%s.render_content: END --------------------"%self.classname()
+        if self.need_debug():
+            print "%s.render_content: BEG --------------------"%self.classname()
+            print "template=%s"%template
+            print "env=%s"%env.keys()
+            # print result
+            print "%s.render_content: END --------------------"%self.classname()
         return result
 
     #################### requirements/prelude management
@@ -116,7 +142,8 @@ class Plugin:
     # or from the result of self.requirements()
     def handle_requirements (self, request, d):
         for (k,v) in d.iteritems():
-            print "%s: handling requirement %s"%(self.classname(),v)
+            if self.need_debug():
+                print "%s: handling requirement %s"%(self.classname(),v)
             method_name='add_'+k
             method=Plugin.__dict__[method_name]
             method(self,request,v)
index 6be6441..bf5e0a9 100644 (file)
@@ -1,5 +1,7 @@
 from types import StringTypes, ListType
 
+from django.template.loader import render_to_string
+
 class Prelude:
 
     """A class for collecting dependencies on js/css files or fragments"""
@@ -29,10 +31,29 @@ class Prelude:
     def add_css_chunks (self, x):
         self.css_chunks += Prelude._normalize (x)
 
+    # first attempt was to use a simple dict like this
+    #    env={}
+    #    env['js_files']=  self.js_files
+    #    env['css_files']= self.css_files
+    #    env['js_chunks']= '\n'.join(self.js_chunks)
+    #    env['css_chunks']='\n'.join(self.css_chunks)
+    #    return env
+    # together with this in layout-myslice.html
+    # {% for js_file in js_files %} {% insert_str prelude js_file %} {% endfor %}
+    # {% for css_file in css_files %} {% insert_str prelude css_file %} {% endfor %}
+    # somehow however this would not work too well, 
+    # probably insert_above is not powerful enough to handle that
+    # 
+    # so a much simpler and safer approach is for use to compute the html header directly
     def render_env (self): 
         env={}
         env['js_files']=  self.js_files
         env['css_files']= self.css_files
-        env['js_chunks']= '\n'.join(self.js_chunks)
-        env['css_chunks']='\n'.join(self.css_chunks)
-        return env
+        env['js_chunks']= self.js_chunks
+        env['css_chunks']=self.css_chunks
+        # not sure how this should be done more cleanly
+        from myslice.settings import STATIC_URL
+        env ['STATIC_URL'] = STATIC_URL
+        # render this with prelude.html and put the result in header_prelude
+        header_prelude = render_to_string ('header-prelude.html',env)
+        return { 'header_prelude' : header_prelude }
diff --git a/engine/templates/header-prelude.html b/engine/templates/header-prelude.html
new file mode 100644 (file)
index 0000000..e75c7c5
--- /dev/null
@@ -0,0 +1,12 @@
+{% for js_file in js_files %}
+<script type='text/javascript' src='{{ STATIC_URL }}{{ js_file|safe }}'></script>
+{% endfor %}
+{% for css_file in css_files %}
+<link rel='stylesheet' type='text/css' href='{{ STATIC_URL }}{{ css_file|safe }}' />
+{% endfor %}
+<script type="text/javascript">
+{% for js_chunk in js_chunks %} {{ js_chunk|safe }} {% endfor %}
+</script>
+<style type="text/css">
+{% for css_chunk in css_chunks %} {{ css_chunk|safe }} {% endfor %}
+</style>
index 7b05cc7..b67197d 100644 (file)
@@ -7,6 +7,7 @@ from django.shortcuts import render_to_response
 
 from plugins.verticallayout import VerticalLayout
 from plugins.simplelist import SimpleList
+from plugins.slicelist import SliceList
 
 from myslice.viewutils import topmenu_items, the_user, hard_wired_slice_names
 
@@ -34,7 +35,8 @@ def test_plugin_view (request):
 
     plugin_main1 = SimpleList (list=hard_wired_list, 
                                header='Hard wired', 
-                               foo='the value for foo')
+                               foo='the value for foo',
+                               with_datatables=True)
     plugin_main2 = SimpleList (hidable=True, 
                                list=hard_wired_slice_names,
                                headers='Slices in main content')
@@ -49,10 +51,11 @@ def test_plugin_view (request):
 
     ##########
     # lacks a/href to /slice/%s
-    plugin_related = SimpleList (visible=True, hidable=True,
-                                 need_datatables='yes', 
-                                 list=hard_wired_slice_names, 
-                                 header='Slices' )
+    plugin_related = SliceList (visible=True, 
+                                hidable=True,
+                                with_datatables='yes', 
+                                list=hard_wired_slice_names, 
+                                header='Slices' )
     content_related = plugin_related.render (request)
     # likewise but on the side view
     template_env [ 'content_related' ] = content_related
@@ -65,6 +68,7 @@ def test_plugin_view (request):
     # request.plugin_prelude holds a summary of the requirements() for all plugins
     # define {js,css}_{files,chunks}
     prelude_env = request.plugin_prelude.render_env()
+    print 'prelude_env',prelude_env
     template_env.update(prelude_env)
 
     return render_to_response ('view-plugin.html',template_env,
index c2ba250..6e041c6 100644 (file)
@@ -2,15 +2,30 @@ from engine.plugin import Plugin
 
 class SimpleList (Plugin) :
 
+    # it would make sense to *not* define any constructor here and let Plugin kick in
+    # however it feels nicer this way as we document the settings used in our own template
+    # plus it's less confusing for any subclass if they can be sure which constructor to call
+    def __init__ (self, list=[], with_datatables=False, **settings):
+        Plugin.__init__ (self, **settings)
+        self.list=list
+        self.add_to_settings ('list')
+        self.with_datatables = with_datatables
+        self.add_to_settings ('with_datatables')
+
     # SimpleList is useless per se anyways
     def title (self) : return "Title for Simple List"
 
     def template (self): return "simplelist.html"
 
     def requirements (self):
-        return { 'js_files' : [ "js/simplelist.js" ],
+        reqs = { 'js_files' : [ "js/simplelist.js" ],
                  'css_files': [ "css/simplelist.css" ],
+                 }
+        if self.with_datatables:
+            reqs['js_files'].append ("datatables/js/dataTables.js")
+            reqs['js_files'].append ("js/with-datatables.js")
+        print self.classname(),reqs
+        return reqs
 # for tests
 #                 'js_chunks' : "/* a javascript chunk */",       
 #                 'css_chunks': "/* a css style */ ",
-                 }
diff --git a/plugins/slicelist.py b/plugins/slicelist.py
new file mode 100644 (file)
index 0000000..ac8fc25
--- /dev/null
@@ -0,0 +1,21 @@
+from plugins.simplelist import SimpleList
+
+class SliceList (SimpleList):
+    
+    def __init__ (self, list=[], **settings):
+        SimpleList.__init__(self, **settings)
+        self.list = [ "<a href='/slice/%s/' class='slicelist'>%s</a>"%(x,x) for x in list ]
+        self.add_to_settings ('list')
+
+    def title (self):
+        return "Slice list"
+
+#    def requirements (self):
+#        reqs=SimpleList.requirements(self)
+#        reqs['js_files'].append('slice.js')
+#        reqs['js_files'].append('slice2.js')
+#        reqs['css_files'].append('slice.css')
+#        reqs['css_files'].append('slice2.css')
+#        reqs['js_chunks']=['js chunk1','js chunk2']
+#        reqs['css_chunks']=['css chunk1','css chunk2']
+#        return reqs
index fb5812e..39c0298 100644 (file)
@@ -1,10 +1,10 @@
-<table class='simplelist {%if need_datatables %}need-datatables{% endif %}'>
+<table class='simplelist {%if with_datatables %}with-datatables{% endif %}'>
 {% if header %}
 <thead><tr><th>{{ header }}</th></tr></thead>
 {% endif %}
 <tbody>
 {% for item in list %}
-<tr><td>{{ item }}</td></tr>
+<tr><td>{{ item|safe }}</td></tr>
 {% endfor %}
 </tbody>
 </table>
diff --git a/static/js/need-datatables.js b/static/js/need-datatables.js
deleted file mode 100644 (file)
index ad1664b..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/* elements with class 'need-datatables' are set to use datatables */
-$(document).ready(function() {$('.need-datatables').each(function() { $(this).dataTable() } ) } )
diff --git a/static/js/with-datatables.js b/static/js/with-datatables.js
new file mode 100644 (file)
index 0000000..6acc764
--- /dev/null
@@ -0,0 +1,2 @@
+/* elements with class 'with-datatables' are set to use datatables */
+$(document).ready(function() {$('.with-datatables').each(function() { window.console.log('here'); $(this).dataTable() } ) } )
index 855e4aa..f8cdc10 100644 (file)
@@ -9,13 +9,12 @@
 <script type="text/javascript">
 {# In case we need to add raw js code - use {% insert prelude_js %} ... {% endinsert %} #}
 {% container prelude_js %}
-{{ js_chunks }}
 </script>
 <style type="text/css">
 {# In case we need to add raw css code #}
 {% container prelude_css %}
-{{ css_chunks }}
 </style>
+{{ header_prelude }}
 </head>
 
 {# let's add these ones no matter what #}
 {% insert_str prelude "js/plugin.js" %}
 {% insert_str prelude "css/myslice.css" %}
 
-{# also add the stuff as collected in a Prelude class #}
-{% for js_file in js_files %} {% insert_str prelude js_file %} {% endfor %}
-{% for css_file in css_files %} {% insert_str prelude css_file %} {% endfor %}
-
 <body>
 
 {% block container %}