expose each query ONCE to js, plugin gets initialized with query_uuid only
authorThierry Parmentelat <thierry.parmentelat@inria.fr>
Tue, 19 Mar 2013 11:49:11 +0000 (12:49 +0100)
committerThierry Parmentelat <thierry.parmentelat@inria.fr>
Tue, 19 Mar 2013 11:49:11 +0000 (12:49 +0100)
manifold/js/manifold-async.js
manifold/js/manifold-queries.js [new file with mode: 0644]
manifold/js/manifold-query.js
manifold/manifoldquery.py
plugins/lists/simplelist.py
plugins/querycode/querycode.js
plugins/querycode/querycode.py
plugins/quickfilter/quickfilter.js
unfold/page.py
unfold/plugin.py
unfold/templates/page-queries.js [new file with mode: 0644]

index 9843377..c33185d 100644 (file)
@@ -1,11 +1,11 @@
-manifold_async_debug=false;
+manifold_async_debug=true;
 
 // Helper functions for asynchronous requests
 
 var api_url = '/manifold/api/json/'
 
 // Executes all async. queries
-// input queries are specified as a list of {'query': new Query(..), 'id': <possibly null>}
+// input queries are specified as a list of {'query_uuid': <query_uuid>, 'id': <possibly null>}
 function manifold_async_exec(queries) {
     if (manifold_async_debug) console.log('manifold_async_exec length='+ queries.length);
     // start spinners
@@ -14,17 +14,36 @@ function manifold_async_exec(queries) {
     // We use js function closure to be able to pass the query (array) to the
     // callback function used when data is received
     var manifold_async_success_closure = function(query, id) {
-        return function(data, textStatus) {manifold_async_success(data, query, id);}
-    };
+       return function(data, textStatus) {manifold_async_success(data, query, id);}};
 
     // Loop through query array and use ajax to send back queries (to frontend) with json
     jQuery.each(queries, function(index, tuple) {
-       hash=tuple.query.to_hash();
-       if (manifold_async_debug) console.log ("sending POST on " + api_url + " iterating on " + tuple + " -> " + hash);
-        jQuery.post(api_url, {'query': hash}, manifold_async_success_closure(tuple.query, tuple.id));
+       var query=manifold.find_query(tuple.query_uuid);
+       var hash=query.to_hash();
+       if (manifold_async_debug) console.log ("sending POST on " + api_url + " iterating on " + tuple.query_uuid + " -> " + hash);
+        jQuery.post(api_url, {'query': hash}, manifold_async_success_closure(query, tuple.id));
     })
 }
 
