Merge branch 'master' of ssh://git.onelab.eu/git/myslice
authorCiro Scognamiglio <ciro.scognamiglio@cslash.net>
Tue, 22 Oct 2013 11:45:59 +0000 (13:45 +0200)
committerCiro Scognamiglio <ciro.scognamiglio@cslash.net>
Tue, 22 Oct 2013 11:45:59 +0000 (13:45 +0200)
18 files changed:
manifold/manifoldapi.py
manifold/static/js/manifold.js
myslice/config.py
myslice/myslice.ini [new file with mode: 0644]
plugins/googlemap/static/js/googlemap.js
plugins/hazelnut/static/js/hazelnut.js
plugins/messages/__init__.py
plugins/resources_selected/static/js/resources_selected.js
portal/accountview.py
portal/actions.py
portal/forms.py
portal/platformsview.py
portal/registrationview.py
portal/resourceview.py
portal/slicerequestview.py
portal/sliceview.py
portal/static/js/common.functions.js
portal/templates/slice-request-view.html

index 2a64a49..c00882a 100644 (file)
@@ -78,12 +78,7 @@ class ManifoldAPI:
 
         return func
 
-def execute_query(request, query):
-    if not 'manifold' in request.session or not 'auth' in request.session['manifold']:
-        print "W: Using hardcoded demo account for execute_query"
-        manifold_api_session_auth = {'AuthMethod': 'password', 'Username': 'demo', 'AuthString': 'demo'}
-    else:
-        manifold_api_session_auth = request.session['manifold']['auth']
+def _execute_query(request, query, manifold_api_session_auth):
     manifold_api = ManifoldAPI(auth=manifold_api_session_auth)
     print "-"*80
     print query
@@ -97,3 +92,15 @@ def execute_query(request, query):
     #Error running query: {'origin': [0, 'XMLRPCAPI'], 'code': 2, 'description': 'No such session: No row was found for one()', 'traceback': 'Traceback (most recent call last):\n  File "/usr/local/lib/python2.7/dist-packages/manifold/core/xmlrpc_api.py", line 68, in xmlrpc_forward\n    user = Auth(auth).check()\n  File "/usr/local/lib/python2.7/dist-packages/manifold/auth/__init__.py", line 245, in check\n    return self.auth_method.check()\n  File "/usr/local/lib/python2.7/dist-packages/manifold/auth/__init__.py", line 95, in check\n    raise AuthenticationFailure, "No such session: %s" % e\nAuthenticationFailure: No such session: No row was found for one()\n', 'type': 2, 'ts': None, 'value': None}
 
     return result['value'] 
+
+def execute_query(request, query):
+    if not 'manifold' in request.session or not 'auth' in request.session['manifold']:
+        raise Exception, "User not authenticated"
+    manifold_api_session_auth = request.session['manifold']['auth']
+    return _execute_query(request, query, manifold_api_session_auth)
+
+def execute_admin_query(request, query):
+    config = Config()
+    admin_user, admin_password = config.manifold_admin_user_password()
+    admin_auth = {'AuthMethod': 'password', 'Username': admin_user, 'AuthString': admin_password}
+    return _execute_query(request, query, admin_auth)
index 791e4cf..c4d0ef7 100644 (file)
@@ -730,6 +730,7 @@ var manifold = {
             if (publish_uuid)
                 $.publish("/results/" + publish_uuid + "/failed", [data.code, data.description] );
 
+/* DEMO - Debug Messages desactivated
             $("#notifications").notify("create", "sticky", {
               title: 'Warning',
               text: data.description
@@ -737,7 +738,7 @@ var manifold = {
               expires: false,
               speed: 1000
             });
-            
+*/            
         }
        if (manifold.asynchroneous_debug) 
            messages.debug ("========== asynchroneous_success " + query.object + " -- before process_query_records");
