[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