improved form and wizard plugins
authorJordan Augé <jordan.auge@lip6.fr>
Tue, 11 Jun 2013 08:36:48 +0000 (10:36 +0200)
committerJordan Augé <jordan.auge@lip6.fr>
Tue, 11 Jun 2013 08:36:48 +0000 (10:36 +0200)
plugins/form/__init__.py
plugins/form/form.html
plugins/form/form.js
plugins/wizard/__init__.py
plugins/wizard/wizard.js
portal/views.py
unfold/page.py

index 5081501..734652e 100644 (file)
@@ -7,17 +7,35 @@ class CreateForm (Plugin):
         Plugin.__init__(self, **settings)
         print "SETTINGS", settings
         assert 'page'   in settings, "You should specify page"
-        assert 'object' in settings, "You should specify object"
+        assert 'object' in settings or 'fields' in settings, "You should specify object or field list"
 
-        # Retrieve object fields from metadata
-        metadata = settings['page'].get_metadata()
-        md_o = metadata.details_by_object(settings['object'])
-        self.columns = md_o['column']
+        if 'object' in settings:
+            # Retrieve object fields from metadata
+            metadata = settings['page'].get_metadata()
+            md_o = metadata.details_by_object(settings['object'])
+            self.columns = md_o['column']
+
+        elif 'fields' in settings:
+            self.columns = []
+            for field in settings['fields']:
+                c = {
+                    'name'          : field.get('name', ''),
+                    'field'         : field.get('field', ''),
+                    'type'          : field.get('type', 'input'),
+                    'description'   : field.get('description', ''),
+                    'validate_rx'   : field.get('validate_rx', ''),
+                    'validate_err'  : field.get('validate_err', ''),
+                    'old_value'     : 'POST',
+                }
+                self.columns.append(c)
     
     def requirements (self):
         return { 'js_files'     : ['js/form.js', 'js/jquery.validate.js', ],
                  'css_files'    : ['css/form.css'] 
                  }
+    def export_json_settings(self):
+        # We need initialization, even though we are not associated with a query
+        return True
 
     def template_env (self, request):
         env={}
@@ -28,11 +46,26 @@ class CreateForm (Plugin):
     def template_file (self):
         return "form.html"
 
-    def json_settings_list (self): return ['plugin_uuid']
+    def json_settings_list (self): return ['plugin_uuid', 'columns']
 
     def get_validation_js(self):
         # XXX We need to avoid sending the same query twice !"
         # somehow store something into the dom, to perform an update afterwards
         # XXX This should be moved to a template
         # XXX We also need some storage into the wizard to be displayed later
-        return "alert('validation'); return true;"
+        return """
+            // Useless since this is now a parameter
+            //frm = document.forms['form_%(domid)s'];
+
+            // Loop on the fields and test regexp if present
+            err = false;
+            $.each(options.columns, function(column) {
+                if (!frm.elements[column['field']].match(column['validate_rx'])) {
+                    $('err_%(domid)s_' + column['field']).html(column['validation_err']);
+                    err = true;
+                }
+            });
+            if (!err) {
+                // Issue json query
+            }
+        """ % self.__dict__
index 47b5e61..cc2226f 100644 (file)
@@ -1,13 +1,13 @@
-<div id="form-{{domid}}">
-  <form class="cmxform" id="commentForm" method="post" action="#" enctype="multipart/form-data" >
+<div id="form_plugin_{{domid}}">
+  <form class="cmxform" id="form_{{domid}}" method="post" action="#" enctype="multipart/form-data" onsubmit="return validate_form_{{domid}}(this)">
     <fieldset>
 
       {% for c in columns %}
       <div class="field">
         <label for="lname">{{c.name}}</label>
-        <input type="text" id="affiliation" name="affiliation" size="25" class="required" minlength="2" value="<?php echo $_POST['affiliation'] ?>"/>
-        <p class="hint">Enter {{c.description}}</p>
-        {{err}}
+        <input type="{{c.type}}" id="{{domid}}-{{c.field}}" name="{{c.field}}" size="25" class="required" minlength="2" value="{{c.old_value}}"/>
+        <p class="hint">{{c.description}}</p>
+        <span id='err-{{domid}}-{{c.field}}'><font color='red'>{{c.validation_err}}</font></span>
       </div>
       {% endfor %}
 