@@ -904,8 +905,10 @@ var manifold = {
                 manifold.run_query(query_ext.main_query_ext.update_query_ext.query);
                 break;
 
-            case FILTER_ADDED:
-                manifold.raise_query_event(query_uuid, event_type, value);
+            case FILTER_ADDED: 
+// Thierry - this is probably wrong but intended as a hotfix 
+// http://trac.myslice.info/ticket/32
+//                manifold.raise_query_event(query_uuid, event_type, value);
                 break;
             case FILTER_REMOVED:
                 manifold.raise_query_event(query_uuid, event_type, value);
index 9cf2407..31dc7e3 100644 (file)
@@ -2,10 +2,13 @@ import os.path
 from ConfigParser import RawConfigParser
 from myslice.settings import ROOT
 
+# myslice/myslice.ini
 # as this code suggests, you have the option to write myslice/myslice.ini
 # that looks like this
 #[manifold]
 #url = http://manifold.pl.sophia.inria.fr:7080/
+#admin_user = admin
+#admin_password = admin
 
 class Config:
 
@@ -16,11 +19,15 @@ class Config:
     # if you use a development backend running on this box, use "http://localhost:7080/"
     # the INRIA setup is with "http://manifold.pl.sophia.inria.fr:7080/"
 
+    default_manifold_admin_user     = 'admin'
+    default_manifold_admin_password = None
+
     _config_parser = None
 
     # having grown tired of screwing up with git stashes 
     # taking away my local config, we now more properly use
     # an external config file to override teh default
+    # XXX we might use support from manifold util classes --jordan
     @staticmethod
     def manifold_url ():
         if Config._config_parser: 
@@ -32,6 +39,20 @@ class Config:
         Config._config_parser=config
         return Config.manifold_url()
 
+    @staticmethod
+    def manifold_admin_user_password():
+        if Config._config_parser: 
+            admin_user = Config._config_parser.get('manifold','admin_user')
+            admin_password = Config._config_parser.get('manifold','admin_password')
+            return (admin_user, admin_password)
+        config = RawConfigParser ()
+        config.add_section('manifold')
+        config.set ('manifold', 'admin_user', Config.default_manifold_admin_user)
+        config.set ('manifold', 'admin_password', Config.default_manifold_admin_password)
+        config.read (os.path.join(ROOT,'myslice/myslice.ini'))
+        Config._config_parser=config
+        return Config.manifold_admin_user_password()
+
     # exporting these details to js
     @staticmethod
     def manifold_js_export ():
diff --git a/myslice/myslice.ini b/myslice/myslice.ini
new file mode 100644 (file)
index 0000000..325191d
--- /dev/null
@@ -0,0 +1,4 @@
+[manifold]
+url = http://localhost:7080
+admin_user = admin
+admin_password = demo
index 8cb652f..424b3aa 100644 (file)
@@ -154,7 +154,7 @@ googlemap_debug_detailed=false;
 
        // this record is *in* the slice
         new_record: function(record) {
-           if (googlemap_debug_detailed) messages.debug ("new_record");
+               if (googlemap_debug_detailed) messages.debug ("new_record");
             if (!(record['latitude'])) return false;
            
             // get the coordinates
@@ -162,33 +162,33 @@ googlemap_debug_detailed=false;
             var longitude=unfold.get_value(record['longitude']);
             var lat_lon = latitude + longitude;
 
-           // check if we've seen anything at that place already
-           // xxx might make sense to allow for some fuzziness, 
-           // i.e. consider 2 places equal if not further away than 300m or so...
-           var marker_s = this.by_lat_lon [lat_lon];
-           if ( marker_s == null ) {
-               marker_s = this.create_marker_struct (this.object, latitude, longitude);
-               this.by_lat_lon [ lat_lon ] = marker_s;
-               this.arm_marker(marker_s.marker, this.map);
-           }
+           // check if we've seen anything at that place already
+           // xxx might make sense to allow for some fuzziness, 
+           // i.e. consider 2 places equal if not further away than 300m or so...
+           var marker_s = this.by_lat_lon [lat_lon];
+           if ( marker_s == null ) {
+                       marker_s = this.create_marker_struct (this.object, latitude, longitude);
+                       this.by_lat_lon [ lat_lon ] = marker_s;
+                       this.arm_marker(marker_s.marker, this.map);
+               }
            
-           // now add a line for this resource in the marker
-           // xxx should compute checked here ?
-           // this is where the checkbox will be appended
-           var ul=marker_s.ul;
-           var checkbox = this.create_record_checkbox (record, ul, false);
-           if ( ! this.key in record ) return;
+           // now add a line for this resource in the marker
+           // xxx should compute checked here ?
+           // this is where the checkbox will be appended
+           var ul=marker_s.ul;
+           var checkbox = this.create_record_checkbox (record, ul, false);
+           if ( ! this.key in record ) return;
             var key_value = record[this.key];
-           // see XXX BACKSLASHES 
-           //var hrn = this.escape_id(key_value).replace(/\\/g, '');
-           var hrn = key_value;
+           // see XXX BACKSLASHES 
+           //var hrn = this.escape_id(key_value).replace(/\\/g, '');
+           var hrn = key_value;
             this.by_hrn[hrn] = {
-               checkbox: checkbox,
-               // xxx Thierry sept 2013
-               // xxx actually we might have just used a domid-based scheme instead of the hash
-               // since at this point we only need to retrieve the checkbox from an hrn
-               // but I was not sure enough that extra needs would not show up so I kept this in place
-               // xxx not sure these are actually useful :
+                   checkbox: checkbox,
+                       // xxx Thierry sept 2013
+                       // xxx actually we might have just used a domid-based scheme instead of the hash
+                       // since at this point we only need to retrieve the checkbox from an hrn
+                       // but I was not sure enough that extra needs would not show up so I kept this in place
+                       // xxx not sure these are actually useful :
                 value: key_value,
                 record: record,
             }
index bdb2de7..21b23f5 100644 (file)
 
 
             var checkbox_id = this.flat_id(this.id('checkbox', key_value));
-            checkbox_id = '#' + checkbox_id;
+            // function escape_id(myid) is defined in portal/static/js/common.functions.js
+            checkbox_id = escape_id(checkbox_id);
                // using dataTables's $ to search also in nodes that are not currently displayed
             var element = this.table.$(checkbox_id);
                if (debug) messages.debug("set_checkbox checked=" + checked + " id=" + checkbox_id + " matches=" + element.length);
index 65baea1..7ee0c3c 100644 (file)
@@ -2,6 +2,7 @@ from unfold.plugin import Plugin
 
 # lists levels and sets them to enabled or not at startup
 default_levels = {'fatal': True, 'error': True, 'warning' : True, 'info' : True, 'debug' : False}
+#default_levels = {'fatal': False, 'error': False, 'warning' : False, 'info' : False, 'debug' : False}
 
 # there are two implementations available here
 # one shows up in the main page like a regular part of the page,
index d64d717..9a06447 100644 (file)
         // - Key and confirmation could be sufficient, or key and record state
         // XXX move record state to the manifold plugin API
 
-        on_field_state_changed: function(request, key, value, status)
+        on_field_state_changed: function(result)
         {
-            this.set_state(request, key, value, status);
+            console.log(result)
+            /* this.set_state(result.request, result.key, result.value, result.status); */
+            this.set_state(result);
         },
 
         // XXX we will have the requests for change
index d97126f..d4b68f4 100644 (file)
@@ -142,19 +142,26 @@ def account_process(request):
         messages.success(request, 'Sucess: Password Updated.')
         return HttpResponseRedirect("/portal/account/")
 
+# XXX TODO: Factorize with portal/registrationview.py
+
     elif 'generate' in request.POST:
         for account_detail in account_details:
             for platform_detail in platform_details:
                 if platform_detail['platform_id'] == account_detail['platform_id']:
                     if 'myslice' in platform_detail['platform']:
+                        from Crypto.PublicKey import RSA
+                        private = RSA.generate(1024)
+                        private_key = json.dumps(private.exportKey())
+                        public  = private.publickey()
+                        public_key = json.dumps(public.exportKey(format='OpenSSH'))
                         # Generate public and private keys using SFA Library
-                        from sfa.trust.certificate  import Keypair
-                        k = Keypair(create=True)
-                        public_key = k.get_pubkey_string()
-                        private_key = k.as_pem()
-                        private_key = ''.join(private_key.split())
-                        public_key = "ssh-rsa " + public_key
-                        keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
+#                        from sfa.trust.certificate  import Keypair
+#                        k = Keypair(create=True)
+#                        public_key = k.get_pubkey_string()
+#                        private_key = k.as_pem()
+#                        private_key = ''.join(private_key.split())
+#                        public_key = "ssh-rsa " + public_key
+                        keypair = '{"user_public_key":'+ public_key + ', "user_private_key":'+ private_key + '}'
 #                       keypair = re.sub("\r", "", keypair)
 #                       keypair = re.sub("\n", "\\n", keypair)
 #                       #keypair = keypair.rstrip('\r\n')
index 21b2563..c66b10a 100644 (file)
@@ -18,12 +18,12 @@ def authority_get_pis(request, authority_hrn):
     return results
 
 def authority_get_pi_emails(request,authority_hrn):
-    user_hrns = authority_get_pis(request,authority_hrn)
-    
-    query = Query.get('user').filter_by('user_hrn', 'included', user_hrns).select('user_email')
+    pi_users = authority_get_pis(request,authority_hrn)
+    pi_user_hrns = [ hrn for x in pi_users for hrn in x['pi_users'] ]
+    query = Query.get('user').filter_by('user_hrn', 'included', pi_user_hrns).select('email')
     results = execute_query(request,query)
-    
-    return [result['user_email'] for result in results]
+    print "mails",  [result['email'] for result in results]
+    return [result['email'] for result in results]
 
 # SFA add record (user, slice)
 
index 109d966..6a23e78 100644 (file)
@@ -62,13 +62,29 @@ class SliceRequestForm(forms.Form):
 #    email = forms.EmailField()
 #    cc_myself = forms.BooleanField(required=False)
 
-    slice_name = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))
-    authority_hrn = forms.ChoiceField(choices=[(1, 'un')],widget=forms.Select(attrs={'class':'form-control'}))
-    number_of_nodes  = forms.DecimalField(widget=forms.TextInput(attrs={'class':'form-control'}))
-    type_of_nodes = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))
-    purpose = forms.CharField(widget=forms.Textarea(attrs={'class':'form-control'}))
-    email = forms.EmailField(widget=forms.TextInput(attrs={'class':'form-control'}))
-    cc_myself = forms.BooleanField(required=False,widget=forms.CheckboxInput(attrs={'class':'form-control'}))
+    slice_name = forms.CharField(
+        widget=forms.TextInput(attrs={'class':'form-control'}), 
+        help_text="Enter a name for the slice you wish to create")
+    authority_hrn = forms.ChoiceField(
+        widget    = forms.Select(attrs={'class':'form-control'}),
+        choices   = [],
+        help_text = "Please select an authority responsible for vetting your slice")
+    number_of_nodes = forms.DecimalField(
+        widget    = forms.TextInput(attrs={'class':'form-control'}),
+        help_text = "Enter the number of nodes you expect to request (informative only)")
+    type_of_nodes = forms.CharField(
+        widget    = forms.TextInput(attrs={'class':'form-control'}),
+        help_text = "Enter the type of nodes you expect to request (informative only)")
+    purpose = forms.CharField(
+        widget    = forms.Textarea(attrs={'class':'form-control'}),
+        help_text = "Enter the purpose of your experiment (informative only)")
+    email = forms.EmailField(
+        widget    = forms.TextInput(attrs={'class':'form-control'}),
+        help_text = "Enter your email address")
+    cc_myself = forms.BooleanField(
+        widget    = forms.CheckboxInput(attrs={'class':'form-control'}),
+        required  = False,
+        help_text = "Please indicate whether you would like to be CC'ed to the request email")
 
     def __init__(self, *args, **kwargs):
         initial =  kwargs.get('initial', {})
