[Ovirt-devel] [PATCH] first cut of autorefresh tree nav

Hugh O. Brock hbrock at redhat.com
Fri Jun 6 04:07:38 UTC 2008


On Thu, Jun 05, 2008 at 06:12:22PM -0400, Jason Guiditta wrote:
> Disclaimer: this still has work to be done, namely:
> 	1.  Keep 'current' highlighted.
> 	2.  Reload an appropriate content pane if the selected node disappears
> 
> Also, I had no merge conflicts, but I do not have rrd set up, so the
> latest patch seems to make my machine throw a 500 error whenever I try
> to go to any node.  I am hoping this is just my lack of rrd, not
> something funky in the merge that I didn't see.
> 
> -j

> >From 7a369c440134cadf8e855f100ce918e4b48a4856 Mon Sep 17 00:00:00 2001
> >From: Jason Guiditta <jguiditt at redhat.com>
> Date: Thu, 5 Jun 2008 18:05:55 -0400
> Subject: [PATCH] New version of the nav tree with first cut of autorefresh (currently every 20 seconds, probably will make this more often)
> 
> 
> Signed-off-by: Jason Guiditta <jguiditt at redhat.com>
> ---
>  wui/src/app/controllers/tree_controller.rb         |   10 ++
>  wui/src/app/helpers/tree_helper.rb                 |   19 +++
>  wui/src/app/views/hardware/move.rhtml              |    2 +-
>  wui/src/app/views/layouts/_tree.rhtml              |   17 +++-
>  wui/src/app/views/layouts/redux.rhtml              |    2 +-
>  wui/src/app/views/tree/fetch_nav.rhtml             |   19 +++
>  .../jquery-treeview/jquery.treeview.async.js       |   19 +--
>  .../public/javascripts/jquery.ovirt.treeview.js    |   89 ++++++++++++
>  wui/src/public/javascripts/jquery.timers.js        |  142 ++++++++++++++++++++
>  wui/src/test/functional/tree_controller_test.rb    |    8 +
>  10 files changed, 312 insertions(+), 15 deletions(-)
>  create mode 100644 wui/src/app/controllers/tree_controller.rb
>  create mode 100644 wui/src/app/helpers/tree_helper.rb
>  create mode 100644 wui/src/app/views/tree/fetch_nav.rhtml
>  create mode 100644 wui/src/public/javascripts/jquery.ovirt.treeview.js
>  create mode 100644 wui/src/public/javascripts/jquery.timers.js
>  create mode 100644 wui/src/test/functional/tree_controller_test.rb
> 
> diff --git a/wui/src/app/controllers/tree_controller.rb b/wui/src/app/controllers/tree_controller.rb
> new file mode 100644
> index 0000000..c7dbe35
> --- /dev/null
> +++ b/wui/src/app/controllers/tree_controller.rb
> @@ -0,0 +1,10 @@
> +class TreeController < ApplicationController
> +  
> +  def fetch_nav
> +    @pools = Pool.root.full_set_nested(:method => :json_hash_element)
> +  end
> +  
> +  def fetch_json
> +    render :json => Pool.root.full_set_nested(:method => :json_hash_element).to_json
> +  end
> +end
> diff --git a/wui/src/app/helpers/tree_helper.rb b/wui/src/app/helpers/tree_helper.rb
> new file mode 100644
> index 0000000..e026e48
> --- /dev/null
> +++ b/wui/src/app/helpers/tree_helper.rb
> @@ -0,0 +1,19 @@
> +module TreeHelper
> +  def tree_html(treenode)
> +    if treenode[:children]
> +      children = %{
> +       <ul>
> +         #{treenode[:children].collect {|child| "<li>#{tree_html(child)}</li>"}.join("\n")}
> +       </ul>
> +      }
> +    else
> +      children = ""
> +    end
> +    %{ 
> +     <div id="tree#{treenode[:id]}">
> +       #{treenode[:obj][:type]} #{treenode[:obj].name}
> +       #{children}
> +     </div>
> +     }
> +  end
> +end
> diff --git a/wui/src/app/views/hardware/move.rhtml b/wui/src/app/views/hardware/move.rhtml
> index e146d6e..4126e3b 100644
> --- a/wui/src/app/views/hardware/move.rhtml
> +++ b/wui/src/app/views/hardware/move.rhtml
> @@ -7,7 +7,7 @@
>  
>  <script type="text/javascript">
>        $(document).ready(function(){         
> -        $("#move_tree").treeview({
> +        $("#move_tree").asynch_treeview({
>              //animated: "normal",
>              current_pool_id:  <%=@current_pool_id%>,
>              url: "<%=  url_for :controller =>'/hardware', :action => 'json_move_tree' %>",
> diff --git a/wui/src/app/views/layouts/_tree.rhtml b/wui/src/app/views/layouts/_tree.rhtml
> index 07d80f4..13f11a4 100644
> --- a/wui/src/app/views/layouts/_tree.rhtml
> +++ b/wui/src/app/views/layouts/_tree.rhtml
> @@ -4,4 +4,19 @@
>      <%= link_to "Dashboard", { :controller => "dashboard" }, { :id => "dashboard", :class => "#{selected}" } %>
>  </div>
>  <div style="clear:both"></div>
> -<ul id="tree" class="filetree treeview-famfamfam treeview"></ul>
> +<%= javascript_include_tag "jquery.ovirt.treeview.js" -%>
> +<script type="text/javascript">    
> +    $(document).ready(function(){         
> +        $("#test-tree").ovirt_treeview({
> +            collapsed: true,
> +            //animated: "normal",
> +            url: "<%=  url_for :controller =>'/tree', :action => 'fetch_json' %>",
> +            hardware_url: "<%=  url_for :controller =>'/hardware', :action => 'show' %>",
> +            resource_url: "<%=  url_for :controller =>'/resources', :action => 'show' %>"
> +	});
> +    });
> +</script>
> +
> +<ul id="test-tree" class="filetree treeview-famfamfam treeview">
> +</ul>
> +<!--<ul id="tree" class="filetree treeview-famfamfam treeview"></ul>-->
> diff --git a/wui/src/app/views/layouts/redux.rhtml b/wui/src/app/views/layouts/redux.rhtml
> index 9589b56..52a4363 100644
> --- a/wui/src/app/views/layouts/redux.rhtml
> +++ b/wui/src/app/views/layouts/redux.rhtml
> @@ -21,6 +21,7 @@
>    <%= javascript_include_tag "jquery-treeview/jquery.treeview.async.js" -%>
>    <%= javascript_include_tag "flexigrid.js" -%>
>    <%= javascript_include_tag "facebox.js" -%>
> +  <%= javascript_include_tag "jquery.timers.js" -%>
>    <%= javascript_include_tag "jquery-svg/jquery.svg.pack.js" -%>
>    <!--%= javascript_include_tag "jquery-svg/jquery.svgfilter.js" -%-->
>    <%= javascript_include_tag "jquery-svg/jquery.svggraph.js" -%>
> @@ -84,7 +85,6 @@
>                          error: function(xhr) {alert(xhr.status + ' ' + xhr.statusText);}
>                      });
>                      return false;})},function(){});
> -            
>  	});
>  
>    function delete_vm_pool(id, parent)
> diff --git a/wui/src/app/views/tree/fetch_nav.rhtml b/wui/src/app/views/tree/fetch_nav.rhtml
> new file mode 100644
> index 0000000..95a0395
> --- /dev/null
> +++ b/wui/src/app/views/tree/fetch_nav.rhtml
> @@ -0,0 +1,19 @@
> +<%= javascript_include_tag "jquery.ovirt.treeview.js" -%>
> +<script type="text/javascript">    
> +    $(document).ready(function(){         
> +        $("#test-tree").ovirt_treeview({
> +            collapsed: true,
> +            animated: "normal",
> +            url: "<%=  url_for :controller =>'/tree', :action => 'fetch_json' %>",
> +            hardware_url: "<%=  url_for :controller =>'/hardware', :action => 'show' %>",
> +            resource_url: "<%=  url_for :controller =>'/resources', :action => 'show' %>"
> +	});
> +        //$("#test-tree").treeview({
> +        //    prerendered: true
> +        //});
> +    });
> +</script>
> +
> +<ul id="test-tree" class="filetree treeview-famfamfam treeview">
> +</ul>
> +
> diff --git a/wui/src/public/javascripts/jquery-treeview/jquery.treeview.async.js b/wui/src/public/javascripts/jquery-treeview/jquery.treeview.async.js
> index 7d5eb2f..b10a130 100644
> --- a/wui/src/public/javascripts/jquery-treeview/jquery.treeview.async.js
> +++ b/wui/src/public/javascripts/jquery-treeview/jquery.treeview.async.js
> @@ -15,8 +15,8 @@
>  
>  ;(function($) {
>  
> -function load(settings, params, child, container) {
> -        $.getJSON(settings.url, params, function(response) { //{id: root}
> +function load(settings, params, child, container) {    
> +        $.getJSON(settings.url, params, function(response) { //{id: root}            
>  		function createNode(parent) {                  
>                          if (this.type=="HardwarePool") {
>                              settings.link_to=settings.hardware_url 
> @@ -63,11 +63,6 @@ function load(settings, params, child, container) {
>  //                                },
>  //                                error: function(xhr) {alert(xhr.status + ' ' + xhr.statusText);}
>  //                              })
> -                              //var new_id = $(this).parent().parent().get(0).id;
> -                              //var current_e = $('span[class^=current_]');
> -                              //current_e.removeClass(current_e.attr('class'));
> -                              //$(this).addClass('current_folder');
> -                              //var my_container = $(container);
>  //                              return false;
>  //                            });
>  
> @@ -92,20 +87,20 @@ function load(settings, params, child, container) {
>  					$.each(this.children, createNode, [branch])
>  				}
>  			}
> -		}                
> -		$.each(response, createNode, [child]);
> -        $(container).treeview({add: child});
> +		} 
> +                $.each(response, createNode, [child]);
> +                $(container).treeview({add: child});
>      });
>  }
>  
>  var proxied = $.fn.treeview;
> -$.fn.treeview = function(settings) {
> +$.fn.asynch_treeview = function(settings) {
>  	if (!settings.url) {
>  		return proxied.apply(this, arguments);
>  	}
>  	var container = this;
>          settings.current_pool_id!=""?settings.params={current_id:settings.current_pool_id}:settings.params=null;
> -	load(settings, settings.params, this, container);
> +	load(settings, settings.params, this, container);        
>  	var userToggle = settings.toggle;
>  	return proxied.call(this, $.extend({}, settings, {
>  		collapsed: true,
> diff --git a/wui/src/public/javascripts/jquery.ovirt.treeview.js b/wui/src/public/javascripts/jquery.ovirt.treeview.js
> new file mode 100644
> index 0000000..2fe0f1b
> --- /dev/null
> +++ b/wui/src/public/javascripts/jquery.ovirt.treeview.js
> @@ -0,0 +1,89 @@
> +;(function($) {
> +  var proxied = $.fn.treeview;
> +  $.fn.ovirt_treeview = function(settings) {
> +    var container = this;    
> +    settings.current_pool_id!=""?settings.params={current_id:settings.current_pool_id}:settings.params=null;
> +    load(settings, settings.params, this, container); 
> +    $(this).everyTime(20000,function(){
> +      load(settings, settings.params, this, container);
> +    })
> +    
> +    return proxied.call(this, $.extend({}, settings, {
> +            toggle: function() {}
> +    }));
> +  }
> +  function load(settings, params, child, container) {    
> +        $.getJSON(settings.url, params, function(response) { //{id: root}            
> +		function createNode(parent) {                     
> +                        if (this.type=="HardwarePool") {
> +                            settings.link_to=settings.hardware_url 
> +                            settings.span_class="folder";
> +                            settings.current_class = settings.current + "_folder";
> +                        } else {
> +                            settings.link_to=settings.resource_url;
> +                            settings.span_class="file";
> +                            settings.current_class = settings.current + "_file";
> +                        }   
> +			var span_onclick;
> +			var current = $("<li/>").attr("id", this.id || "");
> +			var link_open = "<a href=\"" + settings.link_to + "/" + this.id + "\">";
> +			var link_close =  "</a>";
> +			if (settings.action_type=="javascript"){
> +			    span_onclick = " onClick=\"" + settings.onclick + "(" + this.id + ")\" ";
> +   		        } else {
> +			    span_onclick = ""
> +		        }
> +                        if (settings.current_pool_id==this.id) {
> +                          current.html("<span class=\"" + settings.current_class + ">" + this.text  + "</span>")
> +                            .appendTo(parent);
> +                        } else {
> +                          current.html("<span class=\"" + settings.span_class + "\"" + span_onclick + ">" + link_open + this.text + link_close + "</span>")
> +                            .appendTo(parent);
> +                        }
> +			if (this.classes) {
> +				current.children("span").addClass(this.classes);
> +			}
> +			if (this.expanded) {
> +				current.addClass("open");
> +			}                        
> +			if (this.hasChildren || this.children && this.children.length) {
> +				var branch = $("<ul/>").appendTo(current);
> +				if (this.hasChildren) {
> +					current.addClass("hasChildren");
> +					//createNode.call({
> +						//classes:"placeholder",
> +                                        //        text:" ",
> +					//	children:[]
> +					//}, branch);
> +				}
> +				if (this.children && this.children.length) {
> +					$.each(this.children, createNode, [branch])
> +				}
> +			}
> +		} 
> +                $(container).find('li').remove();
> +                createNode.call(response, child);                
> +                $(container).ovirt_treeview({add: child});
> +                for (var i = 0; i < selectedNodes.length; i++){
> +                  $('#test-tree li#' + selectedNodes[i] +' > div').click();
> +                }
> +               
> +    });
> +  }      
> +})(jQuery);
> +
> +var selectedNodes = [];
> +$('#test-tree li.collapsable').livequery(
> +    function(){
> +        if($.inArray(this.id,selectedNodes) == -1){
> +          selectedNodes.push(this.id);
> +        }        
> +    },function(){}
> +); 
> +$('#test-tree li.expandable').livequery(
> +    function(){
> +        if($.inArray(this.id,selectedNodes) != -1){
> +          selectedNodes.splice(selectedNodes.indexOf(this.id),1);
> +        }        
> +    }, function(){}
> +); 
> \ No newline at end of file
> diff --git a/wui/src/public/javascripts/jquery.timers.js b/wui/src/public/javascripts/jquery.timers.js
> new file mode 100644
> index 0000000..406de7e
> --- /dev/null
> +++ b/wui/src/public/javascripts/jquery.timers.js
> @@ -0,0 +1,142 @@
> +jQuery.fn.extend({
> +	everyTime: function(interval, label, fn, times, belay) {
> +		return this.each(function() {
> +			jQuery.timer.add(this, interval, label, fn, times, belay);
> +		});
> +	},
> +	oneTime: function(interval, label, fn) {
> +		return this.each(function() {
> +			jQuery.timer.add(this, interval, label, fn, 1);
> +		});
> +	},
> +	stopTime: function(label, fn) {
> +		return this.each(function() {
> +			jQuery.timer.remove(this, label, fn);
> +		});
> +	}
> +});
> +
> +jQuery.extend({
> +	timer: {
> +		guid: 1,
> +		global: {},
> +		regex: /^([0-9]+)\s*(.*s)?$/,
> +		powers: {
> +			// Yeah this is major overkill...
> +			'ms': 1,
> +			'cs': 10,
> +			'ds': 100,
> +			's': 1000,
> +			'das': 10000,
> +			'hs': 100000,
> +			'ks': 1000000
> +		},
> +		timeParse: function(value) {
> +			if (value == undefined || value == null)
> +				return null;
> +			var result = this.regex.exec(jQuery.trim(value.toString()));
> +			if (result[2]) {
> +				var num = parseInt(result[1], 10);
> +				var mult = this.powers[result[2]] || 1;
> +				return num * mult;
> +			} else {
> +				return value;
> +			}
> +		},
> +		add: function(element, interval, label, fn, times, belay) {
> +			var counter = 0;
> +			
> +			if (jQuery.isFunction(label)) {
> +				if (!times) 
> +					times = fn;
> +				fn = label;
> +				label = interval;
> +			}
> +			
> +			interval = jQuery.timer.timeParse(interval);
> +
> +			if (typeof interval != 'number' || isNaN(interval) || interval <= 0)
> +				return;
> +
> +			if (times && times.constructor != Number) {
> +				belay = !!times;
> +				times = 0;
> +			}
> +			
> +			times = times || 0;
> +			belay = belay || false;
> +			
> +			if (!element.$timers) 
> +				element.$timers = {};
> +			
> +			if (!element.$timers[label])
> +				element.$timers[label] = {};
> +			
> +			fn.$timerID = fn.$timerID || this.guid++;
> +			
> +			var handler = function() {
> +				if (belay && this.inProgress) 
> +					return;
> +				this.inProgress = true;
> +				if ((++counter > times && times !== 0) || fn.call(element, counter) === false)
> +					jQuery.timer.remove(element, label, fn);
> +				this.inProgress = false;
> +			};
> +			
> +			handler.$timerID = fn.$timerID;
> +			
> +			if (!element.$timers[label][fn.$timerID]) 
> +				element.$timers[label][fn.$timerID] = window.setInterval(handler,interval);
> +			
> +			if ( !this.global[label] )
> +				this.global[label] = [];
> +			this.global[label].push( element );
> +			
> +		},
> +		remove: function(element, label, fn) {
> +			var timers = element.$timers, ret;
> +			
> +			if ( timers ) {
> +				
> +				if (!label) {
> +					for ( label in timers )
> +						this.remove(element, label, fn);
> +				} else if ( timers[label] ) {
> +					if ( fn ) {
> +						if ( fn.$timerID ) {
> +							window.clearInterval(timers[label][fn.$timerID]);
> +							delete timers[label][fn.$timerID];
> +						}
> +					} else {
> +						for ( var fn in timers[label] ) {
> +							window.clearInterval(timers[label][fn]);
> +							delete timers[label][fn];
> +						}
> +					}
> +					
> +					for ( ret in timers[label] ) break;
> +					if ( !ret ) {
> +						ret = null;
> +						delete timers[label];
> +					}
> +				}
> +				
> +				for ( ret in timers ) break;
> +				if ( !ret ) 
> +					element.$timers = null;
> +			}
> +		}
> +	}
> +});
> +
> +if (jQuery.browser.msie)
> +	jQuery(window).one("unload", function() {
> +		var global = jQuery.timer.global;
> +		for ( var label in global ) {
> +			var els = global[label], i = els.length;
> +			while ( --i )
> +				jQuery.timer.remove(els[i], label);
> +		}
> +	});
> +
> +
> diff --git a/wui/src/test/functional/tree_controller_test.rb b/wui/src/test/functional/tree_controller_test.rb
> new file mode 100644
> index 0000000..decb0a8
> --- /dev/null
> +++ b/wui/src/test/functional/tree_controller_test.rb
> @@ -0,0 +1,8 @@
> +require File.dirname(__FILE__) + '/../test_helper'
> +
> +class TreeControllerTest < ActionController::TestCase
> +  # Replace this with your real tests.
> +  def test_truth
> +    assert true
> +  end
> +end
> -- 
> 1.5.4.1
> 

ACK... applied and pushed.

--Hugh




More information about the ovirt-devel mailing list