index d02779f..e877e57 100644 (file)
-// Jquery for the Registration page. /views/register/tmpl/deafult.php
-jQuery(document).ready(function(){
-    
-    jQuery("#commentForm").validate({
-        rules: {
-          password: { 
-                required: true
-          }, 
-          confirmpassword: { 
-                required: true, equalTo: "#password"
-          }
+/**
+ * Description: implements a form
+ * Copyright (c) 2013 UPMC Sorbonne Universite
+ * License: GPLv3
+ */
+
+/*
+ * It's a best practice to pass jQuery to an IIFE (Immediately Invoked Function
+ * Expression) that maps it to the dollar sign so it can't be overwritten by
+ * another library in the scope of its execution.
+ */
+(function($){
+
+    /***************************************************************************
+     * Method calling logic
+     ***************************************************************************/
+
+    $.fn.CreateForm = function( method ) {
+        if ( methods[method] ) {
+            return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
+        } else if ( typeof method === 'object' || ! method ) {
+            return methods.init.apply( this, arguments );
+        } else {
+            return undefined;
+            //$.error( 'Method ' +  method + ' does not exist on jQuery.CreateForm' );
+        }    
+    };
+
+    /***************************************************************************
+     * Public methods
+     ***************************************************************************/
+
+    var methods = {
+
+        /**
+         * @brief Plugin initialization
+         * @param options : an associative array of setting values
+         * @return : a jQuery collection of objects on which the plugin is
+         *     applied, which allows to maintain chainability of calls
+         */
+        init : function ( options ) {
+            return this.each(function() {
+                var $this = $(this);
+
+                /* An object that will hold private variables and methods */
+                var form = new CreateForm(options);
+                $this.data('plugin', form);
+
+                $(this).on('validate.Form', form.validate);
+                $(this).on('validate', form.validate);
+
+            }); // this.each
+        }, // init
+
+    };
+
+    /***************************************************************************
+     * CreateForm object
+     ***************************************************************************/
+
+    function CreateForm(options) {
+
+        /* save a reference to this */
+        var obj = this;
+
+        /* member variables */
+        this.options = options;
+
+        /* methods */
+
+        this.on_result = function(data) {
+
         }
-    });
-    // upload button
-    jQuery("#question").change(function(){
-        if(this.value=="upload"){
-            jQuery("#upload_key").show();
-        }else{
-            jQuery("#upload_key").hide();
+        
+        /**
+         * \brief Validate the form
+         * \param validate_callback (function) a callback to be triggered when validation is done
+         * \return True if all fields match validation regex
+         */
+        this.validate = function(validate_callback) {
+            var frm = document.forms['form_'+options.plugin_uuid]
+
+            // $this = $('#' + options.plugin_uuid); // useless
+
+            // Loop on the fields and test regexp if present
+            var err = false;
+            var params = {}
+            $.each(options.columns, function(i, column) {
+                var value = frm.elements[column['field']].value;
+                var rx    = column['validate_rx'];
+                var str   = '';
+                if (rx && !value.match(rx)) {
+                    str = column['validate_err'];
+                    err = true;
+                }
+                params[column['field']] = value;
+                $('#err-' + options.plugin_uuid + '-' + column['field']).html(str);
+            });
+
+            /* If the form correctly validates, we issue a create query */
+            if (!err) {
+                /* Inform user about ongoing query: spinner */
+
+                /* Issue json query and wait for callback */
+                // this.on_result()
+            }
+
+            /* Note, if the create has already been done (or fails, or ... ?)
+             * shall we proceed to an update ? */
+
+            /* We always return false. Only the query callback is in charge of
+             * advancing to next step */
+            return false;
         }
-    });
 
-});
+    }
+
+})( jQuery );
index 74ea3a9..672321c 100644 (file)
@@ -7,26 +7,6 @@ class Wizard(Composite):
         Composite.__init__(self, *args, **kwargs)
         self.validate_step_js = []
         
-        # This, as well as the setting passing code, requires all step to be passed at init :/
-        for i, son in enumerate(self.sons):
-            try:
-                js = son.get_validation_js() 
-                js_name = "%s_validate_step_%d" % (self.domid.replace('-', '_'), i)
-                self.add_js_chunks("""
-                %s = function() {
-                    %s
-                }
-                """ % (js_name, js))
-            except Exception, e:
-                js_name = 'null'
-            self.validate_step_js.append(js_name)
-
-#            self.add_js_chunks("""
-#            %s = function() {
-#                %s
-#            }
-#            """ % (js_name, js))
-
     def export_json_settings(self):
         # We need initialization, even though we are not associated with a query
         return True
@@ -41,4 +21,4 @@ class Wizard(Composite):
         return "wizard.html"
 
     # the list of things passed to the js plugin
-    def json_settings_list (self): return ['plugin_uuid', 'start_step', 'validate_step_js']
+    def json_settings_list (self): return ['plugin_uuid', 'start_step']
index b500101..de0643d 100644 (file)
@@ -1,6 +1,7 @@
 /**
  * Description: implements a wizard-like interface
- * Copyright (c) 2012 UPMC Sorbonne Universite
+ * Copyright (c) 2013 UPMC Sorbonne Universite
+ * Based on SmartWizard 2.0 plugin by Dipu (http://www.techlaboratory.net)
  * License: GPLv3
  */
 
  * Expression) that maps it to the dollar sign so it can't be overwritten by
  * another library in the scope of its execution.
  */
-
 (function($){
-    // routing calls
+
+    /***************************************************************************
+     * Method calling logic
+     ***************************************************************************/
+
     $.fn.Wizard = function( method ) {
         if ( methods[method] ) {
             return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
         } else if ( typeof method === 'object' || ! method ) {
             return methods.init.apply( this, arguments );
         } else {
-            $.error( 'Method ' +  method + ' does not exist on jQuery.Wizard' );
+            //$.error( 'Method ' +  method + ' does not exist on jQuery.Wizard' );
+            return undefined;
         }    
     };
 
 
     var methods = {
 
+        /**
+         * @brief Plugin initialization
+         * @param options : an associative array of setting values
+         * @return : a jQuery collection of objects on which the plugin is
+         *     applied, which allows to maintain chainability of calls
+         */
         init : function ( options ) {
+
+            /* Default settings */
+            var options = $.extend({}, $.fn.Wizard.defaults, options);
+
             return this.each(function() {
                 var $this = $(this);
+                var obj = $(wizard, this);
 
-                // Initialize the smart-wizard third-party jquery plugin
-                $(wizard, this).smartWizard({
-                    selected    : options.start_step - 1,
-                    errorSteps  : [5],
-                    onLeaveStep : leaveAStepCallback,
-//                  onFinish    : onFinishCallback
-                });
-
-                // XXX Mark some steps as done !
-                $(wizard, this).smartWizard('setDone',{stepnum: 1, isdone:true});
+                /* An object that will hold private variables and methods */
+                var form = new Wizard(options, obj);
+                $this.data('Wizard', form);
 
-                function leaveAStepCallback(obj){
-                    var step_num= obj.attr('rel')-1; // get the current step number
-                    func = options.validate_step_js[step_num];
-                    if (func == 'null')
-                        return true;
-                    return window[func]();
-                }
+                form.init();
 
-                function onFinishCallback(){
-                    window.location.href('/');
-                }
+//                // Initialize the smart-wizard third-party jquery plugin
+//                $(wizard, this).smartWizard({
+//                    selected    : options.start_step - 1,
+//                    errorSteps  : [5],
+//                    onLeaveStep : leaveAStepCallback,
+////                  onFinish    : onFinishCallback
+//                });
+//
+//                // XXX Mark some steps as done !
+//                $(wizard, this).smartWizard('setDone',{stepnum: 1, isdone:true});
+//
+//                function leaveAStepCallback(obj){
+//                    var step_num= obj.attr('rel')-1; // get the current step number
+//                    func = options.validate_step_js[step_num];
+//                    if (func == 'null')
+//                        return true;
+//                    return window[func]();
+//                }
+//
+//                function onFinishCallback(){
+//                    window.location.href('/');
+//                }
 
 
             }); // this.each
         } // init
 
     };
+
+    /***************************************************************************
+     * Wizard object
+     ***************************************************************************/
+
+    /**
+     * \param options (dict) : a dictionary of options
+     * \param obj (jQuery ref) : handler to the wizard plugin
+    */
+    function Wizard(options, obj) {
+
+        /* save a reference to this */
+        var $this = this;
+
+        /* member variables */
+        this.options = options;
+
+        /* methods */
+
+        /**
+         * \brief get a handle on a wizard step by id
+           \param stepIdx (integer) : step identifier (0-based)
+           \returns jQuery selector
+         */
+        this.get_step = function(stepIdx) 
+        {
+            return $('.plugin', $(stepIdx.attr('href')));
+        }
+
+        this.get_plugin = function(step) 
+        {
+            return step.data().plugin;
+        }
+
+        this.onLeaveStep = function(stepIdx) 
+        {
+            /* does the plugin has a validate entry ? */
+            var step = this.get_step(stepIdx);
+            var plugin = this.get_plugin(step);
+            if (plugin.validate) {
+                plugin.validate();
+            }
+        }
+    
+
+        this.init1 = function() {
+            $this.curStepIdx = options.selected;
+            $this.steps = $("ul > li > a[href^='#step-']", obj); // Get all anchors in this array
+            $this.contentWidth = 0;
+            //this.loader,msgBox,elmActionBar,elmStepContainer,btNext,btPrevious,btFinish;
+            
+            $this.elmActionBar = $('.actionBar',obj);
+            if($this.elmActionBar.length == 0){
+              $this.elmActionBar = $('<div></div>').addClass("actionBar");                
+            }
+
+            $this.msgBox = $('.msgBox',obj);
+            if($this.msgBox.length == 0){
+              $this.msgBox = $('<div class="msgBox"><div class="content"></div><a href="#" class="close">X</a></div>');
+              $this.elmActionBar.append($this.msgBox);                
+            }
+            
+            $('.close',$this.msgBox).click(function() {
+                $this.msgBox.fadeOut("normal");
+                return false;
+            });
+        } // this.init1
+
+        this.init = function() {
+            this.init1();
+
+            /* additonal init */
+            this.options.onLeaveStep = this.onLeaveStep;
+
+            var allDivs =obj.children('div'); //$("div", obj);                
+            obj.children('ul').addClass("anchor");
+            allDivs.addClass("content");
+            // Create Elements
+            loader = $('<div>Loading</div>').addClass("loader");
+            elmActionBar = $('<div></div>').addClass("actionBar");
+            elmStepContainer = $('<div></div>').addClass("stepContainer");
+            btNext = $('<a>'+options.labelNext+'</a>').attr("href","#").addClass("buttonNext");
+            btPrevious = $('<a>'+options.labelPrevious+'</a>').attr("href","#").addClass("buttonPrevious");
+            btFinish = $('<a>'+options.labelFinish+'</a>').attr("href","#").addClass("buttonFinish");
+            
+            // highlight steps with errors
+            if(options.errorSteps && options.errorSteps.length>0){
+              $.each(options.errorSteps, function(i, n){
+                $this.setError(n,true);
+              });
+            }
+
+
+            elmStepContainer.append(allDivs);
+            elmActionBar.append(loader);
+            obj.append(elmStepContainer);
+            obj.append(elmActionBar); 
+            if (options.includeFinishButton) {
+              elmActionBar.append(btFinish);
+            }
+            elmActionBar.append(btNext).append(btPrevious); 
+            contentWidth = elmStepContainer.width();
+
+            $(btNext).click(function() {
+                if($(this).hasClass('buttonDisabled')){
+                  return false;
+                }
+                $this.doForwardProgress();
+                return false;
+            }); 
+            $(btPrevious).click(function() {
+                if($(this).hasClass('buttonDisabled')){
+                  return false;
+                }
+                $this.doBackwardProgress();
+                return false;
+            }); 
+            $(btFinish).click(function() {
+                if(!$(this).hasClass('buttonDisabled')){
+                   if($.isFunction(options.onFinish)) {
+                      if(!options.onFinish.call(this,$(this.steps))){
+                        return false;
+                      }
+                   }else{
+                     var frm = $(obj).parents('form');
+                     if(frm && frm.length){
+                       frm.submit();
+                     }                         
+                   }                      
+                }
+
+                return false;
+            }); 
+            
+            $(this.steps).bind("click", function(e){
+                if(steps.index(this) == $this.curStepIdx){
+                  return false;                    
+                }
+                var nextStepIdx = steps.index(this);
+                var isDone = steps.eq(nextStepIdx).attr("isDone") - 0;
+                if(isDone == 1){
+                  $this.LoadContent(nextStepIdx);                    
+                }
+                return false;
+            }); 
+            
+            // Enable keyboard navigation                 
+            if(options.keyNavigation){
+                $(document).keyup(function(e){
+                    if(e.which==39){ // Right Arrow
+                      $this.doForwardProgress();
+                    }else if(e.which==37){ // Left Arrow
+                      $this.doBackwardProgress();
+                    }
+                });
+            }
+            //  Prepare the steps
+            this.prepareSteps();
+            // Show the first slected step
+            this.LoadContent($this.curStepIdx);                  
+        }
+
+        this.prepareSteps = function() {
+            if (!options.enableAllSteps) {
+                $(this.steps, obj).removeClass("selected").removeClass("done").addClass("disabled"); 
+                $(this.steps, obj).attr("isDone",0);                 
+            } else {
+                $(this.steps, obj).removeClass("selected").removeClass("disabled").addClass("done"); 
+                $(this.steps, obj).attr("isDone",1); 
+            }
+
+            $(this.steps, obj).each(function(i){
+                $($(this).attr("href"), obj).hide();
+                $(this).attr("rel",i+1);
+            });
+        }
+                    
+        this.LoadContent = function(stepIdx) {
+            var selStep = this.steps.eq(stepIdx);
+            var ajaxurl = options.contentURL;
+            var hasContent =  selStep.data('hasContent');
+            stepNum = stepIdx+1;
+            if(ajaxurl && ajaxurl.length>0){
+               if(options.contentCache && hasContent){
+                   this.showStep(stepIdx);                          
+               }else{
+                   $.ajax({
+                    url: ajaxurl,
+                    type: "POST",
+                    data: ({step_number : stepNum}),
+                    dataType: "text",
+                    beforeSend: function(){ loader.show(); },
+                    error: function(){loader.hide();},
+                    success: function(res){ 
+                      loader.hide();       
+                      if(res && res.length>0){  
+                         selStep.data('hasContent',true);            
+                         $($(selStep, obj).attr("href"), obj).html(res);
+                         this.showStep(stepIdx);
+                      }
+                    }
+                  }); 
+              }
+            }else{
+              this.showStep(stepIdx);
+            }
+        } // this.LoadContent
+                    
+        this.showStep = function(stepIdx) 
+        {
+            var selStep = this.steps.eq(stepIdx); 
+            var curStep = this.steps.eq($this.curStepIdx);
+
+
+            if(stepIdx != $this.curStepIdx){
+              if($.isFunction(options.onLeaveStep)) {
+                if(!options.onLeaveStep.call(this,$(curStep))){
+                  return false;
+                }
+              }
+            }     
+            if (options.updateHeight)
+                elmStepContainer.height($($(selStep, obj).attr("href"), obj).outerHeight());               
+            if(options.transitionEffect == 'slide'){
+              $($(curStep, obj).attr("href"), obj).slideUp("fast",function(e){
+                    $($(selStep, obj).attr("href"), obj).slideDown("fast");
+                    $this.curStepIdx =  stepIdx;                        
+                    $this.SetupStep(curStep,selStep);
+                  });
+            } else if(options.transitionEffect == 'fade'){                      
+              $($(curStep, obj).attr("href"), obj).fadeOut("fast",function(e){
+                    $($(selStep, obj).attr("href"), obj).fadeIn("fast");
+                    $this.curStepIdx =  stepIdx;                        
+                    $this.SetupStep(curStep,selStep);                           
+                  });                    
+            } else if(options.transitionEffect == 'slideleft'){
+                var nextElmLeft = 0;
+                var curElementLeft = 0;
+                if(stepIdx > $this.curStepIdx){
+                    nextElmLeft1 = contentWidth + 10;
+                    nextElmLeft2 = 0;
+                    curElementLeft = 0 - $($(curStep, obj).attr("href"), obj).outerWidth();
+                } else {
+                    nextElmLeft1 = 0 - $($(selStep, obj).attr("href"), obj).outerWidth() + 20;
+                    nextElmLeft2 = 0;
+                    curElementLeft = 10 + $($(curStep, obj).attr("href"), obj).outerWidth();
+                }
+                if(stepIdx == $this.curStepIdx){
+                    nextElmLeft1 = $($(selStep, obj).attr("href"), obj).outerWidth() + 20;
+                    nextElmLeft2 = 0;
+                    curElementLeft = 0 - $($(curStep, obj).attr("href"), obj).outerWidth();                           
+                }else{
+                    $($(curStep, obj).attr("href"), obj).animate({left:curElementLeft},"fast",function(e){
+                      $($(curStep, obj).attr("href"), obj).hide();
+                    });                       
+                }
+
+                $($(selStep, obj).attr("href"), obj).css("left",nextElmLeft1);
+                $($(selStep, obj).attr("href"), obj).show();
+                $($(selStep, obj).attr("href"), obj).animate({left:nextElmLeft2},"fast",function(e){
+                  $this.curStepIdx =  stepIdx;                        
+                  $this.SetupStep(curStep,selStep);                      
+                });
+            } else{
+                $($(curStep, obj).attr("href"), obj).hide(); 
+                $($(selStep, obj).attr("href"), obj).show();
+                $this.curStepIdx =  stepIdx;                        
+                $this.SetupStep(curStep,selStep);
+            }
+            return true;
+        } // this.showStep
+                    
+        this.SetupStep = function(curStep,selStep)
+        {
+            $(curStep, obj).removeClass("selected");
+            $(curStep, obj).addClass("done");
+            
+            $(selStep, obj).removeClass("disabled");
+            $(selStep, obj).removeClass("done");
+            $(selStep, obj).addClass("selected");
+            $(selStep, obj).attr("isDone",1);
+            $this.adjustButton();
+            if($.isFunction(options.onShowStep)) {
+               if(!options.onShowStep.call(this,$(selStep))){
+                 return false;
+               }
+            } 
+        }                
+                    
+        this.doForwardProgress = function()
+        {
+            var nextStepIdx = $this.curStepIdx + 1;
+            if(this.steps.length <= nextStepIdx){
+              if(!options.cycleSteps){
+                return false;
+              }                  
+              nextStepIdx = 0;
+            }
+            this.LoadContent(nextStepIdx);
+        }
+                    
+        this.doBackwardProgress = function()
+        {
+            var nextStepIdx = $this.curStepIdx-1;
+            if(0 > nextStepIdx){
+              if(!options.cycleSteps){
+                return false;
+              }
+              nextStepIdx = this.steps.length - 1;
+            }
+            this.LoadContent(nextStepIdx);
+        }  
+                    
+        this.adjustButton = function()
+        {
+            if(!options.cycleSteps){                
+              if(0 >= $this.curStepIdx){
+                $(btPrevious).addClass("buttonDisabled");
+              }else{
+                $(btPrevious).removeClass("buttonDisabled");
+              }
+              if(($this.steps.length-1) <= $this.curStepIdx){
+                $(btNext).addClass("buttonDisabled");
+              }else{
+                $(btNext).removeClass("buttonDisabled");
+              }
+            }
+            // Finish Button 
+            if(!$this.steps.hasClass('disabled') || options.enableFinishButton){
+              $(btFinish).removeClass("buttonDisabled");
+            }else{
+              $(btFinish).addClass("buttonDisabled");
+            }                  
+        }
+                    
+        this.showMessage = function(msg)
+        {
+            $('.content',msgBox).html(msg);
+            msgBox.show();
+        }
+                    
+        this.setError = function(stepnum,iserror)
+        {
+            if(iserror){                    
+              $(this.steps.eq(stepnum-1), obj).addClass('error')
+            }else{
+              $(this.steps.eq(stepnum-1), obj).removeClass("error");
+            }                                   
+        }                        
+
+        this.setDone = function(stepnum,isdone)
+        {
+            if(isdone){                    
+              $(this.steps.eq(stepnum-1), obj).removeClass("selected").removeClass("disabled").addClass('done')
+            }else{
+              $(this.steps.eq(stepnum-1), obj).removeClass("done");
+            }                                   
+        }
+    }
+
+    /// KEEP BELOW
+
+    // Default Properties and Events
+    $.fn.Wizard.defaults = {
+        selected: 0,  // Selected Step, 0 = first step   
+        keyNavigation: true, // Enable/Disable key navigation(left and right keys are used if enabled)
+        enableAllSteps: false,
+        updateHeight: true,
+        transitionEffect: 'fade', // Effect on navigation, none/fade/slide/slideleft
+        contentURL:null, // content url, Enables Ajax content loading
+        contentCache:true, // cache step contents, if false content is fetched always from ajax url
+        cycleSteps: false, // cycle step navigation
+        includeFinishButton: true, // whether to show a Finish button
+        enableFinishButton: false, // make finish button enabled always
+        errorSteps:[],    // Array Steps with errors
+        labelNext:'Next',
+        labelPrevious:'Previous',
+        labelFinish:'Finish',          
+        onLeaveStep: null, // triggers when leaving a step
+        onShowStep: null,  // triggers when showing a step
+        onFinish: null  // triggers when Finish button is clicked
+    };    
+
 })( jQuery );
index 4c4157e..ba7f30f 100644 (file)
@@ -33,6 +33,8 @@ def index(request):
     p << "<h3>User registration</h3>"
 
     sons = []
+    start_step = 1
+
     # STEP 1
     # If the user already exists (is logged), let's display a summary of his account details
     # Otherwise propose a form to fill in
@@ -40,9 +42,42 @@ def index(request):
         # Fill a disabled form with user info
         # Please logout to register another user
         sons.append(Raw(page=p, title=STEP1_TITLE, togglable=False, html=STEP0))
+        start_step += 1
     else:
         # XXX This should become local:user
-        sons.append(CreateForm(page = p, title = STEP1_TITLE, togglable = False, object = 'user'))
+        # We could pass a list of fields also, instead of retrieving them from metadata
+        # Otherwise we need some heuristics to display nice forms
+        field_list = [{
+            'name'        : 'First name',
+            'field'       : 'firstname',
+            'type'        : 'text',
+            'validate_rx' : '^[a-zA-Z -]+$',
+            'validate_err': 'Your first name must be comprised of letters only',
+            'description' : 'Enter your first name',
+        }, {
+            'name'        : 'Last name',
+            'field'       : 'lastname',
+            'type'        : 'text',
+            'validate_rx' : '^[a-zA-Z -]+$',
+            'validate_err': 'Your last name must be comprised of letters only',
+            'description' : 'Enter your last name',
+        }, { 
+            'name'        : 'Email',
+            'field'       : 'email',
+            'type'        : 'text',
+            'description' : 'Enter your email address',
+        }, {
+            'name'        : 'Password',
+            'field'       : 'password',
+            'type'        : 'password',
+            'description' : 'Enter your password',
+        }, {
+            'name'        : 'Confirm password',
+            'field'       : 'password2',
+            'type'        : 'password',
+            'description' : 'Enter your password again',
+        }]
+        sons.append(CreateForm(page = p, title = STEP1_TITLE, togglable = False, fields = field_list))
 
     # STEP 2
     # If the user already exists (is logged), let's display a summary of its institution
@@ -51,8 +86,9 @@ def index(request):
         # Fill a disabled form with institution
         # Please logout to register another user
         sons.append(Raw(page=p, title=STEP2_TITLE, togglable=False, html="User created"))
+        start_step += 1
     else:
-        sons.append(CreateForm(page = p, title = STEP2_TITLE, togglable = False, object = 'institution'))
+        sons.append(CreateForm(page = p, title = STEP2_TITLE, togglable = False, object = 'slice')) #institution'))
 
     # STEP3
     # Please should your prefered authentication method
@@ -78,7 +114,7 @@ def index(request):
         title      = WIZARD_TITLE,
         togglable  = False,
         sons       = sons,
-        start_step = 2,
+        start_step = start_step,
     )
 
     p << wizard.render(request) # in portal page if possible