+function manifold_async_success(data, query, id) {
+    if (data) {
+
+        if (!!id) {
+            /* Directly inform the requestor */
+            jQuery('#' + id).trigger('results', [data]);
+        } else {
+            /* Publish an update announce */
+            jQuery.publish("/results/" + query.query_uuid + "/changed", [data, query]);
+        }
+
+        // Is there a linked query ?
+        //if ((query.done == 'now') && (query.ts == 'latest')) {
+        //    var new_query = [query_json.replace("latest", "now")];
+        //    manifold_async_exec(new_query);
+        //}
+    }
+}
+
 /* not used
 function manifold_async_error(str) {
     var out = '<div class="error"><h2>Error</h2><dl id="system-message"><dt class="error">Notice</dt><dd class="error message"><ul><li>' + jQuery('<div />').text(str).html() + '</li></ul></dd></dl></div>';
@@ -128,25 +147,6 @@ function manifold_update_template(data)
     });
 }
 
-function manifold_async_success(data, query, id) {
-    if (data) {
-
-        if (!!id) {
-            /* Directly inform the requestor */
-            jQuery('#' + id).trigger('results', [data]);
-        } else {
-            /* Publish an update announce */
-            jQuery.publish("/results/" + query.uuid + "/changed", [data, query]);
-        }
-
-        // Is there a linked query ?
-        //if ((query.done == 'now') && (query.ts == 'latest')) {
-        //    var new_query = [query_json.replace("latest", "now")];
-        //    manifold_async_exec(new_query);
-        //}
-    }
-}
-
 //http://stackoverflow.com/questions/5100539/django-csrf-check-failing-with-an-ajax-post-request
 //make sure to expose csrf in our outcoming ajax/post requests
 $.ajaxSetup({ 
diff --git a/manifold/js/manifold-queries.js b/manifold/js/manifold-queries.js
new file mode 100644 (file)
index 0000000..1e2fc62
--- /dev/null
@@ -0,0 +1,27 @@
+function debug_dict (msg, o) {
+    var keys=[];
+    for (var k in o) keys.push(k);
+    console.log ("debug_dict: " + msg + " Keys : " + keys);
+}
+function debug_value (msg, value) {
+    console.log ("debug_value: " + msg + " " + value);
+}
+
+/* manage a set of queries indexed by their id */
+/* next move will be to insert all the manifold functions in this namespace */
+/* xxx add error management */
+var manifold = {
+    all_queries: {},
+    insert_query : function (query) { 
+       manifold.all_queries[query.query_uuid]=query; 
+   },
+    find_query : function (query_uuid) { 
+       return manifold.all_queries[query_uuid];
+    },
+    debug_all_queries : function (msg) {
+       for (var query_uuid in manifold.all_queries) {
+           console.log("manifold.debug " + msg + " " + query_uuid + " -> " + manifold.all_queries[query_uuid]);
+       }
+    },
+}
+
index 710f5d9..09ba089 100644 (file)
@@ -1,5 +1,5 @@
-function ManifoldQuery(action, method, timestamp, filters, params, fields, unique, uuid, aq, sq)
-{  
+function ManifoldQuery(action, method, timestamp, filters, params, fields, unique, query_uuid, aq, sq) {  
+
     // get, update, delete, create
     var action;
     
@@ -21,8 +21,8 @@ function ManifoldQuery(action, method, timestamp, filters, params, fields, uniqu
     // 0,1 : list of element of an object or single object  
     var unique;
     
-    // uuid : unique identifier of a query
-    var uuid;
+    // query_uuid : unique identifier of a query
+    var query_uuid;
     
     // Query : root query (no sub-Query)
     var analyzed_query;
@@ -102,7 +102,7 @@ INSERT INTO method VALUES(field=value)
     this.analyze_subqueries = function() {
         /* adapted from the PHP function in com_tophat/includes/query.php */
         var q = new ManifoldQuery();
-        q.uuid = this.uuid;
+        q.query_uuid = this.query_uuid;
         q.action = this.action;
         q.method = this.method;
         q.timestamp = this.timestamp;
@@ -174,7 +174,7 @@ INSERT INTO method VALUES(field=value)
     this.params = params;
     this.fields = fields;
     this.unique = unique;
-    this.uuid = uuid;
+    this.query_uuid = query_uuid;
     this.analyzed_query = aq;
     this.subqueries = sq;
 }  
index 4ee9c01..9881f41 100644 (file)
@@ -10,7 +10,7 @@ class ManifoldQuery:
                   filters=[], params=[], fields=[],
                   sort=None, limit=None, offset=None,
                   ):
-        self.uuid=uniqid()
+        self.query_uuid=uniqid()
         # settable
         self.action=action
         self.method=method
@@ -26,7 +26,7 @@ class ManifoldQuery:
         self.subqueries = {}
 
     def to_json (self):
-        uuid=self.uuid
+        query_uuid=self.query_uuid
         a=self.action
         m=self.method
         t=self.timestamp
@@ -45,7 +45,7 @@ class ManifoldQuery:
                       for (method, subquery) in self.subqueries.iteritems()])
             sq="{%s}"%sq
         
-        return """ new ManifoldQuery('%(a)s', '%(m)s', '%(t)s', %(f)s, %(p)s, %(c)s, %(unique)s, '%(uuid)s', %(aq)s, %(sq)s)"""%locals()
+        return """ new ManifoldQuery('%(a)s', '%(m)s', '%(t)s', %(f)s, %(p)s, %(c)s, %(unique)s, '%(query_uuid)s', %(aq)s, %(sq)s)"""%locals()
     
     # this builds a ManifoldQuery object from a dict as received from javascript through its ajax request 
     # e.g. here's what I captured from the server's output
@@ -65,7 +65,7 @@ class ManifoldQuery:
 
     def analyze_subqueries(self):
         analyzed_query = ManifoldQuery()
-        analyzed_query.uuid = self.uuid
+        analyzed_query.query_uuid = self.query_uuid
         analyzed_query.action = self.action
         analyzed_query.method = self.method
         analyzed_query.timestamp = self.timestamp
index 5681bb7..a5fc685 100644 (file)
@@ -21,7 +21,7 @@ class SimpleList (Plugin) :
 
     def requirements (self):
         reqs = { 'js_files' : [ "js/simplelist.js", "js/plugin.js", "js/manifold-query.js", "js/onavail.js",
-                                "js/manifold-pubsub.js", "js/manifold-async.js", 
+                                "js/manifold-pubsub.js", "js/manifold-async.js", "js/manifold-queries.js",
                                 "js/spin.presets.js", "js/spin.min.js", "js/jquery.spin.js", 
                                 "js/myslice.js",
                                 ] ,
@@ -32,5 +32,5 @@ class SimpleList (Plugin) :
             reqs['js_files'].append ("js/with-datatables.js")
         return reqs
     
-    def json_settings_list (self): return ['plugin_uuid', 'query','query_uuid','key']
+    def json_settings_list (self): return ['plugin_uuid','query_uuid','key']
 
index e8719c3..eab1238 100644 (file)
 
        var lang=$plugindiv.find(".querycode-lang").val();
        var dom=$plugindiv.find(".querycode-viz");
-       var query = $plugindiv.data().QueryCode.options.query;
+       var query_uuid = $plugindiv.data().QueryCode.options.query_uuid;
+       var query=manifold.find_query(query_uuid);
        funname="translate_query_as_" + lang;
        fun=eval(funname);
-       if ( ! fun) {
+       if (! fun) {
            console.log("Cannot find translator function for lang " + lang);
            return;
        }
index 5211d63..87dc4c6 100644 (file)
@@ -29,7 +29,7 @@ class QueryCode (Plugin):
                            ],
             }
 
-    def json_settings_list (self): return ['plugin_uuid', 'query','query_uuid']
+    def json_settings_list (self): return ['plugin_uuid','query_uuid']
         
     # because we have a link to a query it looks like we need a spin, let's make this right
     def start_with_spin (self): return False
index 5be5426..f32c0c9 100644 (file)
@@ -87,7 +87,7 @@
                                         query=d.current_query;
                                         query.update_filter(key,op,val);
                                         // Publish the query changed, the other plugins with subscribe will get the changes
-                                        $.publish('/query/' + query.uuid + '/changed', query);
+                                        $.publish('/query/' + query.query_uuid + '/changed', query);
                                         //add_ActiveFilter("#QuickFilter-string-"+key,ui.item.value,d);
                                     }
                                });
             var filter_field = $('#QuickFilter_select_field').val();
 
             query.update_filter(filter_field, '=', filter_value);