@@ -87,5 +103,8 @@ class SliceRequestForm(forms.Form):
         if authority_hrn:# and authority_hrn[0] not in (c[0] for c in authority_hrn):
             # XXX This does not work, the choicefield is not updated...
             #self.fields['authority_hrn'].choices.extend(authority_hrn)
-            self.fields['authority_hrn'] = forms.ChoiceField( choices=authority_hrn)
+            self.fields['authority_hrn'] = forms.ChoiceField(
+                widget    = forms.Select(attrs={'class':'form-control'}),
+                choices   = authority_hrn,
+                help_text = "Please select an authority responsible for vetting your slice")
     
index ddc9689..d3c3ca0 100644 (file)
@@ -14,8 +14,8 @@ class PlatformsView(TemplateView):
     def get_context_data(self, **kwargs):
         page = Page(self.request)
 
-        #platform_query  = Query().get('local:platform').filter_by('disabled', '==', '0').select('platform','platform_longname','gateway_type')
-        platform_query  = Query().get('local:platform').select('platform','platform_longname','gateway_type')
+        platform_query  = Query().get('local:platform').filter_by('disabled', '==', '0').select('platform','platform_longname','gateway_type')
+        #platform_query  = Query().get('local:platform').select('platform','platform_longname','gateway_type')
         page.enqueue_query(platform_query)
 
         page.expose_js_metadata()