index a97ec6d..f7f4456 100644 (file)
@@ -88,21 +88,50 @@ class Page:
         self.expose_js_manifold_config()
 
 
+# DEPRECATED #    # needs to be called explicitly and only when metadata is actually required
+# DEPRECATED #    # in particular user needs to be logged
+# DEPRECATED #    def get_metadata (self):
+# DEPRECATED #        # look in session's cache - we don't want to retrieve this for every request
+# DEPRECATED #        session=self.request.session
+# DEPRECATED #        if 'manifold' not in session:
+# DEPRECATED #            print "Page.expose_js_metadata: no 'manifold' in session... - cannot retrieve metadata - skipping"
+# DEPRECATED #            return
+# DEPRECATED #        manifold=session['manifold']
+# DEPRECATED #        # if cached, use it
+# DEPRECATED #        if 'metadata' in manifold and isinstance(manifold['metadata'],MetaData):
+# DEPRECATED #            if debug: print "Page.get_metadata: return cached value"
+# DEPRECATED #            return manifold['metadata']
+# DEPRECATED #        # otherwise retrieve it
+# DEPRECATED #        manifold_api_session_auth = session['manifold']['auth']
+# DEPRECATED #        print "get_metadata(), manifold_api_session_auth =", session['manifold']['auth']
+# DEPRECATED #        metadata=MetaData (manifold_api_session_auth)
+# DEPRECATED #        metadata.fetch()
+# DEPRECATED #        # store it for next time
+# DEPRECATED #        manifold['metadata']=metadata
+# DEPRECATED #        if debug: print "Page.get_metadata: return new value"
+# DEPRECATED #        return metadata
+
     # needs to be called explicitly and only when metadata is actually required
     # in particular user needs to be logged
     def get_metadata (self):
         # look in session's cache - we don't want to retrieve this for every request
         session=self.request.session
+
         if 'manifold' not in session:
-            print "Page.expose_js_metadata: no 'manifold' in session... - cannot retrieve metadata - skipping"
-            return
-        manifold=session['manifold']
+            session['manifold'] = {}
+        manifold = session['manifold']
+
         # if cached, use it
         if 'metadata' in manifold and isinstance(manifold['metadata'],MetaData):
             if debug: print "Page.get_metadata: return cached value"
             return manifold['metadata']
-        # otherwise retrieve it
-        manifold_api_session_auth = session['manifold']['auth']
+
+        #if 'auth' in session:
+        #manifold_api_session_auth = session['manifold']['auth']
+        #print "get_metadata(), manifold_api_session_auth =", session['manifold']['auth']
+        #else:
+        manifold_api_session_auth = {'AuthMethod': 'password', 'Username': 'demo', 'AuthString':'demo'}
+
         metadata=MetaData (manifold_api_session_auth)
         metadata.fetch()
         # store it for next time