Jason Guiditta
2008-Jun-05 22:12 UTC
[Ovirt-devel] [PATCH] first cut of autorefresh tree nav
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 -------------- next part -------------- A non-text attachment was scrubbed... Name: autorefresh.patch Type: text/x-patch Size: 16412 bytes Desc: not available URL: <http://listman.redhat.com/archives/ovirt-devel/attachments/20080605/94550b7e/attachment.bin>
Hugh O. Brock
2008-Jun-06 04:07 UTC
[Ovirt-devel] [PATCH] first cut of autorefresh tree nav
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