index aefdaa7..ba73700 100644 (file)
@@ -1,4 +1,5 @@
 import os.path, re
+import json
 
 from django.core.mail           import send_mail
 
@@ -9,7 +10,7 @@ from django.shortcuts           import render
 from unfold.page                import Page
 from ui.topmenu                 import topmenu_items
 
-from manifold.manifoldapi       import execute_query
+from manifold.manifoldapi       import execute_admin_query
 from manifold.core.query        import Query
 
 from portal.models              import PendingUser
@@ -30,10 +31,18 @@ class RegistrationView (View):
         errors = []
 
         authorities_query = Query.get('authority').\
-            filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc']).\
             select('name', 'authority_hrn')
-        #authorities_query = Query.get('authority').select('authority_hrn')
-        authorities = execute_query(request, authorities_query)
+        
+        onelab_enabled_query = Query.get('local:platform').filter_by('platform', '==', 'ple-onelab').filter_by('disabled', '==', 'False')
+        #onelab_enabled = not not execute_admin_query(request, onelab_enabled_query)
+        onelab_enabled = True
+        if onelab_enabled:
+            print "ONELAB ENABLED"
+            authorities_query = authorities_query.filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc', 'ple.ibbtple'])
+        else:
+            print "FIREXP ENABLED"
+
+        authorities = execute_admin_query(request, authorities_query)
         # xxx tocheck - if authorities is empty, it's no use anyway
         # (users won't be able to validate the form anyway)
 
