diff --git a/lib/gollum/app.rb b/lib/gollum/app.rb
index 600ec654..b84559d4 100644
--- a/lib/gollum/app.rb
+++ b/lib/gollum/app.rb
@@ -351,6 +351,13 @@ module Precious
end
end
+ 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})
+ mustache :latest_changes
+ end
+
post '/compare/*' do
@file = params[:splat].first
@versions = params[:versions] || []
diff --git a/lib/gollum/templates/latest_changes.mustache b/lib/gollum/templates/latest_changes.mustache
new file mode 100644
index 00000000..9044c23a
--- /dev/null
+++ b/lib/gollum/templates/latest_changes.mustache
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
diff --git a/lib/gollum/templates/page.mustache b/lib/gollum/templates/page.mustache
index d7b7a53a..ffeeb96a 100644
--- a/lib/gollum/templates/page.mustache
+++ b/lib/gollum/templates/page.mustache
@@ -34,6 +34,9 @@ Mousetrap.bind(['e'], function( e ) {
History
+
+ Latest Changes
{{/page_exists}}
diff --git a/lib/gollum/views/latest_changes.rb b/lib/gollum/views/latest_changes.rb
new file mode 100644
index 00000000..8707e489
--- /dev/null
+++ b/lib/gollum/views/latest_changes.rb
@@ -0,0 +1,90 @@
+module Precious
+ module Views
+ class LatestChanges < Layout
+
+ attr_reader :wiki
+
+ def title
+ "Latest Changes (Globally)"
+ end
+
+ def versions
+ i = @versions.size + 1
+ @versions.map do |v|
+ i -= 1
+ { :id => v.id,
+ :id7 => v.id[0..6],
+ :num => i,
+ :author => v.author.name.respond_to?(:force_encoding) ? v.author.name.force_encoding('UTF-8') : v.author.name,
+ :message => v.message.respond_to?(:force_encoding) ? v.message.force_encoding('UTF-8') : v.message,
+ :date => v.authored_date.strftime("%B %d, %Y"),
+ :gravatar => Digest::MD5.hexdigest(v.author.email.strip.downcase),
+ :identicon => self._identicon_code(v.author.email),
+ :date_full => v.authored_date,
+ :files => v.stats.files.map { |f,*rest|
+ page_path = extract_renamed_path_destination(f)
+ page_path = remove_page_extentions(page_path)
+ { :file => f,
+ :link => "#{page_path}/#{v.id}"
+ }
+ }
+ }
+ end
+ end
+
+ def remove_page_extentions(page_path)
+ Gollum::Markup.formats.values.each do |format|
+ page_path = page_path.gsub(/\.#{format[:regexp]}$/, '')
+ end
+ return page_path
+ end
+
+ def extract_renamed_path_destination(file)
+ return file.gsub(/{.* => (.*)}/, '\1').gsub(/.* => (.*)/, '\1')
+ end
+
+ # http://stackoverflow.com/questions/9445760/bit-shifting-in-ruby
+ def left_shift(int, shift)
+ r = ((int & 0xFF) << (shift & 0x1F)) & 0xFFFFFFFF
+ # 1>>31, 2**32
+ (r & 2147483648) == 0 ? r : r - 4294967296
+ end
+
+ def string_to_code(string)
+ # sha bytes
+ b = [Digest::SHA1.hexdigest(string)[0, 20]].pack('H*').bytes.to_a
+ # Thanks donpark's IdenticonUtil.java for this.
+ # Match the following Java code
+ # ((b[0] & 0xFF) << 24) | ((b[1] & 0xFF) << 16) |
+ # ((b[2] & 0xFF) << 8) | (b[3] & 0xFF)
+
+ return left_shift(b[0], 24) |
+ left_shift(b[1], 16) |
+ left_shift(b[2], 8) |
+ b[3] & 0xFF
+ end
+
+ def _identicon_code(blob)
+ string_to_code blob + @request.host
+ end
+
+ def use_identicon
+ @wiki.user_icons == 'identicon'
+ end
+
+ def partial(name)
+ if name == :author_template
+ self.class.partial("history_authors/#{@wiki.user_icons}")
+ else
+ super
+ end
+ end
+
+ def previous_link
+ end
+
+ def next_link
+ end
+ end
+ end
+end
diff --git a/test/test_latest_changes_view.rb b/test/test_latest_changes_view.rb
new file mode 100644
index 00000000..1af3ee53
--- /dev/null
+++ b/test/test_latest_changes_view.rb
@@ -0,0 +1,45 @@
+# ~*~ encoding: utf-8 ~*~
+require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
+require File.expand_path '../../lib/gollum/views/latest_changes', __FILE__
+
+context "Precious::Views::LatestChanges" do
+ include Rack::Test::Methods
+
+ def app
+ Precious::App
+ end
+
+ setup 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})
+ end
+
+ test "displays_latest_changes" do
+ get('/latest_changes')
+ body = last_response.body
+ assert body.include?('Charles Pence'), "/latest_changes should include the Author Charles Pence"
+ assert body.include?('60f12f4'), "/latest_changes should include the :latest_changes_count commit"
+ assert !body.include?('0ed8cbe'), "/latest_changes should not include more than latest_changes_count commits"
+ assert body.include?('Data-Two.csv'), "/latest_changes include links to modified files in #{body}"
+ assert body.include?('Hobbit.md'), "/latest_changes should include links to modified pages in #{body}"
+ assert body.include?('My-<b>Precious.md => My-Precious.md'), "/latest_changes should indicate renaming action in #{body}"
+ end
+
+ test "extract destination file name in case of path renaming" do
+ view = Precious::Views::LatestChanges.new
+ assert_equal "newDirectoryName/fileName.md", view.extract_renamed_path_destination("{oldDirectoryName => newDirectoryName}/fileName.md")
+ end
+
+ test "remove page extentions" do
+ view = Precious::Views::LatestChanges.new
+ assert_equal "page", view.remove_page_extentions("page.wiki")
+ assert_equal "page-wiki", view.remove_page_extentions("page-wiki.md")
+ assert_equal "file.any_extention", view.remove_page_extentions("file.any_extention")
+ end
+
+ teardown do
+ FileUtils.rm_rf(@path)
+ end
+end