Pagination for history and latest changes. (#1396)
* Pagination for history and latest changes * New footer for historical pages * Fix pagination on history view. * Do not directly use git adapter * History view: allow selecting from different pages * Use log_pagination_options to determine latest changes parameters * Fix JS pageFullPath
This commit is contained in:
+16
-8
@@ -17,6 +17,8 @@ require 'gollum/views/helpers'
|
||||
require 'gollum/views/layout'
|
||||
require 'gollum/views/editable'
|
||||
require 'gollum/views/has_page'
|
||||
require 'gollum/views/pagination'
|
||||
|
||||
|
||||
require File.expand_path '../helpers', __FILE__
|
||||
|
||||
@@ -355,8 +357,7 @@ module Precious
|
||||
else
|
||||
sha2, sha1 = sha1, "#{sha1}^" if !sha2
|
||||
@versions = [sha1, sha2]
|
||||
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
|
||||
@diff = diffs.first
|
||||
@diff = wiki.full_reverse_diff_for(@page, @versions.first, @versions.last)
|
||||
@message = "The patch does not apply."
|
||||
mustache :compare
|
||||
end
|
||||
@@ -385,9 +386,15 @@ module Precious
|
||||
wikip = wiki_page(params[:splat].first)
|
||||
@name = wikip.fullname
|
||||
@page = wikip.page
|
||||
@page_num = [params[:page].to_i, 1].max
|
||||
@page_num = [params[:page_num].to_i, 1].max
|
||||
@max_count = settings.wiki_options.fetch(:pagination_count, 10)
|
||||
unless @page.nil?
|
||||
@versions = @page.versions(:page => @page_num, :follow => settings.wiki_options.fetch(:follow_renames, ::Gollum::GIT_ADAPTER == 'rjgit' ? false : true))
|
||||
@versions = @page.versions(
|
||||
per_page: @max_count,
|
||||
page_num: @page_num,
|
||||
follow: settings.wiki_options.fetch(:follow_renames,
|
||||
::Gollum::GIT_ADAPTER == 'rjgit' ? false : true)
|
||||
)
|
||||
mustache :history
|
||||
else
|
||||
redirect to("/")
|
||||
@@ -396,8 +403,9 @@ module Precious
|
||||
|
||||
get '/latest_changes' do
|
||||
@wiki = wiki_new
|
||||
max_count = settings.wiki_options.fetch(:latest_changes_count, 10)
|
||||
@versions = @wiki.latest_changes({:max_count => max_count})
|
||||
@page_num = [params[:page_num].to_i, 1].max
|
||||
@max_count = settings.wiki_options.fetch(:pagination_count, 10)
|
||||
@versions = @wiki.latest_changes(::Gollum::Page.log_pagination_options(per_page: @max_count, page_num: @page_num))
|
||||
mustache :latest_changes
|
||||
end
|
||||
|
||||
@@ -429,8 +437,7 @@ module Precious
|
||||
@versions = [start_version, end_version]
|
||||
wiki = wikip.wiki
|
||||
@page = wikip.page
|
||||
diffs = wiki.repo.diff(@versions.first, @versions.last, @page.path)
|
||||
@diff = diffs.first
|
||||
@diff = wiki.full_reverse_diff_for(@page, @versions.first, @versions.last)
|
||||
mustache :compare
|
||||
end
|
||||
|
||||
@@ -477,6 +484,7 @@ module Precious
|
||||
@name = name
|
||||
@content = page.formatted_data
|
||||
@version = version
|
||||
@historical = true
|
||||
@bar_side = wikip.wiki.bar_side
|
||||
@navbar = true
|
||||
mustache :page
|
||||
|
||||
@@ -97,91 +97,6 @@ $(document).ready(function() {
|
||||
e.preventDefault();
|
||||
} );
|
||||
|
||||
|
||||
var nodeSelector = {
|
||||
node1: null,
|
||||
node2: null,
|
||||
|
||||
selectNodeRange: function( n1, n2 ) {
|
||||
if ( nodeSelector.node1 && nodeSelector.node2 ) {
|
||||
$('#wiki-history td.selected').removeClass('selected');
|
||||
nodeSelector.node1.addClass('selected');
|
||||
nodeSelector.node2.addClass('selected');
|
||||
|
||||
// swap the nodes around if they went in reverse
|
||||
if ( nodeSelector.nodeComesAfter( nodeSelector.node1,
|
||||
nodeSelector.node2 ) ) {
|
||||
var n = nodeSelector.node1;
|
||||
nodeSelector.node1 = nodeSelector.node2;
|
||||
nodeSelector.node2 = n;
|
||||
}
|
||||
|
||||
var s = true;
|
||||
var $nextNode = nodeSelector.node1.next();
|
||||
while ( $nextNode ) {
|
||||
$nextNode.addClass('selected');
|
||||
if ( $nextNode[0] == nodeSelector.node2[0] ) {
|
||||
break;
|
||||
}
|
||||
$nextNode = $nextNode.next();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
nodeComesAfter: function ( n1, n2 ) {
|
||||
var s = false;
|
||||
$(n1).prevAll().each(function() {
|
||||
if ( $(this)[0] == $(n2)[0] ) {
|
||||
s = true;
|
||||
}
|
||||
});
|
||||
return s;
|
||||
},
|
||||
|
||||
checkNode: function( nodeCheckbox ) {
|
||||
var $nodeCheckbox = nodeCheckbox;
|
||||
var $node = $(nodeCheckbox).parent().parent();
|
||||
// if we're unchecking
|
||||
if ( !$nodeCheckbox.is(':checked') ) {
|
||||
|
||||
// remove the range, since we're breaking it
|
||||
$('#wiki-history tr.selected').each(function() {
|
||||
if ( $(this).find('td.checkbox input').is(':checked') ) {
|
||||
return;
|
||||
}
|
||||
$(this).removeClass('selected');
|
||||
});
|
||||
|
||||
// no longer track this
|
||||
if ( $node[0] == nodeSelector.node1[0] ) {
|
||||
nodeSelector.node1 = null;
|
||||
if ( nodeSelector.node2 ) {
|
||||
nodeSelector.node1 = nodeSelector.node2;
|
||||
nodeSelector.node2 = null;
|
||||
}
|
||||
} else if ( $node[0] == nodeSelector.node2[0] ) {
|
||||
nodeSelector.node2 = null;
|
||||
}
|
||||
|
||||
} else {
|
||||
if ( !nodeSelector.node1 ) {
|
||||
nodeSelector.node1 = $node;
|
||||
nodeSelector.node1.addClass('selected');
|
||||
} else if ( !nodeSelector.node2 ) {
|
||||
// okay, we don't have a node 2 but have a node1
|
||||
nodeSelector.node2 = $node;
|
||||
nodeSelector.node2.addClass('selected');
|
||||
nodeSelector.selectNodeRange( nodeSelector.node1,
|
||||
nodeSelector.node2 );
|
||||
} else {
|
||||
// we have two selected already
|
||||
$nodeCheckbox[0].checked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ua detection
|
||||
if ($.browser.mozilla) {
|
||||
$('body').addClass('ff');
|
||||
@@ -351,7 +266,7 @@ $(document).ready(function() {
|
||||
|
||||
if ($('.history button.action-compare-revision').length) {
|
||||
$('.history button.action-compare-revision').click(function() {
|
||||
$("#version-form").submit();
|
||||
$("#selection-form").submit();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -445,6 +360,99 @@ $(document).ready(function() {
|
||||
});
|
||||
}
|
||||
|
||||
if( $("#page-history").length) {
|
||||
if( $("#page-history #pagination").length) {
|
||||
|
||||
var maxSelected = 2;
|
||||
var selectionColors = ["bg-green-light", "bg-red-light"];
|
||||
|
||||
var toggleInputs = function () {
|
||||
var numSelected = 0;
|
||||
$("#selection-form input").each(function (index, element) {
|
||||
var value = $(element).val();
|
||||
var input = $('#version-form input[value="' + value + '"]');
|
||||
input.prop('checked', true);
|
||||
if (index == 0) {
|
||||
input.closest("li").removeClass(selectionColors[1]).addClass(selectionColors[index]);
|
||||
} else if (index == 1) {
|
||||
input.closest("li").addClass(selectionColors[index]);
|
||||
}
|
||||
numSelected = numSelected + 1;
|
||||
});
|
||||
if (numSelected == maxSelected) {
|
||||
$('#version-form input:not(:checked)').prop('disabled', true);
|
||||
$('.history button.action-compare-revision').prop('disabled', false);
|
||||
} else if (numSelected < maxSelected) {
|
||||
$('#version-form input').prop('disabled', false);
|
||||
$('.history button.action-compare-revision').prop('disabled', true);
|
||||
}
|
||||
};
|
||||
|
||||
var onCheckboxSelect = function ( box ) {
|
||||
$('<input>').attr({
|
||||
type: 'hidden',
|
||||
id: $(box).val(),
|
||||
name: 'versions[]',
|
||||
value: $(box).val()
|
||||
}).appendTo($("#selection-form"));
|
||||
toggleInputs();
|
||||
};
|
||||
|
||||
var onCheckboxUnselect = function( box ) {
|
||||
$('#selection-form #' + $(box).val()).remove();
|
||||
$(box).closest("li").removeClass(selectionColors.join(" "));
|
||||
toggleInputs();
|
||||
};
|
||||
|
||||
var setCheckboxEvents = function () {
|
||||
$("#version-form input").on('change', function () {
|
||||
if (this.checked) {
|
||||
onCheckboxSelect(this);
|
||||
} else {
|
||||
onCheckboxUnselect(this);
|
||||
}
|
||||
});
|
||||
};
|
||||
setCheckboxEvents();
|
||||
toggleInputs();
|
||||
|
||||
var clickPageNav = function (e) {
|
||||
e.preventDefault();
|
||||
$.ajax({
|
||||
url: $(this).attr('href'),
|
||||
type: 'GET',
|
||||
success: function(data) {
|
||||
var rowDiv = $('#page-history-list', data);
|
||||
var new_pagination = $('#pagination', data);
|
||||
|
||||
next = $('#pagination #next');
|
||||
prev = $('#pagination #prev');
|
||||
new_next = new_pagination.find('#next');
|
||||
new_prev = new_pagination.find('#prev');
|
||||
|
||||
next[0].hidden = new_next[0].hidden;
|
||||
prev[0].hidden = new_prev[0].hidden;
|
||||
|
||||
next.children('a').attr('href', new_next.children('a').attr('href'));
|
||||
prev.children('a').attr('href', new_prev.children('a').attr('href'));
|
||||
|
||||
$('#page-history-list').replaceWith(rowDiv);
|
||||
|
||||
setCheckboxEvents();
|
||||
toggleInputs();
|
||||
},
|
||||
error: function(data, textStatus, errorThrown) {
|
||||
console.log('something went wrong: ' + textStatus + errorThrown)
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$("#pagination #next a, #pagination #prev a").each(function(index, element) {
|
||||
$(element).on("click", clickPageNav);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if( $("#last-edit").length ) {
|
||||
$("#page-info-toggle").click ( function () {
|
||||
$.ajax({
|
||||
|
||||
@@ -726,4 +726,4 @@ a {
|
||||
color: #A31515;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
<div id="wiki-wrapper" class="history">
|
||||
<div id="head">
|
||||
{{>navbar}}
|
||||
<h1 class="py-4"><span class="f1-light text-gray-light"> History for</span> {{name}}</h1>
|
||||
<h1 class="py-4"><span class="f1-light text-gray-light">History for</span> {{name}}</h1>
|
||||
</div>
|
||||
<div id="page-history">
|
||||
|
||||
<div class="pb-4"><button class="btn btn-sm action-compare-revision" type="submit">Compare Revisions</button></div>
|
||||
{{>pagination}}
|
||||
|
||||
<div class="Box Box--condensed flex-auto">
|
||||
<form name="compare-versions" id="version-form" method="post"
|
||||
action="{{compare_path}}/{{escaped_url_path}}">
|
||||
<ul>
|
||||
<form name="selection-form" id="selection-form" method="post" action="{{compare_path}}/{{escaped_url_path}}"></form>
|
||||
|
||||
<div id="page-history-list" class="Box Box--condensed flex-auto">
|
||||
<form id="version-form">
|
||||
<ul>
|
||||
{{#versions}}
|
||||
<li class="Box-row border-top Box-row--hover-gray d-flex flex-items-center">
|
||||
<span class="pr-2"><input class="checkbox" type="checkbox" name="versions[]" value="{{id}}"></span>
|
||||
@@ -30,6 +31,5 @@
|
||||
<div class="pt-4">
|
||||
<button class="btn btn-sm action-compare-revision" type="submit">Compare Revisions</button>
|
||||
</div>
|
||||
<div class="pt-2"><a href="#" class="action-back-to-top">Back to Top</a></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
<a href="javascript:void(0)">
|
||||
{{author}}
|
||||
</a>
|
||||
{{author}}
|
||||
@@ -3,6 +3,9 @@
|
||||
{{>navbar}}
|
||||
<h1 class="py-4">{{title}}</h1>
|
||||
</div>
|
||||
|
||||
{{>pagination}}
|
||||
|
||||
<div id="wiki-history">
|
||||
|
||||
<div class="Box flex-auto">
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
uploadDest = uploadDest + window.location.pathname.replace(/.*gollum\/[-\w]+\//, "/").replace(/\.[^/.]+$/, "")
|
||||
}
|
||||
{{#page}}
|
||||
var pageFullPath = '{{url_path.source_location}}';
|
||||
var pageFullPath = '{{escaped_url_path}}';
|
||||
{{/page}}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<div id="pagination" class="pb-2 px-3">
|
||||
<span id="prev" {{^previous_page}}hidden{{/previous_page}}>
|
||||
<a href="?page_num={{previous_page}}">« Previous</a>
|
||||
</span>
|
||||
|
||||
<span> </span>
|
||||
|
||||
<span id="next" class="float-right" {{^next_page}}hidden{{/next_page}}>
|
||||
<a href="?page_num={{next_page}}">Next »</a>
|
||||
</span>
|
||||
</div>
|
||||
@@ -42,15 +42,20 @@
|
||||
|
||||
|
||||
<div id="footer" class="pt-4">
|
||||
{{^historical}}
|
||||
{{^preview}}
|
||||
<p id="last-edit"><a id="page-info-toggle" data-pagepath="{{escaped_url_path}}">When was this page last modified?</a></p>
|
||||
{{#allow_editing}}
|
||||
<p>
|
||||
<a id="delete-link" href="{{escaped_url_path}}" data-confirm="Are you sure you want to delete this page?"><span>Delete this Page</span></a>
|
||||
</p>
|
||||
{{/allow_editing}}
|
||||
{{/allow_editing}}
|
||||
{{/preview}}
|
||||
{{/historical}}
|
||||
{{#historical}}
|
||||
<p>This version of the page was edited by <b>{{author}}</b> at {{date}}. <a href="{{full_url_path}}">View the most recent version.</a></p>
|
||||
{{/historical}}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@ module Precious
|
||||
|
||||
def lines
|
||||
lines = []
|
||||
@diff.diff.split("\n")[2..-1].each_with_index do |line, line_index|
|
||||
@diff.split("\n")[2..-1].each_with_index do |line, line_index|
|
||||
lines << { :line => line,
|
||||
:class => line_class(line),
|
||||
:ldln => left_diff_line_number(0, line),
|
||||
|
||||
@@ -15,5 +15,9 @@ module Precious
|
||||
def id
|
||||
@page.sha
|
||||
end
|
||||
|
||||
def full_url_path
|
||||
::File.join(@base_url, escaped_url_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,10 +2,11 @@ module Precious
|
||||
module Views
|
||||
class History < Layout
|
||||
include HasPage
|
||||
include Pagination
|
||||
include Sprockets::Helpers
|
||||
include Precious::Views::SprocketsHelpers
|
||||
|
||||
attr_reader :page, :page_num, :allow_editing
|
||||
attr_reader :page, :allow_editing
|
||||
|
||||
def title
|
||||
@page.title
|
||||
@@ -69,26 +70,6 @@ module Precious
|
||||
def editable
|
||||
@editable
|
||||
end
|
||||
|
||||
def previous_link
|
||||
label = "« Previous"
|
||||
if @page_num == 1
|
||||
%(<span class="disabled">#{label}</span>)
|
||||
else
|
||||
link = url("/history/#{@page.name}?page=#{@page_num-1}")
|
||||
%(<a href="#{link}" hotkey="h">#{label}</a>)
|
||||
end
|
||||
end
|
||||
|
||||
def next_link
|
||||
label = "Next »"
|
||||
if @versions.size == Gollum::Page.per_page
|
||||
link = "/history/#{@page.name}?page=#{@page_num+1}"
|
||||
%(<a href="#{link}" hotkey="l">#{label}</a>)
|
||||
else
|
||||
%(<span class="disabled">#{label}</span>)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
module Precious
|
||||
module Views
|
||||
class LatestChanges < Layout
|
||||
include Pagination
|
||||
|
||||
attr_reader :wiki
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require "pathname"
|
||||
require 'pathname'
|
||||
|
||||
module Precious
|
||||
module Views
|
||||
|
||||
@@ -3,7 +3,7 @@ module Precious
|
||||
class Page < Layout
|
||||
include HasPage
|
||||
|
||||
attr_reader :content, :page, :header, :footer, :preview
|
||||
attr_reader :content, :page, :header, :footer, :preview, :historical
|
||||
|
||||
VALID_COUNTER_STYLES = ['decimal', 'decimal-leading-zero', 'arabic-indic', 'armenian', 'upper-armenian',
|
||||
'lower-armenian', 'bengali', 'cambodian', 'khmer', 'cjk-decimal', 'devanagari', 'georgian', 'gujarati', 'gurmukhi',
|
||||
@@ -42,13 +42,13 @@ module Precious
|
||||
end
|
||||
|
||||
def author
|
||||
first = page.last_version
|
||||
first = @version ? page.version : page.last_version
|
||||
return DEFAULT_AUTHOR unless first
|
||||
first.author.name.respond_to?(:force_encoding) ? first.author.name.force_encoding('UTF-8') : first.author.name
|
||||
end
|
||||
|
||||
def date
|
||||
first = page.last_version
|
||||
first = @version ? page.version : page.last_version
|
||||
return Time.now.strftime(DATE_FORMAT) unless first
|
||||
first.authored_date.strftime(DATE_FORMAT)
|
||||
end
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
module Precious
|
||||
module Pagination
|
||||
def next_page
|
||||
@versions.length < @max_count ? nil : (@page_num + 1).to_s
|
||||
end
|
||||
|
||||
def previous_page
|
||||
@page_num == 1 ? nil : (@page_num - 1).to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -701,6 +701,23 @@ context "Frontend with lotr" do
|
||||
assert_match /not so big smelly creatures/, last_response.body
|
||||
end
|
||||
|
||||
test 'editable pages have footer' do
|
||||
get 'Bilbo-Baggings'
|
||||
assert_equal last_response.body.include?('delete-link'), false
|
||||
assert_equal last_response.body.include?('page-info-toggle'), false
|
||||
end
|
||||
|
||||
test 'show specific revision of page' do
|
||||
old_sha = '5bc1aaec6149e854078f1d0f8b71933bbc6c2e43'
|
||||
page = 'Bilbo-Baggins'
|
||||
get "#{page}/#{old_sha}"
|
||||
assert last_response.ok?
|
||||
assert_equal last_response.body.include?('delete-link'), false
|
||||
assert_equal last_response.body.include?('page-info-toggle'), false
|
||||
assert last_response.body.include?('This version of the page was edited by <b>Tom Preston-Werner</b> at 2010-04-07')
|
||||
assert last_response.body.include?("<a href=\"/Bilbo-Baggins.md\">View the most recent version.</a></p>")
|
||||
end
|
||||
|
||||
test "show revision of specific file" do
|
||||
old_sha = "df26e61e707116f81ebc6b935ec6d1676b7e96c4"
|
||||
update_sha = "f803c64d11407b23797325e3843f3f378b78f611"
|
||||
|
||||
@@ -13,16 +13,16 @@ context "Precious::Views::LatestChanges" do
|
||||
@path = cloned_testpath("examples/lotr.git")
|
||||
@wiki = Gollum::Wiki.new(@path)
|
||||
Precious::App.set(:gollum_path, @path)
|
||||
Precious::App.set(:wiki_options, {:latest_changes_count => 10})
|
||||
Precious::App.set(:wiki_options, {:pagination_count => 10})
|
||||
end
|
||||
|
||||
test "displays_latest_changes" do
|
||||
get('/gollum/latest_changes')
|
||||
body = last_response.body
|
||||
|
||||
assert body.include?("<span class=\"float-left col-2\"><a href=\"javascript:void(0)\">\n Charles Pence\n</a>\n</span>"), "/latest_changes should include Author Charles Pence"
|
||||
assert body.include?('1db89eb'), "/latest_changes should include the :latest_changes_count commit"
|
||||
assert !body.include?('a8ad3c0'), "/latest_changes should not include more than latest_changes_count commits"
|
||||
|
||||
assert body.include?("Charles Pence</span>"), "/latest_changes should include Author Charles Pence"
|
||||
assert body.include?('1db89eb'), "/latest_changes should include the :pagination_count commit"
|
||||
assert !body.include?('a8ad3c0'), "/latest_changes should not include more than :pagination_count commits"
|
||||
assert body.include?('<a href="Data-Two.csv/874f597a5659b4c3b153674ea04e406ff393975e">Data-Two.csv</a>'), "/latest_changes include links to modified files in #{body}"
|
||||
assert body.include?('<a href="Hobbit.md/874f597a5659b4c3b153674ea04e406ff393975e">Hobbit.md</a>'), "/latest_changes should include links to modified pages in #{body}"
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user