]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-3825 move treemap from prototypejs to jquery
authorSimon Brandhof <simon.brandhof@gmail.com>
Tue, 4 Dec 2012 21:35:33 +0000 (22:35 +0100)
committerSimon Brandhof <simon.brandhof@gmail.com>
Tue, 4 Dec 2012 21:51:19 +0000 (22:51 +0100)
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/DefaultResourceTypes.java
sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceType.java
sonar-plugin-api/src/main/java/org/sonar/api/resources/ResourceTypes.java
sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypeTest.java
sonar-plugin-api/src/test/java/org/sonar/api/resources/ResourceTypesTest.java
sonar-server/src/main/webapp/WEB-INF/app/controllers/treemap_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/models/measure_filter_display_treemap.rb
sonar-server/src/main/webapp/WEB-INF/app/models/user.rb
sonar-server/src/main/webapp/WEB-INF/app/views/measures/_display_treemap.html.erb
sonar-server/src/main/webapp/javascripts/application.js
sonar-server/src/main/webapp/stylesheets/style.css

index 72bd2cb244ede8c3043e165a5d01c7f68da144ea..4cbe473af2847ed84cd8302f51b667cf5457d0e9 100644 (file)
@@ -38,28 +38,28 @@ public final class DefaultResourceTypes extends ExtensionProvider implements Bat
             .setProperty("modifiable_history", true)
             .setProperty("hasRolePolicy", true)
             .setProperty("updatable_key", true)
-            .setProperty("supports_measure_filters", true)
+            .setProperty("supportsMeasureFilters", true)
             .setProperty("comparable", true)
             .build())
         .addType(ResourceType.builder(Qualifiers.MODULE)
             .setProperty("updatable_key", true)
-            .setProperty("supports_measure_filters", true)
+            .setProperty("supportsMeasureFilters", true)
             .build())
         .addType(ResourceType.builder(Qualifiers.DIRECTORY)
-            .setProperty("supports_measure_filters", true)
+            .setProperty("supportsMeasureFilters", true)
             .build())
         .addType(ResourceType.builder(Qualifiers.PACKAGE)
             .build())
         .addType(ResourceType.builder(Qualifiers.FILE)
             .hasSourceCode()
-            .setProperty("supports_measure_filters", true)
+            .setProperty("supportsMeasureFilters", true)
             .build())
         .addType(ResourceType.builder(Qualifiers.CLASS)
             .hasSourceCode()
             .build())
         .addType(ResourceType.builder(Qualifiers.UNIT_TEST_FILE)
             .hasSourceCode()
-            .setProperty("supports_measure_filters", true)
+            .setProperty("supportsMeasureFilters", true)
             .build())
 
         .addRelations(Qualifiers.PROJECT, Qualifiers.MODULE)
index bda5124bff6d20401755fee6e5e8bbde5ff96271..93b6a0da86b6336abe218194295a0e32180a0612 100644 (file)
@@ -40,7 +40,7 @@ import java.util.Map;
  * </p>
  * <ul>
  * <li>"deletable": if set to "true", then this resource can be deleted/purged.</li>
- * <li>"supports_measure_filters": if set to "true", then this resource can be displayed in measure filters</li>
+ * <li>"supportsMeasureFilters": if set to "true", then this resource can be displayed in measure filters</li>
  * <li>"modifiable_history": if set to "true", then the history of this resource may be modified (deletion of snapshots, modification of events, ...)</li>
  * <li>"updatable_key" (since 3.2): if set to "true", then it is possible to update the key of this resource</li>
  * <li>"supportsGlobalDashboards" (since 3.2): if true, this resource can be displayed in global dashboards</li>
@@ -84,11 +84,11 @@ public final class ResourceType {
     }
 
     /**
-     * @deprecated since 3.0. Use {@link #setProperty(String, String)} with "supports_measure_filters" set to "true".
+     * @deprecated since 3.0. Use {@link #setProperty(String, String)} with "supportsMeasureFilters" set to "true".
      */
     @Deprecated
     public Builder availableForFilters() {
-      setProperty("supports_measure_filters", "true");
+      setProperty("supportsMeasureFilters", "true");
       return this;
     }
 
