Commit a9cce9358ae2c264bad1fc61c6e1d20b9e3a23c7

Authored by Valeriy Sizov
2 parents 325569ac 332fc328

Merge pull request #1627 from tsigo/tree_performance

Tree performance improvements
app/assets/javascripts/tree.js
@@ -1,30 +0,0 @@ @@ -1,30 +0,0 @@
1 -/**  
2 - * Tree slider for code browse  
3 - *  
4 - */  
5 -var Tree = {  
6 - init:  
7 - function() {  
8 - $('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live("click", function() {  
9 - $("#tree-content-holder").hide("slide", { direction: "left" }, 150)  
10 - })  
11 -  
12 - $('.project-refs-form').live({  
13 - "ajax:beforeSend": function() {  
14 - $("#tree-content-holder").hide("slide", { direction: "left" }, 150);  
15 - }  
16 - })  
17 -  
18 - $("#tree-slider .tree-item").live('click', function(e){  
19 - if(e.target.nodeName != "A") {  
20 - link = $(this).find(".tree-item-file-name a");  
21 - link.trigger("click");  
22 - }  
23 - });  
24 -  
25 - $('#tree-slider .tree-item-file-name a, .breadcrumb a, .project-refs-form').live({  
26 - "ajax:beforeSend": function() { $('.tree_progress').addClass("loading"); },  
27 - "ajax:complete": function() { $('.tree_progress').removeClass("loading"); }  
28 - });  
29 - }  
30 -}  
app/assets/javascripts/tree.js.coffee 0 → 100644
@@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
  1 +# Code browser tree slider
  2 +
  3 +$ ->
  4 + if $('#tree-slider').length > 0
  5 + # Show the "Loading commit data" for only the first element
  6 + $('span.log_loading:first').removeClass('hide')
  7 +
  8 + $('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live "click", ->
  9 + $("#tree-content-holder").hide("slide", { direction: "left" }, 150)
  10 +
  11 + $('.project-refs-form').live
  12 + "ajax:beforeSend": -> $("#tree-content-holder").hide("slide", { direction: "left" }, 150)
  13 +
  14 + # Make the entire tree-item row clickable, but not if clicking another link (like a commit message)
  15 + $("#tree-slider .tree-item").live 'click', (e) ->
  16 + $('.tree-item-file-name a', this).trigger('click') if (e.target.nodeName != "A")
  17 +
  18 + # Show/Hide the loading spinner
  19 + $('#tree-slider .tree-item-file-name a, .breadcrumb a, .project-refs-form').live
  20 + "ajax:beforeSend": -> $('.tree_progress').addClass("loading")
  21 + "ajax:complete": -> $('.tree_progress').removeClass("loading")
app/decorators/tree_decorator.rb
@@ -8,14 +8,14 @@ class TreeDecorator < ApplicationDecorator @@ -8,14 +8,14 @@ class TreeDecorator < ApplicationDecorator
8 8
9 #parts = parts[0...-1] if is_blob? 9 #parts = parts[0...-1] if is_blob?
10 10
11 - yield(h.link_to("..", "#", remote: :true)) if parts.count > max_links 11 + yield(h.link_to("..", "#", remote: true)) if parts.count > max_links
12 12
13 parts.each do |part| 13 parts.each do |part|
14 part_path = File.join(part_path, part) unless part_path.empty? 14 part_path = File.join(part_path, part) unless part_path.empty?
15 part_path = part if part_path.empty? 15 part_path = part if part_path.empty?
16 16
17 next unless parts.last(2).include?(part) if parts.count > max_links 17 next unless parts.last(2).include?(part) if parts.count > max_links
18 - yield(h.link_to(h.truncate(part, length: 40), h.project_tree_path(project, h.tree_join(ref, part_path)), remote: :true)) 18 + yield(h.link_to(h.truncate(part, length: 40), h.project_tree_path(project, h.tree_join(ref, part_path)), remote: true))
19 end 19 end
20 end 20 end
21 end 21 end
app/helpers/tree_helper.rb
1 module TreeHelper 1 module TreeHelper
2 - def tree_icon(content)  
3 - if content.is_a?(Grit::Blob)  
4 - if content.text?  
5 - image_tag "file_txt.png"  
6 - elsif content.image?  
7 - image_tag "file_img.png" 2 + # Sorts a repository's tree so that folders are before files and renders
  3 + # their corresponding partials
  4 + #
  5 + # contents - A Grit::Tree object for the current tree
  6 + def render_tree(contents)
  7 + # Render Folders before Files/Submodules
  8 + folders, files = contents.partition { |v| v.kind_of?(Grit::Tree) }
  9 +
  10 + tree = ""
  11 +
  12 + # Render folders if we have any
  13 + tree += render partial: 'tree/tree_item', collection: folders, locals: {type: 'folder'} if folders.present?
  14 +
  15 + files.each do |f|
  16 + if f.respond_to?(:url)
  17 + # Object is a Submodule
  18 + tree += render partial: 'tree/submodule_item', object: f
8 else 19 else
9 - image_tag "file_bin.png" 20 + # Object is a Blob
  21 + tree += render partial: 'tree/tree_item', object: f, locals: {type: 'file'}
10 end 22 end
11 - else  
12 - image_tag "file_dir.png"  
13 end 23 end
  24 +
  25 + tree.html_safe
14 end 26 end
15 27
16 - def tree_hex_class(content)  
17 - "file_#{hexdigest(content.name)}" 28 + # Return an image icon depending on the file type
  29 + #
  30 + # type - String type of the tree item; either 'folder' or 'file'
  31 + def tree_icon(type)
  32 + image = type == 'folder' ? 'file_dir.png' : 'file_txt.png'
  33 + image_tag(image, size: '16x16')
18 end 34 end
19 35
20 - def tree_full_path(content)  
21 - content.name.force_encoding('utf-8')  
22 - if params[:path]  
23 - File.join(params[:path], content.name)  
24 - else  
25 - content.name  
26 - end 36 + def tree_hex_class(content)
  37 + "file_#{hexdigest(content.name)}"
27 end 38 end
28 39
29 # Public: Determines if a given filename is compatible with GitHub::Markup. 40 # Public: Determines if a given filename is compatible with GitHub::Markup.
app/views/tree/_submodule_item.html.haml
1 -- url = content.url(@ref) rescue nil  
2 -- name = content.basename 1 +- url = submodule_item.url(@ref) rescue nil
  2 +- name = submodule_item.basename
3 - return unless url 3 - return unless url
4 %tr{ class: "tree-item", url: url } 4 %tr{ class: "tree-item", url: url }
5 %td.tree-item-file-name 5 %td.tree-item-file-name
6 = image_tag "submodule.png" 6 = image_tag "submodule.png"
7 %strong= truncate(name, length: 40) 7 %strong= truncate(name, length: 40)
8 %td 8 %td
9 - %code= content.id[0..10] 9 + %code= submodule_item.id[0..10]
10 %td 10 %td
11 = link_to truncate(url, length: 40), url 11 = link_to truncate(url, length: 40), url
12 -  
13 -  
app/views/tree/_tree.html.haml
@@ -6,13 +6,14 @@ @@ -6,13 +6,14 @@
6 - tree.breadcrumbs(6) do |link| 6 - tree.breadcrumbs(6) do |link|
7 \/ 7 \/
8 %li= link 8 %li= link
  9 +
9 .clear 10 .clear
10 %div.tree_progress 11 %div.tree_progress
  12 +
11 %div#tree-content-holder.tree-content-holder 13 %div#tree-content-holder.tree-content-holder
12 - if tree.is_blob? 14 - if tree.is_blob?
13 - = render partial: "tree/tree_file", locals: { name: tree.name, content: tree.data, file: tree } 15 + = render partial: "tree/tree_file", object: tree
14 - else 16 - else
15 - - contents = tree.contents  
16 %table#tree-slider{class: "table_#{@hex_path} tree-table" } 17 %table#tree-slider{class: "table_#{@hex_path} tree-table" }
17 %thead 18 %thead
18 %th Name 19 %th Name
@@ -22,22 +23,16 @@ @@ -22,22 +23,16 @@
22 = link_to "History", tree.history_path, class: "right" 23 = link_to "History", tree.history_path, class: "right"
23 24
24 - if tree.up_dir? 25 - if tree.up_dir?
25 - %tr{ class: "tree-item", url: tree.up_dir_path } 26 + %tr.tree-item
26 %td.tree-item-file-name 27 %td.tree-item-file-name
27 - = image_tag "file_empty.png"  
28 - = link_to "..", tree.up_dir_path, remote: :true 28 + = image_tag "file_empty.png", size: '16x16'
  29 + = link_to "..", tree.up_dir_path, remote: true
29 %td 30 %td
30 %td 31 %td
31 32
32 - - index = 0  
33 - - contents.select{ |i| i.is_a?(Grit::Tree)}.each do |content|  
34 - = render partial: "tree/tree_item", locals: { content: content, index: (index += 1) }  
35 - - contents.select{ |i| i.is_a?(Grit::Blob)}.each do |content|  
36 - = render partial: "tree/tree_item", locals: { content: content, index: (index += 1) }  
37 - - contents.select{ |i| i.is_a?(Grit::Submodule)}.each do |content|  
38 - = render partial: "tree/submodule_item", locals: { content: content, index: (index += 1) } 33 + = render_tree(tree.contents)
39 34
40 - - if content = contents.select{ |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i }.first 35 + - if content = tree.contents.find { |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i }
41 .file_holder#README 36 .file_holder#README
42 .file_title 37 .file_title
43 %i.icon-file 38 %i.icon-file
app/views/tree/_tree_file.html.haml
@@ -2,32 +2,32 @@ @@ -2,32 +2,32 @@
2 .file_title 2 .file_title
3 %i.icon-file 3 %i.icon-file
4 %span.file_name 4 %span.file_name
5 - = name.force_encoding('utf-8')  
6 - %small #{file.mode} 5 + = tree_file.name.force_encoding('utf-8')
  6 + %small #{tree_file.mode}
7 %span.options 7 %span.options
8 = link_to "raw", project_blob_path(@project, @id), class: "btn very_small", target: "_blank" 8 = link_to "raw", project_blob_path(@project, @id), class: "btn very_small", target: "_blank"
9 = link_to "history", project_commits_path(@project, @id), class: "btn very_small" 9 = link_to "history", project_commits_path(@project, @id), class: "btn very_small"
10 = link_to "blame", project_blame_path(@project, @id), class: "btn very_small" 10 = link_to "blame", project_blame_path(@project, @id), class: "btn very_small"
11 - - if file.text?  
12 - - if gitlab_markdown?(name) 11 + - if tree_file.text?
  12 + - if gitlab_markdown?(tree_file.name)
13 .file_content.wiki 13 .file_content.wiki
14 = preserve do 14 = preserve do
15 - = markdown(file.data)  
16 - - elsif markup?(name) 15 + = markdown(tree_file.data)
  16 + - elsif markup?(tree_file.name)
17 .file_content.wiki 17 .file_content.wiki
18 - = raw GitHub::Markup.render(name, file.data) 18 + = raw GitHub::Markup.render(tree_file.name, tree_file.data)
19 - else 19 - else
20 .file_content.code 20 .file_content.code
21 - - unless file.empty? 21 + - unless tree_file.empty?
22 %div{class: current_user.dark_scheme ? "black" : "white"} 22 %div{class: current_user.dark_scheme ? "black" : "white"}
23 = preserve do 23 = preserve do
24 - = raw file.colorize(options: { linenos: 'True'}) 24 + = raw tree_file.colorize(options: { linenos: 'True'})
25 - else 25 - else
26 %h4.nothing_here_message Empty file 26 %h4.nothing_here_message Empty file
27 27
28 - - elsif file.image? 28 + - elsif tree_file.image?
29 .file_content.image_file 29 .file_content.image_file
30 - %img{ src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} 30 + %img{ src: "data:#{tree_file.mime_type};base64,#{Base64.encode64(tree_file.data)}"}
31 31
32 - else 32 - else
33 .file_content.blob_file 33 .file_content.blob_file
@@ -37,4 +37,4 @@ @@ -37,4 +37,4 @@
37 %br 37 %br
38 = image_tag "download.png", width: 64 38 = image_tag "download.png", width: 64
39 %h3 39 %h3
40 - Download (#{file.mb_size}) 40 + Download (#{tree_file.mb_size})
app/views/tree/_tree_item.html.haml
1 -- file = tree_full_path(content)  
2 -%tr{ class: "tree-item #{tree_hex_class(content)}", url: project_tree_path(@project, tree_join(@id, file)) } 1 +%tr{ class: "tree-item #{tree_hex_class(tree_item)}" }
3 %td.tree-item-file-name 2 %td.tree-item-file-name
4 - = tree_icon(content)  
5 - %strong= link_to truncate(content.name, length: 40), project_tree_path(@project, tree_join(@id || @commit.id, file)), remote: :true 3 + = tree_icon(type)
  4 + %strong= link_to truncate(tree_item.name, length: 40), project_tree_path(@project, tree_join(@id || @commit.id, tree_item.name)), remote: true
6 %td.tree_time_ago.cgray 5 %td.tree_time_ago.cgray
7 - - if index == 1  
8 - %span.log_loading  
9 - Loading commit data..  
10 - = image_tag "ajax_loader_tree.gif", width: 14 6 + %span.log_loading.hide
  7 + Loading commit data...
  8 + = image_tag "ajax_loader_tree.gif", width: 14
11 %td.tree_commit 9 %td.tree_commit
app/views/tree/show.html.haml
1 = render "head" 1 = render "head"
2 %div#tree-holder.tree-holder 2 %div#tree-holder.tree-holder
3 - = render "tree", commit: @commit, tree: @tree  
4 -  
5 -:javascript  
6 - $(function() {  
7 - Tree.init();  
8 - }); 3 + = render "tree", tree: @tree
app/views/tree/show.js.haml
1 :plain 1 :plain
2 // Load Files list 2 // Load Files list
3 - $("#tree-holder").html("#{escape_javascript(render(partial: "tree", locals: {commit: @commit, tree: @tree}))}"); 3 + $("#tree-holder").html("#{escape_javascript(render(partial: "tree", locals: {tree: @tree}))}");
4 $("#tree-content-holder").show("slide", { direction: "right" }, 150); 4 $("#tree-content-holder").show("slide", { direction: "right" }, 150);
5 $('.project-refs-form #path').val("#{@path}"); 5 $('.project-refs-form #path').val("#{@path}");
6 6