From: Thierry Parmentelat <thierry.parmentelat@inria.fr>
Date: Fri, 29 Nov 2013 08:46:33 +0000 (+0100)
Subject: the tabs plugin has a persistent_active feature to enable saving the active tab in... 
X-Git-Tag: myslice-0.3-0~103^2
X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=f19bceaa080ab47bae751cd0597a9fb32d1b6b4f;p=myslice.git

the tabs plugin has a persistent_active feature to enable saving the active tab in html5 storage
---

diff --git a/plugins/tabs/__init__.py b/plugins/tabs/__init__.py
index d1b9bda3..4bab62d9 100644
--- a/plugins/tabs/__init__.py
+++ b/plugins/tabs/__init__.py
@@ -1,7 +1,24 @@
 from unfold.composite import Composite
 
+# although the persistent_active feature originally targetted any kind of 
+# composite widget, the current implementation clearly 
+# works only with Tabs, as the javascript function for enabling a given tab
+# cannot just set the 'active' class on some DOM element, but is required
+# by bootstrap to call the tab() javascript method
+
 class Tabs (Composite):
     
+    """A composite plugin for arranging sons as selectable tabs
+    
+persistent_active: if set to True, enables preserving 
+the domid for the active tab, so that a given page
+will re-open with the same active tab
+"""
+
+    def __init__ (self, persistent_active=False, *args, **kwds):
+        Composite.__init__ (self, *args, **kwds)
+        self.persistent_active=persistent_active
+        
     def requirements (self):
         return { 'js_files'     : ['js/tabs.js', 'js/bootstrap.js'],
                  'css_files'    : ['css/bootstrap.css', 'css/tabs.css', ] 
@@ -10,6 +27,11 @@ class Tabs (Composite):
     def template_file (self):
         return "tabs.html"
 
+    def template_env (self, request):
+        inherited=Composite.template_env(self,request)
+        inherited.update({'persistent_active':self.persistent_active})
+        return inherited
+
     # see Composite.py for the details of template_env, that exposes global
     # 'sons' as a list of sons with each a set of a few attributes
     def json_settings_list (self):
diff --git a/plugins/tabs/static/js/tabs.js b/plugins/tabs/static/js/tabs.js
index 75ce452a..bfd568a9 100644
--- a/plugins/tabs/static/js/tabs.js
+++ b/plugins/tabs/static/js/tabs.js
@@ -1,3 +1,71 @@
+// storing tabs active component in localStorage
+//
+// based on plugin_helper.js, extended to store the domid of an active tab
+//
+
+var tabs_helper = {
+
+    debug:false,
+
+    ////////// use local storage to remember the active son
+    // xxx this is a bit fragile in that we assume the elements that need to have the 'active' class
+    // are direct sons of the .persistent-active elements
+    // it would be simple to overcome this weakness by requiring the template to set
+    // .persistent-active-item on these elements active-able instead 
+    store_active_domid : function (domid,active_domid) {
+	var key='active.'+domid;
+	if (tabs_helper.debug) messages.debug("storing for domid " + domid + " (key=" + key + ") active_domid=" + active_domid);
+	$.localStorage.setItem(key,active_domid);
+    },
+    // restore last status
+    retrieve_last_active_domid : function (domid) {
+	var key='active.'+domid;
+	// don't do anything if nothing stored
+	var retrieved=$.localStorage.getItem(key);
+	// set default to undefined
+	if (retrieved==null) retrieved=undefined;
+	if (tabs_helper.debug) messages.debug ("retrieved active status for " + domid + " (key=" + key + ") -> " + retrieved);
+	return retrieved;
+    },
+    // tabs_helper.set_active_domid("tabs-resources","tab-resources-list")
+    set_active_domid : function (domid,active_domid) {
+	if ( ! active_domid ) return;
+	if (tabs_helper.debug) messages.debug ("setting active for " + domid + " to active_domid=" + active_domid);
+	// build something like "#uldomid a[href='#active_domid']"
+	var selector="#"+domid+" a[href='#"+active_domid+"']";
+	console.log("selector="+selector);
+	$(selector).tab('show');
+    },
+    set_from_saved_active_domid : function (domid) {
+	var active_domid=tabs_helper.retrieve_last_active_domid (domid);
+	if (tabs_helper.debug) messages.debug("restoring active domid for domid " + domid + " -> " + active_domid);
+	tabs_helper.set_active_domid (domid,active_domid);
+    },
+
+    init_all_tabs : function () {
+	////////// active
+	$('.persistent-active').each(function() {
+	    var domid=this.id;
+	    tabs_helper.set_from_saved_active_domid(domid);
+	});
+	// on all the children of the persistent-active element
+	$('.persistent-active>*').on('shown.bs.tab', function (e) {
+	    var active_domid=e.target;
+	    // at this point we have something like 
+	    // http://localhost:8080/portal/slice/ple.inria.f14#tab-resources-list
+	    active_domid=active_domid.hash.replace("#","");
+	    // find out the domid, which is for the nearest ancestor with class
+	    // persistent-active
+	    var domid=$(e.target).closest(".persistent-active").attr('id');
+	    tabs_helper.store_active_domid(domid,active_domid);
+	    console.log("CLICKED domid="+domid+" active_domid="+active_domid);
+	});
+    },
+
+} // global var tabs_helper
+
+$(document).ready(tabs_helper.init_all_tabs);
+
 (function($){
     $.fn.Tabs = function( method ) {
         // In Bootstrap 3, we need 'shown.bs.tab' instead of 'shown'
diff --git a/plugins/tabs/templates/tabs.html b/plugins/tabs/templates/tabs.html
index 298dec92..60031f63 100644
--- a/plugins/tabs/templates/tabs.html
+++ b/plugins/tabs/templates/tabs.html
@@ -1,4 +1,4 @@
-<ul class="nav nav-tabs" id='tabs-{{ domid }}'>
+<ul class="nav nav-tabs{%if persistent_active%} persistent-active{%endif%}" id='tabs-{{ domid }}'>
 {% for son in sons %}
 <li{% if son.is_active %} class='active'{% endif %}> <a href="#tab-{{ son.domid }}" data-toggle="tab">{{ son.title }}</a> </li>
 {% endfor %}
diff --git a/portal/sliceview.py b/portal/sliceview.py
index 35ab8102..753fed26 100644
--- a/portal/sliceview.py
+++ b/portal/sliceview.py
@@ -199,6 +199,7 @@ class SliceView (LoginRequiredAutoLogoutView):
                                        resources_as_3dmap,
                                        resources_as_list_area, ],
                                 active_domid = 'resources-map',
+                                persistent_active=True,
                                 )
         main_stack.insert (resources_area)
 
diff --git a/unfold/composite.py b/unfold/composite.py
index 16e28f30..f3d42fc4 100644
--- a/unfold/composite.py
+++ b/unfold/composite.py
@@ -1,13 +1,14 @@
 from unfold.plugin import Plugin
 
-# this is a simple base class for plugins that contain/arrange a set of other plugins
-# sons is expected to be a list of the contained plugins, and 
-# active_domid is the domid for the one son that should be displayed as active
-# some subclasses of Composite, like e.g. Tabs, will not behave as expected 
-# if a valid active_domid is not provided
-
 class Composite (Plugin):
 
+    """a simple base class for plugins that contain/arrange a set of other plugins
+sons is expected to be a list of the contained plugins, and 
+active_domid is the domid for the one son that should be displayed as active
+some subclasses of Composite, like e.g. Tabs, will not behave as expected 
+if a valid active_domid is not provided
+"""
+
     def __init__ (self, sons=None, active_domid=None, *args, **kwds):
         Plugin.__init__ (self, *args, **kwds)
         self.sons= sons if sons else []
diff --git a/unfold/static/js/plugin_helper.js b/unfold/static/js/plugin_helper.js
index d15e7a71..7f81a3c3 100644
--- a/unfold/static/js/plugin_helper.js
+++ b/unfold/static/js/plugin_helper.js
@@ -1,18 +1,19 @@
 //
 // storing toggle's status in localStorage
 // NOTE that localStorage only stores strings, so true becomes "true"
+//
 var plugin_helper = {
 
     debug:false,
 
     ////////// use local storage to remember open/closed toggles
-    store_status : function (domid,status) {
+    store_toggle_status : function (domid,status) {
 	var key='toggle.'+domid;
 	if (plugin_helper.debug) messages.debug("storing toggle status " + status + " for " + domid + " key=" + key);
 	$.localStorage.setItem(key,status);
     },
     // restore last status
-    retrieve_last_status : function (domid) {
+    retrieve_last_toggle_status : function (domid) {
 	var key='toggle.'+domid;
 	// don't do anything if nothing stored
 	var retrieved=$.localStorage.getItem(key);
@@ -27,20 +28,22 @@ var plugin_helper = {
 	var hidebtn=$('#hide-'+domid);
 	if (status=="true")	{ plugindiv.slideDown(); hidebtn.show(); showbtn.hide(); }
 	else			{ plugindiv.slideUp();   hidebtn.hide(); showbtn.show(); }
-	plugin_helper.store_status(domid,status);
+	plugin_helper.store_toggle_status(domid,status);
     },
-    set_from_saved_status : function (domid) {
-	var previous_status=plugin_helper.retrieve_last_status (domid);
+    set_from_saved_toggle_status : function (domid) {
+	var previous_status=plugin_helper.retrieve_last_toggle_status (domid);
 	if (plugin_helper.debug) messages.debug("restoring initial status for domid " + domid + " -> " + previous_status);
 	plugin_helper.set_toggle_status (domid,previous_status);
     },
+
+
     // triggered upon $(document).ready
     init_all_plugins : function() {
 	// plugins marked as persistent start with all 3 parts turned off
 	// let us first make sure the right parts are turned on 
 	$('.persistent-toggle').each(function() {
 	    var domid=this.id.replace('complete-','');
-	    plugin_helper.set_from_saved_status(domid);
+	    plugin_helper.set_from_saved_toggle_status(domid);
 	});
 	// program the hide buttons so they do the right thing
 	$('.plugin-hide').each(function() {
@@ -57,7 +60,7 @@ var plugin_helper = {
 	// arm tooltips
 	$('.plugin-tooltip').each(function(){ $(this).tooltip({'selector':'','placement':'right'}); });
     },
-} // global var plugin
+} // global var plugin_helper
 
 /* upon document completion, we locate all the hide and show areas, 
  * and configure their behaviour