@@ -61,16 +70,24 @@ class RegistrationView (View):
             # XXX validate authority hrn !!
             if PendingUser.objects.filter(email__iexact=reg_email):
                 errors.append('Email already registered.Please provide a new email address.')
+
+# XXX TODO: Factorize with portal/accountview.py
             if 'generate' in request.POST['question']:
-                # Generate public and private keys using SFA Library
-                from sfa.trust.certificate  import Keypair
-                k = Keypair(create=True)
-                public_key = k.get_pubkey_string()
-                private_key = k.as_pem()
-                private_key = ''.join(private_key.split())
-                public_key = "ssh-rsa " + public_key
+                from Crypto.PublicKey import RSA
+                private = RSA.generate(1024)
+                private_key = json.dumps(private.exportKey())
+                public  = private.publickey()
+                public_key = json.dumps(public.exportKey(format='OpenSSH'))
+
+#                # Generate public and private keys using SFA Library
+#                from sfa.trust.certificate  import Keypair
+#                k = Keypair(create=True)
+#                public_key = k.get_pubkey_string()
+#                private_key = k.as_pem()
+#                private_key = ''.join(private_key.split())
+#                public_key = "ssh-rsa " + public_key
                 # Saving to DB
-                keypair = '{"user_public_key":"'+ public_key + '", "user_private_key":"'+ private_key + '"}'
+                keypair = '{"user_public_key":'+ public_key + ', "user_private_key":'+ private_key + '}'
                 #keypair = re.sub("\r", "", keypair)
                 #keypair = re.sub("\n", "\\n", keypair)
                 #keypair = keypair.rstrip('\r\n')
index 22d4b2e..0421854 100644 (file)
@@ -48,7 +48,7 @@ class ResourceView(TemplateView):
             title      = 'Geographic view',
             domid      = 'resources-map',
             # tab's sons preferably turn this off
-            togglable  = False,
+            togglable  = True,
             query      = resource_query,
             query_all  = resource_query,
             checkboxes = False,
