From: Thierry Parmentelat Date: Thu, 7 Mar 2013 17:00:50 +0000 (+0100) Subject: new object pluginset X-Git-Tag: myslice-django-0.1-1~55 X-Git-Url: http://git.onelab.eu/?p=myslice.git;a=commitdiff_plain;h=fcebef2a30c4061ef8b7e302ad9e88554ed6803a new object pluginset a bit like Plugins in php acts as a context for a given page has the Prelude object for the side effects must be passed to Plugin creation --- diff --git a/Makefile b/Makefile index c4074fa6..a29b5b3a 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ force: #################### compute emacs tags # list files under git but exclude third-party stuff like bootstrap and jquery myfiles: force - @git ls-files | egrep -v 'insert(_|-)above|/bootstrap.*[0-9]|/jquery/|datatables/' + @git ls-files | egrep -v 'insert(_|-)above|static/bootstrap|/jquery/|datatables/' # in general it's right to rely on the contents as reported by git tags: force diff --git a/auth/backend.py b/auth/backend.py index 0eb1f2d6..4c93676a 100644 --- a/auth/backend.py +++ b/auth/backend.py @@ -1,10 +1,6 @@ # import the User object from django.contrib.auth.models import User -# import the IMAP library -#from imaplib import IMAP4 - -# import time - this is used to create Django's internal username import time # Name my backend 'MyCustomBackend' diff --git a/auth/manifoldbackend.py b/auth/manifoldbackend.py index 54b16e72..dbaf863c 100644 --- a/auth/manifoldbackend.py +++ b/auth/manifoldbackend.py @@ -1,10 +1,8 @@ -# import the User object -from django.contrib.auth.models import User -from engine.manifoldapi import ManifoldAPI +import time +from django.contrib.auth.models import User -# import time - this is used to create Django's internal username -import time +from engine.manifoldapi import ManifoldAPI # Name my backend 'ManifoldBackend' class ManifoldBackend: diff --git a/engine/manifoldapi.py b/engine/manifoldapi.py index b125a595..b900855f 100644 --- a/engine/manifoldapi.py +++ b/engine/manifoldapi.py @@ -1,5 +1,6 @@ # Manifold API Python interface import xmlrpclib + from myslice.config import Config debug=True diff --git a/engine/plugin.py b/engine/plugin.py index cad2706d..00b37b7c 100644 --- a/engine/plugin.py +++ b/engine/plugin.py @@ -6,6 +6,7 @@ import json from django.template.loader import render_to_string +from engine.pluginset import PluginSet from engine.prelude import Prelude #################### @@ -15,7 +16,14 @@ from engine.prelude import Prelude # . True : to debug all plugin DEBUG= False -DEBUG= [ 'SimpleList' ] +#DEBUG= [ 'SimpleList' ] + +# decorator to deflect calls on Plugin to its PluginSet +def to_prelude (method): + def actual (self, *args, **kwds): + prelude_method=Prelude.__dict__[method.__name__] + return prelude_method(self.pluginset.prelude,*args, **kwds) + return actual class Plugin: @@ -31,6 +39,7 @@ class Plugin: ########## # Constructor #### mandatory + # . pluginset: 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) @@ -46,8 +55,9 @@ class Plugin: # p=Plugin(foo='bar') # which will result in 'foo' being accessible to the template engine # - def __init__ (self, title, domid=None, + def __init__ (self, pluginset, title, domid=None, visible=True, togglable=True, toggled=True, **settings): + self.pluginset = pluginset self.title=title if not domid: domid=Plugin.newdomid() self.domid=domid @@ -64,6 +74,8 @@ class Plugin: print "%s init dbg .... BEG"%self.classname 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.pluginset.record_plugin(self) def _classname (self): try: return self.__class__.__name__ @@ -102,8 +114,6 @@ class Plugin: # returns the html code for that plugin # in essence, wraps the results of self.render_content () def render (self, request): - # initialize prelude placeholder if needed - self._init_prelude (request) # call render_content plugin_content = self.render_content (request) # shove this into plugin.html @@ -118,7 +128,7 @@ class Plugin: env ['settings_json' ] = self.settings_json() # compute plugin-specific initialization js_init = render_to_string ( 'plugin-setenv.js', env ) - self.add_js_chunks (request, js_init) + self.add_js_chunks (js_init) # interpret the result of requirements () self.handle_requirements (request) @@ -144,26 +154,6 @@ class Plugin: print "%s.render_content: END --------------------"%self.classname return result - #################### requirements/prelude management - def _init_prelude (self, request): - if not hasattr (request, 'plugin_prelude'): - # include css/plugins.css - request.plugin_prelude=Prelude(css_files='css/plugin.css') - - # can be used directly in render_content() - def add_js_files (self, request, files): - self._init_prelude (request) - request.plugin_prelude.add_js_files (files) - def add_css_files (self, request, files): - self._init_prelude (request) - request.plugin_prelude.add_css_files (files) - def add_js_chunks (self, request, chunks): - self._init_prelude (request) - request.plugin_prelude.add_js_chunks (chunks) - def add_css_chunks (self, request, chunks): - self._init_prelude (request) - request.plugin_prelude.add_css_chunks (chunks) - # or from the result of self.requirements() def handle_requirements (self, request): try: @@ -172,8 +162,8 @@ class Plugin: 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) + method=PluginSet.__dict__[method_name] + method(self.pluginset,v) except AttributeError: # most likely the object does not have that method defined, which is fine pass @@ -182,6 +172,17 @@ class Plugin: traceback.print_exc() pass + #################### requirements/prelude management + # just forward to self.pluginset - see decorator above + @to_prelude + def add_js_files (self):pass + @to_prelude + def add_css_files (self):pass + @to_prelude + def add_js_chunks (self):pass + @to_prelude + def add_css_chunks (self):pass + ######################################## abstract interface # your plugin is expected to implement either # (*) def render_content(self, request) -> html fragment diff --git a/engine/pluginset.py b/engine/pluginset.py new file mode 100644 index 00000000..633874ce --- /dev/null +++ b/engine/pluginset.py @@ -0,0 +1,66 @@ +# the supervisor for Plugins +# keeps a handle on all present plugins for managing their queries in a consistent way +# it is expected to exist one such object for a given page + +from engine.prelude import Prelude + +# decorator to deflect calls on this PluginSet to its prelude +def to_prelude (method): + def actual (self, *args, **kwds): + prelude_method=Prelude.__dict__[method.__name__] + return prelude_method(self.prelude,*args, **kwds) + return actual + +class PluginSet: + + def __init__ (self): + self._plugins = {} + # queue of queries + self._queue=[] + self.prelude=Prelude(css_files='css/plugin.css') + # no queries yet, needed ? + + # record known plugins hashed on their domid + def record_plugin (self, plugin): + self._plugins[plugin.domid]=plugin + + def get_plugin (self, domid): + return self._plugins.get(domid,None) + + def reset_queue (self): + self._queue = [] + + # the js async methods (see manifold_async_success) + # offer the option to deliver the result to a specific DOM elt + # otherwise it goes through the pubsub using query's uuid + def query_enqueue (self, query, domid=None): + self._queue.append ( (query,domid,) ) + + # return the javascript that triggers all the queries + def exec_queue_asynchroneously (self): + js = "" + js += "var manifold_query_array = new Array();" + for (query,domid) in self._queue: + qjson=query.to_json() + id="'%s'"%domid if domid else undefined + js += "manifold_query_array.push({'query':'%(qjson)s', 'id':%(id)s});"%locals() + js += "onFunctionAvailable('manifold_async_exec', function() {manifold_async_exec(manifold_query_array);}, this, true);" + self.reset_queue() + # run only once the document is ready + js = "jQuery(function(){%(js)s})"%locals() + self.prelude.inspect('before add_js_chunks in async') + self.add_js_chunks (js) + self.prelude.inspect('after add_js_chunks in async') + + #################### requirements/prelude management + # just forward to self.pluginset - see decorator above + @to_prelude + def add_js_files (self):pass + @to_prelude + def add_css_files (self):pass + @to_prelude + def add_js_chunks (self):pass + @to_prelude + def add_css_chunks (self):pass + @to_prelude + def template_env (self):pass diff --git a/engine/prelude.py b/engine/prelude.py index 2975cca1..29053551 100644 --- a/engine/prelude.py +++ b/engine/prelude.py @@ -2,12 +2,14 @@ from types import StringTypes, ListType from django.template.loader import render_to_string +debug=True + class Prelude: """A class for collecting dependencies on js/css files or fragments""" keys=[ 'js_files','css_files','js_chunks', 'css_chunks' ] - def __init__ (self, js_files=[], css_files=[], js_chunks=[], css_chunks=[]): + def __init__ (self, js_files=None, css_files=None, js_chunks=None, css_chunks=None): # it's tempting to use sets but sets are not ordered.. self.js_files = Prelude._normalize(js_files) self.css_files = Prelude._normalize(css_files) @@ -16,7 +18,8 @@ class Prelude: @staticmethod def _normalize (input): - if isinstance (input, ListType): return input + if not input: return [] + elif isinstance (input, ListType): return input elif isinstance (input, StringTypes): return [ input ] else: return list (input) @@ -27,10 +30,19 @@ class Prelude: for i in Prelude._normalize (x): if i not in self.css_files: self.css_files.append(i) def add_js_chunks (self, x): + print 'add_js_chunks BEFORE',len(self.js_chunks) self.js_chunks += Prelude._normalize (x) + print 'add_js_chunks AFTER',len(self.js_chunks) def add_css_chunks (self, x): self.css_chunks += Prelude._normalize (x) + def inspect_string (self,msg): + result = 'Prelude.inspect %s (%s) with '%(msg,self) + result += ",".join( [ "%s->%s"%(k,len(getattr(self,k))) for k in ['js_files','js_chunks','css_files','css_chunks'] ] ) + return result + def inspect (self,msg): + print self.inspect_string(msg) + # first attempt was to use a simple dict like this # env={} # env['js_files']= self.js_files @@ -46,6 +58,8 @@ class Prelude: # # so a much simpler and safer approach is for use to compute the html header directly def template_env (self): + inspect = self.inspect ('template_env') + print inspect env={} env['js_files']= self.js_files env['css_files']= self.css_files diff --git a/engine/static/js/onavail.js b/engine/static/js/onavail.js new file mode 100644 index 00000000..57ef5520 --- /dev/null +++ b/engine/static/js/onavail.js @@ -0,0 +1,18 @@ +onavail_debug=true; + +function onFunctionAvailable(sMethod, oCallback, oObject, bScope) { + if (eval('typeof ' + sMethod) == 'function') { + if (onavail_debug) console.log("onFunctionAvailable, running"); + bScope ? oCallback.call(oObject) : oCallback(oObject); + } else { + if (onavail_debug) console.log("onFunctionAvailable, delaying for 50 ms"); + setTimeout(function () {onFunctionAvailable(sMethod, oCallback, oObject, bScope);}, 50); + } +} +function onObjectAvailable(sMethod, oCallback, oObject, bScope) { + if (eval('typeof ' + sMethod) == 'object') { + bScope ? oCallback.call(oObject) : oCallback(oObject); + } else { + setTimeout(function () {onObjectAvailable(sMethod, oCallback, oObject, bScope);}, 50); + } +} diff --git a/engine/static/js/plugin.js b/engine/static/js/plugin.js index 0a8bd44d..709421ed 100644 --- a/engine/static/js/plugin.js +++ b/engine/static/js/plugin.js @@ -1,7 +1,3 @@ -/* - * This file is included in includes/js_libraries.php - */ - function getMetadata(){ return all_headers; } diff --git a/myslice/dashboard.py b/myslice/dashboard.py index 142d33b4..3fa6d205 100644 --- a/myslice/dashboard.py +++ b/myslice/dashboard.py @@ -7,14 +7,11 @@ from django.shortcuts import render_to_response from django.contrib.auth.decorators import login_required +from engine.pluginset import PluginSet from engine.manifoldquery import ManifoldQuery -#from plugins.verticallayout import VerticalLayout -#from plugins.tabs import Tabs from plugins.simplelist import SimpleList -# from plugins.slicelist import SliceList -# from plugins.quickfilter import QuickFilter -# from plugins.raw import Raw + # from myslice.viewutils import topmenu_items, the_user # from myslice.viewutils import hard_wired_slice_names, hard_wired_list, lorem_p, lorem, quickfilter_criterias @@ -22,6 +19,8 @@ from myslice.viewutils import topmenu_items, the_user @login_required def dashboard_view (request): + pluginset = PluginSet() + slices_query = ManifoldQuery (action='get', method='slice', timestamp='latest', @@ -31,10 +30,8 @@ def dashboard_view (request): # in addition this currently returns all slices anyways sort='slice_hrn',) - # variables that will get passed to this template - template_env = {} - main_plugin = SimpleList ( # setting visible attributes first + pluginset=pluginset, title='SimpleList and dataTables', header='slices list', with_datatables=True, @@ -43,12 +40,15 @@ def dashboard_view (request): query=slices_query, key='slice_hrn', value='slice_hrn', -) + ) + # variables that will get passed to the view-plugin.html template + template_env = {} + # define 'content_main' to the template engine template_env [ 'content_main' ] = main_plugin.render(request) -# ########## +# ########## add another plugin with the same request, on the RHS pane # # lacks a/href to /slice/%s # related_plugin = SliceList (title='SliceList plugin',domid='slicelist1', # with_datatables='yes', @@ -58,15 +58,18 @@ def dashboard_view (request): # template_env [ 'content_related' ] = related_plugin.render (request) # more general variables expected in the template - template_env [ 'title' ] = 'Test Plugin View' + template_env [ 'title' ] = 'SimpleList Test View' + # the menu items on the top template_env [ 'topmenu_items' ] = topmenu_items('dashboard', request) + # so we can sho who is logged template_env [ 'username' ] = the_user (request) + pluginset.exec_queue_asynchroneously () + # request.plugin_prelude holds a summary of the requirements() for all plugins # define {js,css}_{files,chunks} - prelude_env = request.plugin_prelude.template_env() + prelude_env = pluginset.template_env() template_env.update(prelude_env) - return render_to_response ('view-plugin.html',template_env, context_instance=RequestContext(request)) diff --git a/plugins/simplelist.py b/plugins/simplelist.py index 815170ec..19a77692 100644 --- a/plugins/simplelist.py +++ b/plugins/simplelist.py @@ -14,7 +14,7 @@ class SimpleList (Plugin) : def template_file (self): return "simplelist.html" def requirements (self): - reqs = { 'js_files' : [ "js/simplelist.js", "js/plugin.js", "js/query.js", + reqs = { 'js_files' : [ "js/simplelist.js", "js/plugin.js", "js/query.js", "js/onavail.js", "js/manifold-pubsub.js", "js/manifold-async.js", ] , 'css_files': [ "css/simplelist.css" ], } diff --git a/templates/layout-myslice.html b/templates/layout-myslice.html index 22309baa..98c6f789 100644 --- a/templates/layout-myslice.html +++ b/templates/layout-myslice.html @@ -9,7 +9,7 @@ {{ header_prelude }} {# let's add these ones no matter what #} {% insert_str prelude "jquery/js/jquery.js" %} -{% insert prelude_js %} "jQuery.noConflict();" {% endinsert %} +{# {% insert prelude_js %} jQuery.noConflict(); {% endinsert %} #} {% insert_str prelude "js/plugin-init.js" %} {% insert_str prelude "css/myslice.css" %}