-            $.publish('/query/' + query.uuid + '/changed', query);
+            $.publish('/query/' + query.query_uuid + '/changed', query);
         });
         
         $('.QuickFilter_select').change( function() {
                     query.update_filter(key[1], '=', f_value);
                 }
             }
-            $.publish('/query/' + query.uuid + '/changed', query);
+            $.publish('/query/' + query.query_uuid + '/changed', query);
         });
 
     }
index a8bc0f4..d0c9727 100644 (file)
@@ -4,8 +4,12 @@
 
 import json
 
-from unfold.prelude import Prelude
+from django.template.loader import render_to_string
+
 from manifold.manifoldapi import ManifoldAPI
+
+from unfold.prelude import Prelude
+
 from myslice.config import Config
 
 # decorator to deflect calls on this Page to its prelude
@@ -21,7 +25,9 @@ class Page:
         self.request=request
         # all plugins mentioned in this page
         self._plugins = {}
-        # queue of queries
+        # the set of all queries 
+        self._queries=set()
+        # queue of queries with maybe a domid, see enqueue_query
         self._queue=[]
         # global prelude object
         self.prelude=Prelude(css_files='css/plugin.css')
@@ -38,6 +44,7 @@ class Page:
         return self._plugins.get(domid,None)
     
     def reset_queue (self):
+        self._queries = set()
         self._queue = []
 
     # the js async methods (see manifold_async_success)
@@ -45,21 +52,21 @@ class Page:
     # otherwise (i.e. if domid not provided) 
     # it goes through the pubsub using query's uuid
     def enqueue_query (self, query, domid=None):
-        self._queue.append ( (query,domid,) )
+        self._queries = self._queries.union(set( [ query, ] ))
+        self._queue.append ( (query.query_uuid,domid,) )
 
     # return the javascript that triggers all the queries
+    # xxx could fruitfully be renamed expose_queries_to_javascript or something
     def exec_queue_asynchroneously (self):
