Feature: ajax load for tree commit log
This commit is contained in:
parent
b8425cf173
commit
1a2bacfb4b
9 changed files with 206 additions and 20 deletions
|
@ -12,6 +12,7 @@
|
||||||
//= require jquery.cookie
|
//= require jquery.cookie
|
||||||
//= require jquery.endless-scroll
|
//= require jquery.endless-scroll
|
||||||
//= require jquery.highlight
|
//= require jquery.highlight
|
||||||
|
//= require jquery.waitforimages
|
||||||
//= require bootstrap-modal
|
//= require bootstrap-modal
|
||||||
//= require modernizr
|
//= require modernizr
|
||||||
//= require chosen-jquery
|
//= require chosen-jquery
|
||||||
|
|
|
@ -9,7 +9,7 @@ class RefsController < ApplicationController
|
||||||
before_filter :require_non_empty_project
|
before_filter :require_non_empty_project
|
||||||
|
|
||||||
before_filter :ref
|
before_filter :ref
|
||||||
before_filter :define_tree_vars, :only => [:tree, :blob, :blame]
|
before_filter :define_tree_vars, :only => [:tree, :blob, :blame, :logs_tree]
|
||||||
before_filter :render_full_content
|
before_filter :render_full_content
|
||||||
|
|
||||||
layout "project"
|
layout "project"
|
||||||
|
@ -46,6 +46,18 @@ class RefsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def logs_tree
|
||||||
|
contents = @tree.contents
|
||||||
|
@logs = contents.map do |content|
|
||||||
|
file = params[:path] ? File.join(params[:path], content.name) : content.name
|
||||||
|
last_commit = @project.commits(@commit.id, file, 1).last
|
||||||
|
{
|
||||||
|
:file_name => content.name,
|
||||||
|
:commit => last_commit
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def blob
|
def blob
|
||||||
if @tree.is_blob?
|
if @tree.is_blob?
|
||||||
if @tree.text?
|
if @tree.text?
|
||||||
|
@ -79,6 +91,15 @@ class RefsController < ApplicationController
|
||||||
@commit = project.commit(@ref)
|
@commit = project.commit(@ref)
|
||||||
@tree = Tree.new(@commit.tree, project, @ref, params[:path])
|
@tree = Tree.new(@commit.tree, project, @ref, params[:path])
|
||||||
@tree = TreeDecorator.new(@tree)
|
@tree = TreeDecorator.new(@tree)
|
||||||
|
@hex_path = Digest::SHA1.hexdigest(params[:path] || "/")
|
||||||
|
|
||||||
|
if params[:path]
|
||||||
|
@history_path = tree_file_project_ref_path(@project, @ref, params[:path])
|
||||||
|
@logs_path = logs_file_project_ref_path(@project, @ref, params[:path])
|
||||||
|
else
|
||||||
|
@history_path = tree_project_ref_path(@project, @ref)
|
||||||
|
@logs_path = logs_tree_project_ref_path(@project, @ref)
|
||||||
|
end
|
||||||
rescue
|
rescue
|
||||||
return render_404
|
return render_404
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
= render :partial => "refs/tree_file", :locals => { :name => tree.name, :content => tree.data, :file => tree }
|
= render :partial => "refs/tree_file", :locals => { :name => tree.name, :content => tree.data, :file => tree }
|
||||||
- else
|
- else
|
||||||
- contents = tree.contents
|
- contents = tree.contents
|
||||||
%table#tree-slider.bordered-table.table
|
%table#tree-slider.bordered-table.table{:class => "table_#{@hex_path}" }
|
||||||
%thead
|
%thead
|
||||||
%th Name
|
%th Name
|
||||||
%th Last Update
|
%th Last Update
|
||||||
|
@ -48,17 +48,18 @@
|
||||||
- else
|
- else
|
||||||
= simple_format(content.data)
|
= simple_format(content.data)
|
||||||
|
|
||||||
- if params[:path]
|
|
||||||
- history_path = tree_file_project_ref_path(@project, @ref, params[:path])
|
|
||||||
- else
|
|
||||||
- history_path = tree_project_ref_path(@project, @ref)
|
|
||||||
:javascript
|
:javascript
|
||||||
$(function(){
|
$(function(){
|
||||||
$('select#branch').selectmenu({style:'popup', width:200});
|
$('select#branch').selectmenu({style:'popup', width:200});
|
||||||
$('select#tag').selectmenu({style:'popup', width:200});
|
$('select#tag').selectmenu({style:'popup', width:200});
|
||||||
$('.project-refs-select').chosen();
|
$('.project-refs-select').chosen();
|
||||||
|
|
||||||
history.pushState({ path: this.path }, '', "#{history_path}")
|
history.pushState({ path: this.path }, '', "#{@history_path}");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$(window).load(function(){
|
||||||
|
$.ajax({type: "GET", url: '#{@logs_path}', dataType: "script"});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
3
app/views/refs/_tree_commit.html.haml
Normal file
3
app/views/refs/_tree_commit.html.haml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
- if tm
|
||||||
|
%strong= link_to "[#{tm.user_name}]", project_team_member_path(@project, tm)
|
||||||
|
= link_to truncate(content_commit.safe_message, :length => tm ? 30 : 50), project_commit_path(@project, content_commit.id), :class => "tree-commit-link"
|
|
@ -1,23 +1,15 @@
|
||||||
- file = params[:path] ? File.join(params[:path], content.name) : content.name
|
- file = params[:path] ? File.join(params[:path], content.name) : content.name
|
||||||
- content_commit = @project.commits(@commit.id, file, 1).last
|
%tr{ :class => "tree-item file_#{Digest::SHA1.hexdigest(content.name)}", :url => tree_file_project_ref_path(@project, @ref, file) }
|
||||||
- return unless content_commit
|
|
||||||
%tr{ :class => "tree-item", :url => tree_file_project_ref_path(@project, @ref, file) }
|
|
||||||
%td.tree-item-file-name
|
%td.tree-item-file-name
|
||||||
- if content.is_a?(Grit::Blob)
|
- if content.is_a?(Grit::Blob)
|
||||||
- if content.text?
|
- if content.text?
|
||||||
= image_tag "file_txt.png"
|
= image_tag "file_txt.png", :class => "tree-ico"
|
||||||
- elsif content.image?
|
- elsif content.image?
|
||||||
= image_tag "file_img.png"
|
= image_tag "file_img.png", :class => "tree-ico"
|
||||||
- else
|
- else
|
||||||
= image_tag "file_bin.png"
|
= image_tag "file_bin.png", :class => "tree-ico"
|
||||||
- else
|
- else
|
||||||
= image_tag "file_dir.png"
|
= image_tag "file_dir.png", :class => "tree-ico"
|
||||||
= link_to truncate(content.name, :length => 40), tree_file_project_ref_path(@project, @ref || @commit.id, file), :remote => :true
|
= link_to truncate(content.name, :length => 40), tree_file_project_ref_path(@project, @ref || @commit.id, file), :remote => :true
|
||||||
%td.tree_time_ago.cgray
|
%td.tree_time_ago.cgray
|
||||||
= time_ago_in_words(content_commit.committed_date)
|
|
||||||
ago
|
|
||||||
%td.tree_commit
|
%td.tree_commit
|
||||||
- tm = @project.team_member_by_name_or_email(content_commit.author_email, content_commit.author_name)
|
|
||||||
- if tm
|
|
||||||
%strong= link_to "[#{tm.user_name}]", project_team_member_path(@project, tm)
|
|
||||||
= link_to truncate(content_commit.safe_message, :length => tm ? 30 : 50), project_commit_path(@project, content_commit.id), :class => "tree-commit-link"
|
|
||||||
|
|
9
app/views/refs/logs_tree.js.haml
Normal file
9
app/views/refs/logs_tree.js.haml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
- @logs.each do |content_data|
|
||||||
|
- file_name = content_data[:file_name]
|
||||||
|
- content_commit = content_data[:commit]
|
||||||
|
- tm = @project.team_member_by_name_or_email(content_commit.author_email, content_commit.author_name)
|
||||||
|
|
||||||
|
:plain
|
||||||
|
var row = $("table.table_#{@hex_path} tr.file_#{Digest::SHA1.hexdigest(file_name)}");
|
||||||
|
row.find("td.tree_time_ago").html('#{escape_javascript(time_ago_in_words(content_commit.committed_date))} ago');
|
||||||
|
row.find("td.tree_commit").html('#{escape_javascript(render("tree_commit", :tm => tm, :content_commit => content_commit))}');
|
|
@ -2,3 +2,8 @@
|
||||||
$("#tree-holder").html("#{escape_javascript(render(:partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree}))}");
|
$("#tree-holder").html("#{escape_javascript(render(:partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree}))}");
|
||||||
$("#tree-content-holder").show("slide", { direction: "right" }, 150);
|
$("#tree-content-holder").show("slide", { direction: "right" }, 150);
|
||||||
$('.project-refs-form #path').val("#{params[:path]}");
|
$('.project-refs-form #path').val("#{params[:path]}");
|
||||||
|
|
||||||
|
|
||||||
|
$('#tree-slider').waitForImages(function() {
|
||||||
|
$.ajax({type: "GET", url: '#{@logs_path}', dataType: "script"});
|
||||||
|
});
|
||||||
|
|
|
@ -117,6 +117,8 @@ Gitlab::Application.routes.draw do
|
||||||
|
|
||||||
member do
|
member do
|
||||||
get "tree", :constraints => { :id => /[a-zA-Z.\/0-9_\-]+/ }
|
get "tree", :constraints => { :id => /[a-zA-Z.\/0-9_\-]+/ }
|
||||||
|
get "logs_tree", :constraints => { :id => /[a-zA-Z.\/0-9_\-]+/ }
|
||||||
|
|
||||||
get "blob",
|
get "blob",
|
||||||
:constraints => {
|
:constraints => {
|
||||||
:id => /[a-zA-Z.0-9\/_\-]+/,
|
:id => /[a-zA-Z.0-9\/_\-]+/,
|
||||||
|
@ -132,6 +134,14 @@ Gitlab::Application.routes.draw do
|
||||||
:path => /.*/
|
:path => /.*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# tree viewer
|
||||||
|
get "logs_tree/:path" => "refs#logs_tree",
|
||||||
|
:as => :logs_file,
|
||||||
|
:constraints => {
|
||||||
|
:id => /[a-zA-Z.0-9\/_\-]+/,
|
||||||
|
:path => /.*/
|
||||||
|
}
|
||||||
|
|
||||||
# blame
|
# blame
|
||||||
get "blame/:path" => "refs#blame",
|
get "blame/:path" => "refs#blame",
|
||||||
:as => :blame_file,
|
:as => :blame_file,
|
||||||
|
|
144
vendor/assets/javascripts/jquery.waitforimages.js
vendored
Normal file
144
vendor/assets/javascripts/jquery.waitforimages.js
vendored
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
/*
|
||||||
|
* waitForImages 1.4
|
||||||
|
* -----------------
|
||||||
|
* Provides a callback when all images have loaded in your given selector.
|
||||||
|
* http://www.alexanderdickson.com/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011 Alex Dickson
|
||||||
|
* Licensed under the MIT licenses.
|
||||||
|
* See website for more info.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
;(function($) {
|
||||||
|
// Namespace all events.
|
||||||
|
var eventNamespace = 'waitForImages';
|
||||||
|
|
||||||
|
// CSS properties which contain references to images.
|
||||||
|
$.waitForImages = {
|
||||||
|
hasImageProperties: [
|
||||||
|
'backgroundImage',
|
||||||
|
'listStyleImage',
|
||||||
|
'borderImage',
|
||||||
|
'borderCornerImage'
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Custom selector to find `img` elements that have a valid `src` attribute and have not already loaded.
|
||||||
|
$.expr[':'].uncached = function(obj) {
|
||||||
|
// Ensure we are dealing with an `img` element with a valid `src` attribute.
|
||||||
|
if ( ! $(obj).is('img[src!=""]')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Firefox's `complete` property will always be`true` even if the image has not been downloaded.
|
||||||
|
// Doing it this way works in Firefox.
|
||||||
|
var img = document.createElement('img');
|
||||||
|
img.src = obj.src;
|
||||||
|
return ! img.complete;
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.waitForImages = function(finishedCallback, eachCallback, waitForAll) {
|
||||||
|
|
||||||
|
// Handle options object.
|
||||||
|
if ($.isPlainObject(arguments[0])) {
|
||||||
|
eachCallback = finishedCallback.each;
|
||||||
|
waitForAll = finishedCallback.waitForAll;
|
||||||
|
finishedCallback = finishedCallback.finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle missing callbacks.
|
||||||
|
finishedCallback = finishedCallback || $.noop;
|
||||||
|
eachCallback = eachCallback || $.noop;
|
||||||
|
|
||||||
|
// Convert waitForAll to Boolean
|
||||||
|
waitForAll = !! waitForAll;
|
||||||
|
|
||||||
|
// Ensure callbacks are functions.
|
||||||
|
if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) {
|
||||||
|
throw new TypeError('An invalid callback was supplied.');
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.each(function() {
|
||||||
|
// Build a list of all imgs, dependent on what images will be considered.
|
||||||
|
var obj = $(this),
|
||||||
|
allImgs = [];
|
||||||
|
|
||||||
|
if (waitForAll) {
|
||||||
|
// CSS properties which may contain an image.
|
||||||
|
var hasImgProperties = $.waitForImages.hasImageProperties || [],
|
||||||
|
matchUrl = /url\((['"]?)(.*?)\1\)/g;
|
||||||
|
|
||||||
|
// Get all elements, as any one of them could have a background image.
|
||||||
|
obj.find('*').each(function() {
|
||||||
|
var element = $(this);
|
||||||
|
|
||||||
|
// If an `img` element, add it. But keep iterating in case it has a background image too.
|
||||||
|
if (element.is('img:uncached')) {
|
||||||
|
allImgs.push({
|
||||||
|
src: element.attr('src'),
|
||||||
|
element: element[0]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$.each(hasImgProperties, function(i, property) {
|
||||||
|
var propertyValue = element.css(property);
|
||||||
|
// If it doesn't contain this property, skip.
|
||||||
|
if ( ! propertyValue) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all url() of this element.
|
||||||
|
var match;
|
||||||
|
while (match = matchUrl.exec(propertyValue)) {
|
||||||
|
allImgs.push({
|
||||||
|
src: match[2],
|
||||||
|
element: element[0]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// For images only, the task is simpler.
|
||||||
|
obj
|
||||||
|
.find('img:uncached')
|
||||||
|
.each(function() {
|
||||||
|
allImgs.push({
|
||||||
|
src: this.src,
|
||||||
|
element: this
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var allImgsLength = allImgs.length,
|
||||||
|
allImgsLoaded = 0;
|
||||||
|
|
||||||
|
// If no images found, don't bother.
|
||||||
|
if (allImgsLength == 0) {
|
||||||
|
finishedCallback.call(obj[0]);
|
||||||
|
};
|
||||||
|
|
||||||
|
$.each(allImgs, function(i, img) {
|
||||||
|
|
||||||
|
var image = new Image;
|
||||||
|
|
||||||
|
// Handle the image loading and error with the same callback.
|
||||||
|
$(image).bind('load.' + eventNamespace + ' error.' + eventNamespace, function(event) {
|
||||||
|
allImgsLoaded++;
|
||||||
|
|
||||||
|
// If an error occurred with loading the image, set the third argument accordingly.
|
||||||
|
eachCallback.call(img.element, allImgsLoaded, allImgsLength, event.type == 'load');
|
||||||
|
|
||||||
|
if (allImgsLoaded == allImgsLength) {
|
||||||
|
finishedCallback.call(obj[0]);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
image.src = img.src;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
})(jQuery);
|
Loading…
Reference in a new issue