index de1f83d..e8c80d8 100644 (file)
@@ -3,7 +3,7 @@ from django.shortcuts            import render
 from django.core.mail            import send_mail
 
 from manifold.core.query         import Query
-from manifold.manifoldapi        import execute_query
+from manifold.manifoldapi        import execute_admin_query, execute_query
 
 from portal.models               import PendingSlice
 from portal.actions              import authority_get_pi_emails
@@ -14,12 +14,20 @@ from ui.topmenu                  import topmenu_items, the_user
 class SliceRequestView (LoginRequiredAutoLogoutView):
 
     def authority_hrn_initial (self, request):
-#        authorities_query = Query.get('authority').filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc']).select('name', 'authority_hrn')
-        authorities_query = Query.get('authority').select('authority_hrn')
-        authorities = execute_query(request, authorities_query)
-        authorities = sorted(authorities)
+        authorities_query = Query.get('authority').\
+            select('name', 'authority_hrn')
         
-        authority_hrn_tuples = [ (authority['authority_hrn'], authority['name'],) for authority in authorities ]
+        onelab_enabled_query = Query.get('local:platform').filter_by('platform', '==', 'ple-onelab').filter_by('disabled', '==', 'False')
+        #onelab_enabled = not not execute_admin_query(request, onelab_enabled_query)
+        onelab_enabled = True
+        if onelab_enabled:
+            authorities_query = authorities_query.filter_by('authority_hrn', 'included', ['ple.inria', 'ple.upmc', 'ple.ibbtple'])
+
+        authorities = execute_admin_query(request, authorities_query)
+        #authorities = sorted(authorities)
+        
+        authority_hrn_tuples = [ (authority['authority_hrn'], authority['name'] if authority['name'] else authority['authority_hrn'],) for authority in authorities ]
+        print "authority_hrn_tuples=", authority_hrn_tuples
         return {'authority_hrn': authority_hrn_tuples}
 
     # because we inherit LoginRequiredAutoLogoutView that is implemented by redefining 'dispatch'
@@ -56,6 +64,7 @@ class SliceRequestView (LoginRequiredAutoLogoutView):
             if cc_myself:
                 recipients.append(email)
             msg = render_to_string('slice-request-email.txt', form.cleaned_data)
+            print "email, msg, email, recipients", email , msg, email, recipients 
             send_mail("Onelab user %s requested a slice"%email , msg, email, recipients)
 
             return render(request,'slice-request-ack-view.html') # Redirect after POST
index b9293b9..9d335f4 100644 (file)
@@ -133,8 +133,7 @@ class SliceView (LoginRequiredAutoLogoutView):
             domid               = 'filters',
             sons                = [filter_query_editor, filter_active_filters],
             togglable           = True,
-            # start turned off, it will open up itself when stuff comes in
-            toggled             = False,
+            toggled             = 'persistent',
             outline_complete    = True, 
         )
         main_stack.insert (filters_area)
@@ -161,6 +160,7 @@ class SliceView (LoginRequiredAutoLogoutView):
         resources_as_list = Hazelnut( 
             page       = page,
             domid      = 'resources-list',
+            title      = 'List view',
             # this is the query at the core of the slice list
             query      = sq_resource,
             query_all  = query_resource_all,
@@ -172,23 +172,9 @@ class SliceView (LoginRequiredAutoLogoutView):
                 },
             )
 
-        # List area itself is a Stack with hazelnut on top,
-        # and a togglable tabs for customization plugins 
-        resources_as_list_area = Stack(
-            page        = page,
-            title       = 'Resources as a List',
-            domid       = 'resources-list-area',
-            sons= [ resources_as_list, 
-                    Tabs ( page=page,
-                           title="Customize Resources layout",
-                           togglable=True,
-                           toggled='persistent',
-                           domid="customize-resources",
-                           outline_complete=True,
-                           #sons = [ resources_query_editor, resources_active_filters, ],
-                           ),
-                    ],
-            )
+        # with the new 'Filter' stuff on top, no need for anything but the hazelnut
+        resources_as_list_area = resources_as_list 
+
         resources_area = Tabs ( page=page, 
                                 domid="resources",
                                 togglable=True,
@@ -230,52 +216,52 @@ class SliceView (LoginRequiredAutoLogoutView):
                     'bAutoWidth'     : True,
                 },
             ))