-        js = ""
-        js += "var async_queries = new Array();\n"
-        for (query,domid) in self._queue:
-            qjson=query.to_json()
-            id="'%s'"%domid if domid else 'undefined'
-            js += "async_queries.push({'query':%(qjson)s, 'id':%(id)s});\n"%locals()
-        js += "onFunctionAvailable('manifold_async_exec', function() {manifold_async_exec(async_queries);}, this, true);"
+        # compute variables to expose to the template
+        env = {}
+        # expose the json definition of all queries
+        env['queries_jsons'] = [ query.to_json() for query in self._queries ]
+        env['query_uuid_domids'] = [ {'query_uuid' : a, 'domid': '"%s"'%b if b else 'null'} for (a,b) in self._queue ]
+        javascript = render_to_string ("page-queries.js",env)
         self.reset_queue()
-        # run only once the document is ready
-        js = "$(document).ready(function(){%(js)s})"%locals()
-        self.add_js_chunks (js)
+        self.add_js_chunks (javascript)
+
 
 
     def expose_js_metadata(self):
@@ -91,14 +98,14 @@ class Page:
 
             request.session['metadata'] = self._metadata
 
-        javascript = "all_headers=" + json.dumps(self._metadata) + ";"
-        self.add_js_chunks(javascript)
+#        javascript = "all_headers=" + json.dumps(self._metadata) + ";"
+#        self.add_js_chunks(javascript)
 
     def metadata_get_fields(self, method):
         return self._metadata[method]['column'].sort()
         
     def expose_js_manifold_config (self):
-        self.add_js_chunks(Config.manifold_js_export())
+        self.add_js_chunks(Config.manifold_js_export()+"\n")
 
     #################### requirements/prelude management
     # just forward to self.prelude - see decorator above
index 1b71052..17931b6 100644 (file)
@@ -16,7 +16,8 @@ from unfold.prelude import Prelude
 # . True : to debug all plugin
 
 DEBUG= False
-DEBUG= [ 'QuickFilter' ]
+#DEBUG= [ 'SliceList' ]
+DEBUG=True
 
 # decorator to deflect calls on Plugin to its Prelude through self.page.prelude
 def to_prelude (method):
@@ -98,7 +99,7 @@ class Plugin:
         if setting=='plugin_uuid':
             value=self.domid
         elif setting=='query_uuid':
-            try: value=self.query.uuid
+            try: value=self.query.query_uuid
             except: return '%s:"undefined"'%setting
         else:
             value=getattr(self,setting,None)
@@ -112,6 +113,9 @@ class Plugin:
     # and add plugin_uuid: domid in the mix
     # NOTE this plugin_uuid thing might occur in js files from joomla/js, ** do not rename **
     def settings_json (self):
+        exposed_settings=self.json_settings_list()
+        if 'query' in exposed_settings:
+            print "WARNING, cannot expose 'query' directly in json_settings_list, query_uuid is enough"
         result = "{"
         result += ",".join([ self.setting_json(setting) for setting in self.json_settings_list() ])
         result += "}"
@@ -121,8 +125,9 @@ class Plugin:
     # need to be prepared for js - meaning their json settings get exposed to js
     # others just get displayed and that's it
     def export_json_settings (self):
-        return 'query' in self.__dict__
+        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()
 
@@ -137,6 +142,8 @@ class Plugin:
         # need_spin is used in plugin.html
         self.need_spin=self.start_with_spin()
         env.update(self.__dict__)
+        if self.need_debug(): 
+            print "rendering plugin.html with env keys %s"%env.keys()
         result = render_to_string ('plugin.html',env)
 
         # export this only for relevant plugins
@@ -235,7 +242,7 @@ class Plugin:
     # mandatory : define the fields that need to be exposed to json as part of 
     # plugin initialization
     # mention 'domid' if you need plugin_uuid
-    # also 'query_uuid' gets replaced with query.uuid
+    # also 'query_uuid' gets replaced with query.query_uuid
     def json_settings_list (self): return ['json_settings_list-must-be-redefined']
 
     # might also define these ones:
diff --git a/unfold/templates/page-queries.js b/unfold/templates/page-queries.js
new file mode 100644 (file)
index 0000000..63a5aa9
--- /dev/null
@@ -0,0 +1,8 @@
+{% for json in queries_jsons %} manifold.insert_query({{ json|safe }});
+{% endfor %}
+$(document).ready(function () {
+var async_queries = new Array();
+{% for d in query_uuid_domids %} async_queries.push({'query_uuid':"{{ d.query_uuid }}", 'id':{{ d.domid }}});
+{% endfor %}
+manifold_async_exec(async_queries);
+})