From d2ab222245b6311d81f9465cde3f48761c077168 Mon Sep 17 00:00:00 2001 From: Thierry Parmentelat Date: Tue, 19 Mar 2013 12:49:11 +0100 Subject: [PATCH] expose each query ONCE to js, plugin gets initialized with query_uuid only --- manifold/js/manifold-async.js | 52 +++++++++++++++--------------- manifold/js/manifold-queries.js | 27 ++++++++++++++++ manifold/js/manifold-query.js | 12 +++---- manifold/manifoldquery.py | 8 ++--- plugins/lists/simplelist.py | 4 +-- plugins/querycode/querycode.js | 5 +-- plugins/querycode/querycode.py | 2 +- plugins/quickfilter/quickfilter.js | 6 ++-- unfold/page.py | 39 +++++++++++++--------- unfold/plugin.py | 15 ++++++--- unfold/templates/page-queries.js | 8 +++++ 11 files changed, 114 insertions(+), 64 deletions(-) create mode 100644 manifold/js/manifold-queries.js create mode 100644 unfold/templates/page-queries.js diff --git a/manifold/js/manifold-async.js b/manifold/js/manifold-async.js index 98433775..c33185d1 100644 --- a/manifold/js/manifold-async.js +++ b/manifold/js/manifold-async.js @@ -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': } +// input queries are specified as a list of {'query_uuid': , 'id': } 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 = '

Error

Notice
  • ' + jQuery('
    ').text(str).html() + '
'; @@ -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 index 00000000..1e2fc629 --- /dev/null +++ b/manifold/js/manifold-queries.js @@ -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]); + } + }, +} + diff --git a/manifold/js/manifold-query.js b/manifold/js/manifold-query.js index 710f5d94..09ba089f 100644 --- a/manifold/js/manifold-query.js +++ b/manifold/js/manifold-query.js @@ -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; } diff --git a/manifold/manifoldquery.py b/manifold/manifoldquery.py index 4ee9c01e..9881f41d 100644 --- a/manifold/manifoldquery.py +++ b/manifold/manifoldquery.py @@ -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 diff --git a/plugins/lists/simplelist.py b/plugins/lists/simplelist.py index 5681bb72..a5fc685c 100644 --- a/plugins/lists/simplelist.py +++ b/plugins/lists/simplelist.py @@ -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'] diff --git a/plugins/querycode/querycode.js b/plugins/querycode/querycode.js index e8719c3a..eab1238e 100644 --- a/plugins/querycode/querycode.js +++ b/plugins/querycode/querycode.js @@ -76,10 +76,11 @@ 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; } diff --git a/plugins/querycode/querycode.py b/plugins/querycode/querycode.py index 5211d637..87dc4c65 100644 --- a/plugins/querycode/querycode.py +++ b/plugins/querycode/querycode.py @@ -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 diff --git a/plugins/quickfilter/quickfilter.js b/plugins/quickfilter/quickfilter.js index 5be5426f..f32c0c9e 100644 --- a/plugins/quickfilter/quickfilter.js +++ b/plugins/quickfilter/quickfilter.js @@ -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); } }); @@ -248,7 +248,7 @@ 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() { @@ -271,7 +271,7 @@ query.update_filter(key[1], '=', f_value); } } - $.publish('/query/' + query.uuid + '/changed', query); + $.publish('/query/' + query.query_uuid + '/changed', query); }); } diff --git a/unfold/page.py b/unfold/page.py index a8bc0f42..d0c97271 100644 --- a/unfold/page.py +++ b/unfold/page.py @@ -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 diff --git a/unfold/plugin.py b/unfold/plugin.py index 1b710520..17931b67 100644 --- a/unfold/plugin.py +++ b/unfold/plugin.py @@ -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 index 00000000..63a5aa90 --- /dev/null +++ b/unfold/templates/page-queries.js @@ -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); +}) -- 2.43.0