-    
+# DEMO    
         # --------------------------------------------------------------------------
         # MEASUREMENTS
-        tab_measurements = Tabs (
-            page                = page,
-            active_domid        = 'measurements-list',
-            outline_complete    = True,
-            togglable           = True,
-            title               = 'Measurements',
-            domid               = 'measurements',
-        )
-        main_stack.insert(tab_measurements)
-    
-        tab_measurements.insert(Hazelnut( 
-            page        = page,
-            title       = 'Measurements',
-            domid       = 'measurements-list',
-            # tab's sons preferably turn this off
-            togglable   = False,
-            # this is the query at the core of the slice list
-            query       = sq_measurement,
-            # do NOT set checkboxes to False
-            # this table being otherwise empty, it just does not fly with dataTables
-            checkboxes  = True,
-            datatables_options = { 
-                'iDisplayLength' : 25,
-                'bLengthChange'  : True,
-                'bAutoWidth'     : True,
-            },
-        ))
-    
-        # --------------------------------------------------------------------------
-        # MESSAGES (we use transient=False for now)
-        main_stack.insert(Messages(
-            page   = page,
-            title  = "Runtime messages for slice %s"%slicename,
-            domid  = "msgs-pre",
-            levels = "ALL",
-            # plain messages are probably less nice for production but more reliable for development for now
-            transient = False,
-            # these make sense only in non-transient mode..
-            togglable = True,
-            toggled = 'persistent',
-            outline_complete = True,
-        ))
-    
+#        tab_measurements = Tabs (
+#            page                = page,
+#            active_domid        = 'measurements-list',
+#            outline_complete    = True,
+#            togglable           = True,
+#            title               = 'Measurements',
+#            domid               = 'measurements',
+#        )
+#        main_stack.insert(tab_measurements)
+#    
+#        tab_measurements.insert(Hazelnut( 
+#            page        = page,
+#            title       = 'Measurements',
+#            domid       = 'measurements-list',
+#            # tab's sons preferably turn this off
+#            togglable   = False,
+#            # this is the query at the core of the slice list
+#            query       = sq_measurement,
+#            # do NOT set checkboxes to False
+#            # this table being otherwise empty, it just does not fly with dataTables
+#            checkboxes  = True,
+#            datatables_options = { 
+#                'iDisplayLength' : 25,
+#                'bLengthChange'  : True,
+#                'bAutoWidth'     : True,
+#            },
+#        ))
+#    
+#        # --------------------------------------------------------------------------
+#        # MESSAGES (we use transient=False for now)
+#        main_stack.insert(Messages(
+#            page   = page,
+#            title  = "Runtime messages for slice %s"%slicename,
+#            domid  = "msgs-pre",
+#            levels = "ALL",
+#            # plain messages are probably less nice for production but more reliable for development for now
+#            transient = False,
+#            # these make sense only in non-transient mode..
+#            togglable = True,
+#            toggled = 'persistent',
+#            outline_complete = True,
+#        ))
+#    
     
         # variables that will get passed to the view-unfold1.html template
         template_env = {}
index 2414216..56b02ca 100644 (file)
@@ -1,6 +1,10 @@
 /*
  * This file is included in tophat_render.php
  */
+// Escape special characters in jQuery Selector
+function escape_id( myid ) {
+    return "#" + myid.replace( /(:|\.|\[|\])/g, "\\$1" );
+}
 
 function getKeySplitId(id,separator){
     // id of elements must respect this rule
index 6983354..f437ae0 100644 (file)
@@ -21,7 +21,8 @@
     {% for field in form %}
     <div class="form-group">
       <label for="{{ field.html_name }}" class="col-xs-4 control-label">{{ field.label }}</label>
-      <div class="col-xs-4"> {{ field.errors }} {{ field }} <p class="form-hint">{{ field.help_text }}</p> </div>
+      <div class="col-xs-4"> {{ field.errors }} {{ field }} </div>
+      <div class="col-xs-4"> <p class="form-hint">{{ field.help_text }}</p> </div>
     </div>
     {% endfor %}
     <div class="col-xs-offset-4 col-xs-4">