@@ -112,7 +112,7 @@ public final class ResourceType {
 
       // for backward-compatibility since version 3.4
       if (key.equals("availableForFilters")) {
-        properties.put("supports_measure_filters", value);
+        properties.put("supportsMeasureFilters", value);
       }
       return this;
     }
index f3494e963c2653a2fe162d37e065f41400ef1a0b..4834fa61848008d2858964ca7c9c6433cc09eaae 100644 (file)
@@ -45,7 +45,7 @@ public final class ResourceTypes implements BatchComponent, ServerComponent {
 
   public static final Predicate<ResourceType> AVAILABLE_FOR_FILTERS = new Predicate<ResourceType>() {
     public boolean apply(@Nullable ResourceType input) {
-      return input != null && input.getBooleanProperty("supports_measure_filters");
+      return input != null && input.getBooleanProperty("supportsMeasureFilters");
     }
   };
 
index 98e11c609d3eb30a297894f803ac47e07e4e98a5..9d38bdb852d9a3f41a4b7733f1d8011b56d01864 100644 (file)
@@ -40,13 +40,13 @@ public class ResourceTypeTest {
     ResourceType def = ResourceType.builder("qualifier")
       .setIconPath("/custom-icon.png")
       .hasSourceCode()
-      .setProperty("supports_measure_filters", "true")
+      .setProperty("supportsMeasureFilters", "true")
       .setProperty("anotherProperty", "foo")
       .build();
     assertThat(def.getQualifier()).isEqualTo("qualifier");
     assertThat(def.getIconPath()).isEqualTo("/custom-icon.png");
     assertThat(def.hasSourceCode()).isTrue();
-    assertThat(def.getBooleanProperty("supports_measure_filters")).isTrue();
+    assertThat(def.getBooleanProperty("supportsMeasureFilters")).isTrue();
     assertThat(def.getStringProperty("anotherProperty")).isEqualTo("foo");
   }
 
@@ -71,32 +71,32 @@ public class ResourceTypeTest {
   @Test
   public void testDeprecatedIsAvailableForFiltesCompatibility() {
     ResourceType def = ResourceType.builder("qualifier").build();
-    assertThat(def.getBooleanProperty("supports_measure_filters")).isFalse();
+    assertThat(def.getBooleanProperty("supportsMeasureFilters")).isFalse();
 
     def = ResourceType.builder("qualifier").availableForFilters().build();
-    assertThat(def.getBooleanProperty("supports_measure_filters")).isTrue();
+    assertThat(def.getBooleanProperty("supportsMeasureFilters")).isTrue();
   }
 
   @Test
   public void getBooleanProperty_is_set() {
     // set with boolean parameter
-    ResourceType def = ResourceType.builder("qualifier").setProperty("supports_measure_filters", true).build();
-    assertThat(def.getBooleanProperty("supports_measure_filters")).isTrue();
+    ResourceType def = ResourceType.builder("qualifier").setProperty("supportsMeasureFilters", true).build();
+    assertThat(def.getBooleanProperty("supportsMeasureFilters")).isTrue();
 
-    def = ResourceType.builder("qualifier").setProperty("supports_measure_filters", false).build();
-    assertThat(def.getBooleanProperty("supports_measure_filters")).isFalse();
+    def = ResourceType.builder("qualifier").setProperty("supportsMeasureFilters", false).build();
+    assertThat(def.getBooleanProperty("supportsMeasureFilters")).isFalse();
 
-    def = ResourceType.builder("qualifier").setProperty("supports_measure_filters", "true").build();
-    assertThat(def.getBooleanProperty("supports_measure_filters")).isTrue();
+    def = ResourceType.builder("qualifier").setProperty("supportsMeasureFilters", "true").build();
+    assertThat(def.getBooleanProperty("supportsMeasureFilters")).isTrue();
 
-    def = ResourceType.builder("qualifier").setProperty("supports_measure_filters", "false").build();
-    assertThat(def.getBooleanProperty("supports_measure_filters")).isFalse();
+    def = ResourceType.builder("qualifier").setProperty("supportsMeasureFilters", "false").build();
+    assertThat(def.getBooleanProperty("supportsMeasureFilters")).isFalse();
   }
 
   @Test
   public void getBooleanProperty_is_not_set() {
     ResourceType def = ResourceType.builder("qualifier").build();
-    assertThat(def.getBooleanProperty("supports_measure_filters")).isFalse();
+    assertThat(def.getBooleanProperty("supportsMeasureFilters")).isFalse();
   }
 
   @Test
index 1d73ddcc550fa23b98294e5be1c55f7fbe3b5389..673a60a70b3d909050748dda0eb8718718080c44 100644 (file)
@@ -30,14 +30,14 @@ import static org.fest.assertions.Assertions.assertThat;
 public class ResourceTypesTest {
 
   private ResourceTypeTree viewsTree = ResourceTypeTree.builder()
-    .addType(ResourceType.builder(Qualifiers.VIEW).setProperty("supports_measure_filters", "true").build())
+    .addType(ResourceType.builder(Qualifiers.VIEW).setProperty("supportsMeasureFilters", "true").build())
     .addType(ResourceType.builder(Qualifiers.SUBVIEW).build())
     .addRelations(Qualifiers.VIEW, Qualifiers.SUBVIEW)
     .addRelations(Qualifiers.SUBVIEW, Qualifiers.PROJECT)
     .build();
 
   private ResourceTypeTree defaultTree = ResourceTypeTree.builder()
-    .addType(ResourceType.builder(Qualifiers.PROJECT).setProperty("supports_measure_filters", "true").build())
+    .addType(ResourceType.builder(Qualifiers.PROJECT).setProperty("supportsMeasureFilters", "true").build())
     .addType(ResourceType.builder(Qualifiers.DIRECTORY).build())
     .addType(ResourceType.builder(Qualifiers.FILE).build())
     .addRelations(Qualifiers.PROJECT, Qualifiers.DIRECTORY)
@@ -67,14 +67,14 @@ public class ResourceTypesTest {
 
   @Test
   public void getAllWithPropertyKey() {
-    assertThat(qualifiers(types.getAllWithPropertyKey("supports_measure_filters"))).containsOnly(Qualifiers.VIEW, Qualifiers.PROJECT);
+    assertThat(qualifiers(types.getAllWithPropertyKey("supportsMeasureFilters"))).containsOnly(Qualifiers.VIEW, Qualifiers.PROJECT);
   }
 
   @Test
   public void getAllWithPropertyValue() {
-    assertThat(qualifiers(types.getAllWithPropertyValue("supports_measure_filters", "true"))).containsOnly(Qualifiers.VIEW, Qualifiers.PROJECT);
-    assertThat(qualifiers(types.getAllWithPropertyValue("supports_measure_filters", true))).containsOnly(Qualifiers.VIEW, Qualifiers.PROJECT);
-    assertThat(qualifiers(types.getAllWithPropertyValue("supports_measure_filters", false))).containsOnly(Qualifiers.SUBVIEW, Qualifiers.DIRECTORY, Qualifiers.FILE);
+    assertThat(qualifiers(types.getAllWithPropertyValue("supportsMeasureFilters", "true"))).containsOnly(Qualifiers.VIEW, Qualifiers.PROJECT);
+    assertThat(qualifiers(types.getAllWithPropertyValue("supportsMeasureFilters", true))).containsOnly(Qualifiers.VIEW, Qualifiers.PROJECT);
+    assertThat(qualifiers(types.getAllWithPropertyValue("supportsMeasureFilters", false))).containsOnly(Qualifiers.SUBVIEW, Qualifiers.DIRECTORY, Qualifiers.FILE);
   }
 
   @Test
index ea63d4387476ad3e69291f0f07c5b9f30835ee73..a2db5e892e80f755ce6a424a40010e365ebbacec 100644 (file)
 class TreemapController < ApplicationController
   helper :metrics
 
-  SECTION=Navigation::SECTION_HOME
-
   def index
-    html_id = params[:id]
-    bad_request('Missing required property: id') if html_id.blank?
-
-    height = params[:height]
-    bad_request('Missing required property: height') if height.blank?
-    bad_request('Bad height') if height.to_i<=0
-
-    size_metric=Metric.by_key(params[:size_metric]||'lines')
-    bad_request('Unknown metric: ' + params[:size_metric]) unless size_metric
-
-    color_metric=Metric.by_key(params[:color_metric])
-    bad_request('Unknown metric: ' + params[:color_metric]) unless color_metric
+    verify_ajax_request
+    require_parameters :html_id, :resource
 
-    if params[:resource]
-      resource = Project.by_key(params[:resource])
-      bad_request('Unknown resource: ' + params[:resource]) unless resource
-      bad_request('Data not available') unless resource.last_snapshot
-      access_denied unless has_role?(:user, resource)
-      resource = resource.permanent_resource
-
-    elsif params[:filter]
-      filter=::Filter.find(params[:filter])
-      bad_request('Unknown filter: ' + params[:filter]) unless filter
-      access_denied unless filter.authorized_to_execute?(self)
-      params[:metric_ids]=[size_metric.id, color_metric.id]
-      filter_context=Filters.execute(filter, self, params)
-    else
-      bad_request('Missing parameter: resource or filter')
+    if params[:size_metric].present?
+      size_metric=Metric.by_key(params[:size_metric])
+      bad_request('Unknown metric: ' + params[:size_metric]) unless size_metric
     end
 
-    treemap = Sonar::Treemap.new(html_id, size_metric, height.to_i, {
-      :color_metric => color_metric,
-      :root_snapshot => (resource ? resource.last_snapshot : nil),
-      :measures_by_snapshot => (filter_context ? filter_context.measures_by_snapshot : nil),
-      :period_index => params[:period_index].to_i
-    })
-
-    render :update do |page|
-      page.replace_html "tm-#{html_id}", :partial => 'treemap', :object => treemap
-      page.replace_html "tm-gradient-#{html_id}", :partial => 'gradient', :locals => {:metric => color_metric}
-      page.hide "tm-loading-#{html_id}"
+    if params[:color_metric].present?
+      color_metric=Metric.by_key(params[:color_metric])
+      bad_request('Unknown metric: ' + params[:color_metric]) unless color_metric
     end
+
+    resource = Project.by_key(params[:resource])
+    bad_request('Unknown resource: ' + params[:resource]) unless resource
+    bad_request('Data not available') unless resource.last_snapshot
+    access_denied unless has_role?(:user, resource)
+    resource = resource.permanent_resource
+
+    filter = MeasureFilter.new
+    filter.set_criteria_value('baseId', resource.id)
+    filter.set_criteria_value('onBaseComponents', 'true')
+    filter.set_criteria_value('display', 'treemap')
+    filter.set_criteria_value('tmSize', size_metric.key) if size_metric
+    filter.set_criteria_value('tmColor', color_metric.key) if color_metric
+    filter.execute(self, :user => current_user)
+
+    render :text => filter.display.html
   end
 
 end
index 961672facaac7371567f1a5ad6d0c00d6d3b6964..d672ed5dc19880d454c7a64d84e85929898109aa 100644 (file)
@@ -29,7 +29,6 @@ class MeasureFilterDisplayTreemap < MeasureFilterDisplay
 
     @size_metric = Metric.by_key(@filter.criteria('tmSize')||'ncloc')
     @color_metric = Metric.by_key(@filter.criteria('tmColor'))
-    @html_id = options[:html_id]
     @filter.metrics=([@size_metric, @color_metric].compact)
     @id_count = 0
 
@@ -51,8 +50,7 @@ class MeasureFilterDisplayTreemap < MeasureFilterDisplay
         o.full_html = false
         o.details_at_depth = 1
       end
-      html = output.to_html(root)
-      html + "<script>treemapById(#{@html_id}).onLoaded(#{@filter.results.size});</script>"
+      output.to_html(root)
     end
   end
 
@@ -69,8 +67,7 @@ class MeasureFilterDisplayTreemap < MeasureFilterDisplay
         if size_measure
           color_measure=(@color_metric ? result.measure(@color_metric) : nil)
           resource = result.snapshot.resource
-          child = Treemap::Node.new(:id => "#{@html_id}-#{@id_count += 1}",
-                                    :size => size_value(size_measure),
+          child = Treemap::Node.new(:size => size_value(size_measure),
                                     :label => resource.name(false),
                                     :title => escape_javascript(resource.name(true)),
                                     :tooltip => tooltip(resource, size_measure, color_measure),
@@ -117,12 +114,16 @@ class Sonar::HtmlOutput < Treemap::HtmlOutput
     html += "left:#{node.bounds.x1}%; top:#{node.bounds.y1}%;"
     html += "width:#{node.bounds.width}%;height: #{node.bounds.height}%;"
     html += "background-color:#FFF;\">"
-    html += "<div rid='#{node.rid}' id=\"tm-node-#{node.id}\" style='margin: 1px;background-color: #{node.color}; height: 100%;
-border: 1px solid #{node.color};' alt=\"#{node.tooltip}\" title=\"#{node.tooltip}\""
-    if node.leaf
-      html += "l=1 "
+    if node.rid
+      html += "<div rid='#{node.rid}' id=\"tm-node-#{node.id}\" style='margin: 1px;background-color: #{node.color}; height: 100%;
+  border: 1px solid #{node.color};' alt=\"#{node.tooltip}\" title=\"#{node.tooltip}\""
+      if node.leaf
+        html += "l=1 "
+      end
+      html += ' >'
+    else
+      html += '<div>'
     end
-    html += ' >'
     html += draw_node_body(node)
 
     if (!node.children.nil? && node.children.size > 0)
index c89ae10fef9082c16153581a08903b9c20093d00..ff6bcd6ebbcaa06d4ee2f0222274428a78878c43 100644 (file)
@@ -27,7 +27,6 @@ class User < ActiveRecord::Base
 
   has_many :user_roles, :dependent => :delete_all
   has_many :properties, :foreign_key => 'user_id', :dependent => :delete_all
-  has_many :filters, :dependent => :destroy
   has_many :active_dashboards, :dependent => :destroy, :order => 'order_index'
   has_many :dashboards, :dependent => :destroy
   has_many :measure_filters, :class_name => 'MeasureFilter', :dependent => :delete_all, :order => 'name asc'
@@ -99,7 +98,6 @@ class User < ActiveRecord::Base
     self.save(false)
     self.user_roles.clear
     self.properties.clear
-    self.filters.clear
     self.dashboards.clear
     self.active_dashboards.clear
     self.measure_filter_favourites.clear
index ea8981befafbc0412505d56115f5e1e664937204..561d68e3441772013732571d1ca6e1b9826daf28 100644 (file)
@@ -1,4 +1,8 @@
-<% if defined? widget %>
+<%
+  treemap_id = 1
+  if defined? widget
+    treemap_id = widget.id
+%>
   <span class="note"><%= message('size') -%>: <b><%= filter.display.size_metric.short_name -%></b></span>
   <% if filter.display.color_metric %>
     &nbsp;&nbsp;
@@ -17,7 +21,7 @@
       <td valign="top" class="thin nowrap">
         <span class="comments"><%= message('color') -%></span>
         <% if filter.display.color_metric %>
-        <span id="tm-gradient" class="note">
+        <span id="tm-gradient-<%= treemap_id -%>" class="note">
           <%= render :partial => 'treemap/gradient', :locals => {:metric => filter.display.color_metric} %>
         </span>
         <% end %>
@@ -29,7 +33,7 @@
 
         <button id="update-treemap">Update</button>
       </td>
-      <td></td>
+      <td valign="bottom"><%= image_tag 'loading.gif', :id => "tm-loading-#{treemap_id}", :style => 'display:none' -%></td>
     </tr>
   </table>
 <% end %>
 <% if filter.results.empty? %>
   <p><%= message('no_data') -%></p>
 <% else %>
-  <div class="treemap" style="width: 100%; height: 500px;">
+  <div id="tm-<%= treemap_id -%>" class="treemap width100">
     <%= filter.display.html -%>
   </div>
+
+  <div style="margin: 5px 0 0 0" class="notes">
+    <div style="float: right;cursor: help"><%= image_tag 'help.png', :title => h(message('treemap.click_help')) -%></div>
+    <div id="tm-bc-<%= treemap_id -%>">/</div>
+  </div>
+
+  <script>
+    new Treemap(<%= treemap_id -%>, '<%= filter.display.size_metric.key  -%>', '<%= filter.display.color_metric ? filter.display.color_metric.key : '' -%>');
+  </script>
+
 <% end %>
\ No newline at end of file
index eb635f67831bf6c7af058ecd562621ac3c090a9e..65d32fb7d034cb7c6f6d3df95d68ef2168564177 100644 (file)
@@ -15,33 +15,33 @@ function info(message) {
 function autocompleteResources() {
   $('searchInput').value = '';
   new Ajax.Autocompleter('searchInput', 'searchResourcesResults', baseUrl + '/search', {
-    method:'post',
-    minChars:3,
-    indicator:'searchingResources',
-    paramName:'s',
-    updateElement:function (item) {
+    method: 'post',
+    minChars: 3,
+    indicator: 'searchingResources',
+    paramName: 's',
+    updateElement: function (item) {
       if (item.id) {
         window.location = baseUrl + '/dashboard/index/' + item.id;
       }
     },
-    onShow:function (element, update) { /* no update */
+    onShow: function (element, update) { /* no update */
       update.show();
     }
   });
 }
 
 var SelectBox = {
-  cache:new Object(),
-  init:function (id) {
+  cache: new Object(),
+  init: function (id) {
     var box = document.getElementById(id);
     var node;
     SelectBox.cache[id] = new Array();
     var cache = SelectBox.cache[id];
     for (var i = 0; (node = box.options[i]); i++) {
-      cache.push({value:node.value, text:node.text, displayed:1});
+      cache.push({value: node.value, text: node.text, displayed: 1});
     }
   },
-  redisplay:function (id) {
+  redisplay: function (id) {
     // Repopulate HTML select box from cache
     var box = document.getElementById(id);
     box.options.length = 0; // clear all options
@@ -52,7 +52,7 @@ var SelectBox = {
       }
     }
   },
-  filter:function (id, text) {
+  filter: function (id, text) {
     // Redisplay the HTML select box, displaying only the choices containing ALL
     // the words in text. (It's an AND search.)
     var tokens = text.toLowerCase().split(/\s+/);
@@ -67,7 +67,7 @@ var SelectBox = {
     }
     SelectBox.redisplay(id);
   },
-  delete_from_cache:function (id, value) {
+  delete_from_cache: function (id, value) {
     var node, delete_index = null;
     for (var i = 0; (node = SelectBox.cache[id][i]); i++) {
       if (node.value == value) {
@@ -81,10 +81,10 @@ var SelectBox = {
     }
     SelectBox.cache[id].length--;
   },
-  add_to_cache:function (id, option) {
-    SelectBox.cache[id].push({value:option.value, text:option.text, displayed:1});
+  add_to_cache: function (id, option) {
+    SelectBox.cache[id].push({value: option.value, text: option.text, displayed: 1});
   },
-  cache_contains:function (id, value) {
+  cache_contains: function (id, value) {
     // Check if an item is contained in the cache
     var node;
     for (var i = 0; (node = SelectBox.cache[id][i]); i++) {
@@ -94,31 +94,31 @@ var SelectBox = {
     }
     return false;
   },
-  move:function (from, to) {
+  move: function (from, to) {
     var from_box = document.getElementById(from);
     var option;
     for (var i = 0; (option = from_box.options[i]); i++) {
       if (option.selected && SelectBox.cache_contains(from, option.value)) {
-        SelectBox.add_to_cache(to, {value:option.value, text:option.text, displayed:1});
+        SelectBox.add_to_cache(to, {value: option.value, text: option.text, displayed: 1});
         SelectBox.delete_from_cache(from, option.value);
       }
     }
     SelectBox.redisplay(from);
     SelectBox.redisplay(to);
   },
-  move_all:function (from, to) {
+  move_all: function (from, to) {
     var from_box = document.getElementById(from);
     var option;
     for (var i = 0; (option = from_box.options[i]); i++) {
       if (SelectBox.cache_contains(from, option.value)) {
-        SelectBox.add_to_cache(to, {value:option.value, text:option.text, displayed:1});
+        SelectBox.add_to_cache(to, {value: option.value, text: option.text, displayed: 1});
         SelectBox.delete_from_cache(from, option.value);
       }
     }
     SelectBox.redisplay(from);
     SelectBox.redisplay(to);
   },
-  sort:function (id) {
+  sort: function (id) {
     SelectBox.cache[id].sort(function (a, b) {
       a = a.text.toLowerCase();
       b = b.text.toLowerCase();
@@ -132,7 +132,7 @@ var SelectBox = {
       return 0;
     });
   },
-  select_all:function (id) {
+  select_all: function (id) {
     var box = document.getElementById(id);
     for (var i = 0; i < box.options.length; i++) {
       box.options[i].selected = 'selected';
@@ -146,9 +146,8 @@ var treemaps = {};
 function treemapById(id) {
   return treemaps[id];
 }
-var TreemapContext = function (type, id, label) {
-  this.type = type;
-  this.id = id;
+var TreemapContext = function (rid, label) {
+  this.rid = rid;
   this.label = label;
 };
 
@@ -158,25 +157,15 @@ var TreemapContext = function (type, id, label) {
  * tm-bc-#{id} : required breadcrumb
  * tm-loading-#{id} : optional loading icon
  */
-var Treemap = function (id, sizeMetric, colorMetric, heightInPercents) {
+var Treemap = function (id, sizeMetric, colorMetric) {
   this.id = id;
   this.sizeMetric = sizeMetric;
   this.colorMetric = colorMetric;
-  this.heightInPercents = heightInPercents;
   this.breadcrumb = [];
   treemaps[id] = this;
-};
-Treemap.prototype.initResource = function (resourceId) {
-  this.breadcrumb.push(new TreemapContext('resource', resourceId, ''));
-  return this;
-};
-Treemap.prototype.initFilter = function (filterId) {
-  this.breadcrumb.push(new TreemapContext('filter', filterId, ''));
-  return this;
-};
-Treemap.prototype.init = function (type, id) {
-  this.breadcrumb.push(new TreemapContext(type, id, ''));
-  return this;
+  this.rootNode().height(this.rootNode().width() * 0.6);
+  this.initNodes();
+
 };
 Treemap.prototype.changeSizeMetric = function (metric) {
   this.sizeMetric = metric;
@@ -194,74 +183,69 @@ Treemap.prototype.currentContext = function () {
   }
   return null;
 };
-Treemap.prototype.width = function () {
-  return $('tm-' + this.id).getWidth();
-};
 Treemap.prototype.load = function () {
   var context = this.currentContext();
-  var width = this.width();
-  var height = Math.round(width * Math.abs(this.heightInPercents / 100.0));
-
   var output = '';
   this.breadcrumb.each(function (ctx) {
     output += ctx.label + '&nbsp;/&nbsp;';
   });
-  if ($('tm-bc-' + this.id) != null) {
-    $('tm-bc-' + this.id).innerHTML = output;
-  }
-  var loadingIcon = $('tm-loading-' + this.id);
-  if (loadingIcon != null) {
-    loadingIcon.show();
-  }
-
-  new Ajax.Request(
-      baseUrl + '/treemap/index?id=' + this.id + '&height=' + height + '&size_metric=' + this.sizeMetric + '&color_metric=' + this.colorMetric + '&' + context.type + '=' + context.id,
-      {
-        asynchronous:true,
-        evalScripts:true
-      });
+  $j('#tm-bc-' + this.id).html(output);
+  $j('#tm-loading-' + this.id).show();
+  var self = this;
+  $j.ajax({
+    type: "GET",
+    url: baseUrl + '/treemap/index?html_id=' + this.id + '&size_metric=' + this.sizeMetric + '&color_metric=' + this.colorMetric + '&resource=' + context.rid,
+    dataType: "html",
+    success: function (data) {
+      self.rootNode().html(data);
+      self.initNodes();
+      $j("#tm-loading-" + self.id).hide();
+    }
+  });
 };
-Treemap.prototype.htmlNode = function (nodeId) {
-  return $('tm-node-' + this.id + '-' + nodeId);
+Treemap.prototype.rootNode = function () {
+  return $j('#tm-' + this.id);
 };
-Treemap.prototype.handleClick = function (event) {
-  if (Event.isLeftClick(event)) {
-    var link = event.findElement('a');
-    if (link != null) {
-      event.stopPropagation();
-      return false;
-    }
 
-    var elt = event.findElement('div');
-    var rid = elt.readAttribute('rid');
-    var leaf = elt.hasAttribute('l');
-    if (!leaf) {
-      var label = elt.innerText || elt.textContent;
-      var context = new TreemapContext('resource', rid, label);
-      this.breadcrumb.push(context);
-      this.load();
-    }
-
-  } else if (Event.isRightClick(event)) {
-    if (this.breadcrumb.length > 1) {
-      this.breadcrumb.pop();
-      this.load();
-    }
-  }
-};
-Treemap.prototype.onLoaded = function (componentsSize) {
-  for (var i = 1; i <= componentsSize; i++) {
-    var elt = this.htmlNode(i);
-    elt.oncontextmenu = function () {
-      return false
-    };
-    elt.observe('mouseup', this.handleClick.bind(this));
-  }
+Treemap.prototype.initNodes = function () {
+  var self = this;
+  $j('#tm-' + this.id).find('a').each(function (index) {
+    this.on("mouseup", function (event) {
+      event.stopPropagation()
+    });
+  });
+  $j('#tm-' + this.id).find('[rid]').each(function (index) {
+        this.on("mouseup", function (event) {
+              if (event.which == 1) {
+                var source = $j(this);
+                var rid = source.attr('rid');
+                var has_leaves = !!(source.attr('l'));
+                if (!has_leaves) {
+                  var context = new TreemapContext(rid, source.text());
+                  self.breadcrumb.push(context);
+                  self.load();
+                }
+              }
+            }
+        );
+        this.on("contextmenu", function (event) {
+          event.preventDefault();
+          // right click
+          if (self.breadcrumb.length > 1) {
+            self.breadcrumb.pop();
+            self.load();
+          } else {
+            location.reload();
+          }
+          return false;
+        });
+      }
+  );
 };
 
 (function ($j) {
   $j.fn.extend({
-    modal:function () {
+    modal: function () {
       return this.each(function () {
         var obj = $j(this);
         var $link = obj.bind('click', function () {
@@ -275,13 +259,13 @@ Treemap.prototype.onLoaded = function (componentsSize) {
             $dialog.html(html);
             $dialog
                 .dialog({
-                  width:($link.attr('modal-width') || 540),
-                  draggable:false,
-                  autoOpen:false,
-                  modal:true,
-                  minHeight:50,
-                  resizable:false,
-                  close:function () {
+                  width: ($link.attr('modal-width') || 540),
+                  draggable: false,
+                  autoOpen: false,
+                  modal: true,
+                  minHeight: 50,
+                  resizable: false,
+                  close: function () {
                     $j('#modal').remove();
                   }
                 });
@@ -301,19 +285,19 @@ Treemap.prototype.onLoaded = function (componentsSize) {
         });
       });
     },
-    modalForm:function (ajax_options) {
+    modalForm: function (ajax_options) {
       return this.each(function () {
         var obj = $j(this);
         obj.submit(function (event) {
           $j('input[type=submit]', this).attr('disabled', 'disabled');
           $j.ajax($j.extend({
-            type:'POST',
-            url:obj.attr('action'),
-            data:obj.serialize(),
-            success:function (data) {
+            type: 'POST',
+            url: obj.attr('action'),
+            data: obj.serialize(),
+            success: function (data) {
               window.location.reload();
             },
-            error:function (xhr, textStatus, errorThrown) {
+            error: function (xhr, textStatus, errorThrown) {
               $j("#modal").html(xhr.responseText);
             }
           }, ajax_options));
index 4c8a61c9b4bc9ec06b779024b588db3ab7ad7fd6..903bec852fc5af4bd7e2d1677ff0c1a46ab1f083 100644 (file)
@@ -271,10 +271,13 @@ h4, .h4 {
 
 .treemap a {
   color: #FFF;
-  text-decoration: underline;
+  text-decoration: none;
   font-size: 12px;
   padding: 1px;
 }
+.treemap a:hover {
+  text-decoration: underline;
+}
 
 /* ------------------- MESSAGES ------------------- */
 .warning {