turn off default site on jessie
[myslice.git] / unfold / plugin.py
index 17931b6..229f196 100644 (file)
@@ -16,12 +16,14 @@ from unfold.prelude import Prelude
 # . True : to debug all plugin
 
 DEBUG= False
-#DEBUG= [ 'SliceList' ]
-DEBUG=True
+#DEBUG= [ 'SimpleList' ]
+#DEBUG=True
 
 # decorator to deflect calls on Plugin to its Prelude through self.page.prelude
 def to_prelude (method):
     def actual (self, *args, **kwds):
+        if not self.page: # jordan
+            return None
         prelude_method=Prelude.__dict__[method.__name__]
         return prelude_method(self.page.prelude,*args, **kwds)
     return actual
@@ -32,10 +34,14 @@ class Plugin:
     # we just need this to be unique in a page
     domid=0
 
-    @staticmethod
-    def newdomid():
+    # when a domid is not set by the caller, we name plugins after their respective class as well, 
+    # so as to limit name clashes between different views
+    # this has to see with the UI storing the last-seen status of plugins based on their id
+    # put it more bluntly it is recommended that a domid should be set 
+    # and maybe xxx we should just enforce that...
+    def newdomid(self):
         Plugin.domid += 1
-        return "plugin-%d"%Plugin.domid
+        return "plugin-%s-%d"%(self.__class__.__name__.lower(),Plugin.domid)
 
     ########## 
     # Constructor
@@ -43,10 +49,26 @@ class Plugin:
     # . page: the context of the request being served
     # . title: is used visually for displaying the widget
     #### optional
-    # . togglable: whether it can be turned on and off (like PleKitToggle)
-    # . toggled: if togglable, what's the initial status
     # . visible: if not set the plugin does not show up at all
     #            (not quite sure what this was for)
+    # . togglable: whether it can be turned on and off by clicking on the title (like PleKitToggle)
+    # . toggled:   whether the plugin should startup open/shown or closed/hidden
+    #              possible values are
+    #   .. True         : start up open/hidden
+    #   .. False        : start up closed/shown
+    #   .. 'persistent' : start up as it was the last time that browser showed it (based on 'domid')
+    #                NOTE that it is required for you to set a domid if you want to use persistent mode
+    #                     since domid is the key for storing that data in the browser storage space
+    #   .. None         : if not passed to __init__ at all, then the default_toggled() method is called
+    #   ..              : anything else, defaults to True
+    # . outline_complete: whether the overall plugin (body + toggle buttons/title) needs to receive
+    #                     a border and extra space
+    # . outline_body    : same but for the plugin body only
+    #      for these 2 outline_ flags, possible values mimick the above behaviour, i.e.:
+    #   .. True:        : outline is on
+    #   .. False:       : outline is off
+    #   .. None:        : calls default_outline_complete() on the plugin object
+    #
     #### internal data
     # . domid: created internally, but can be set at creation time if needed
     #          useful for hand-made css, or for selecting an active plugin in a composite
@@ -56,18 +78,28 @@ class Plugin:
     # p=Plugin(foo='bar')
     # which will result in 'foo' being accessible to the template engine
     # 
-    def __init__ (self, page, title, domid=None,
-                  visible=True, togglable=True, toggled=True, **settings):
+    def __init__ (self, page, title=None, domid=None,
+                  visible=True, togglable=None, toggled=None,
+                  outline_complete=None, outline_body=None,
+                  **settings):
         self.page = page
-        self.title=title
         # callers can provide their domid for css'ing 
-        if not domid: domid=Plugin.newdomid()
+        if not domid: domid=self.newdomid()
         self.domid=domid
+        # title is shown when togglable
+        #if not title: title="Plugin title for %s"%domid
+        self.title=title
         self.classname=self._py_classname()
         self.plugin_classname=self._js_classname()
         self.visible=visible
-        self.togglable=togglable
-        self.toggled=toggled
+        if togglable is None:           self.togglable=self.default_togglable()
+        else:                           self.togglable=togglable
+        if toggled is None:             self.toggled=self.default_toggled()
+        else:                           self.toggled=toggled
+        if outline_complete is None:    self.outline_complete=self.default_outline_complete()
+        else:                           self.outline_complete=outline_complete
+        if outline_body is None:        self.outline_body=self.default_outline_body()
+        else:                           self.outline_body=outline_body
         # what comes from subclasses
         for (k,v) in settings.iteritems():
             setattr(self,k,v)
@@ -78,7 +110,11 @@ class Plugin:
             for (k,v) in self.__dict__.items(): print "dbg %s:%s"%(k,v)
             print "%s init dbg .... END"%self.classname
         # do this only once the structure is fine
-        self.page.record_plugin(self)
+        if self.page: # I assume we can have a None page (Jordan)
+            self.page.record_plugin(self)
+
+    def __repr__ (self):
+        return "[%s]:%s"%(self.classname,self.domid)
 
     def _py_classname (self): 
         try:    return self.__class__.__name__
@@ -103,7 +139,7 @@ class Plugin:
             except: return '%s:"undefined"'%setting
         else:
             value=getattr(self,setting,None)
-            if not value: value = "unknown-setting-%s"%setting
+            if value is None: value = "unknown-setting-%s"%setting
         # first try to use to_json method (json.dumps not working on class instances)
         try:    value_json=value.to_json()
         except: value_json=json.dumps(value,separators=(',',':'))
@@ -127,10 +163,6 @@ class Plugin:
     def export_json_settings (self):
         return 'query_uuid' in self.json_settings_list()
     
-    # by default we create a timer if there's a query attached, redefine to change this behaviour
-    def start_with_spin (self):
-        return self.export_json_settings()
-
     # returns the html code for that plugin
     # in essence, wraps the results of self.render_content ()
     def render (self, request):
@@ -139,19 +171,32 @@ class Plugin:
         # shove this into plugin.html
         env = {}
         env ['plugin_content']= plugin_content
-        # need_spin is used in plugin.html
-        self.need_spin=self.start_with_spin()
         env.update(self.__dict__)
+        # translate high-level 'toggled' into 4 different booleans
+        self.need_toggle = False
+        if self.toggled=='persistent':
+            # start with everything turned off and let the js callback do its job
+            env.update({'persistent_toggle':True,'display_hide_button':False,
+                        'display_show_button':False,'display_body':False})
+        elif self.toggled==False:
+            env.update({'persistent_toggle':False,'display_hide_button':False,
+                        'display_show_button':True,'display_body':False})
+        else:
+            env.update({'persistent_toggle':False,'display_hide_button':True,
+                        'display_show_button':False,'display_body':True})
         if self.need_debug(): 
             print "rendering plugin.html with env keys %s"%env.keys()
+            for (k,v) in env.items(): 
+                if "display" in k or "persistent" in k: print k,'->',v
         result = render_to_string ('plugin.html',env)
 
         # export this only for relevant plugins
         if self.export_json_settings():
             env ['settings_json' ] = self.settings_json()
             # compute plugin-specific initialization
-            js_init = render_to_string ( 'plugin-setenv.js', env )
-            self.add_js_chunks (js_init)
+            js_init = render_to_string ( 'plugin-init.js', env )
+            # make sure this happens first in js
+            self.add_js_init_chunks (js_init)
         
         # interpret the result of requirements ()
         self.handle_requirements (request)
@@ -164,7 +209,12 @@ class Plugin:
     def render_content (self, request):
         """Should return an HTML fragment"""
         template = self.template_file()
-        env=self.template_env(request)
+        # start with a fresh one
+        env={}
+        # add our own settings as defaults
+        env.update(self.__dict__)
+        # then the things explicitly defined in template_env()
+        env.update(self.template_env(request))
         if not isinstance (env,dict):
             raise Exception, "%s.template_env returns wrong type"%self.classname
         result=render_to_string (template, env)
@@ -203,6 +253,8 @@ class Plugin:
     @to_prelude
     def add_css_files (self):pass
     @to_prelude
+    def add_js_init_chunks (self):pass
+    @to_prelude
     def add_js_chunks (self):pass
     @to_prelude
     def add_css_chunks (self):pass
@@ -221,6 +273,11 @@ class Plugin:
     def template_file (self):           return "undefined_template"
     def template_env (self, request):   return {}
 
+    def default_togglable (self):       return False
+    def default_toggled (self):         return 'persistent'
+    def default_outline_complete (self):return False
+    def default_outline_body(self):     return False
+
 #    # tell the framework about requirements (for the document <header>)
 #    # the notion of 'Media' in django provides for medium-dependant
 #    # selection of css files
@@ -252,6 +309,3 @@ class Plugin:
     #
     # whether we export the json settings to js
     # def export_json_settings (self)
-    #
-    # whether we show an initial spinner
-    # def start_with_spin (self)