Added wiki annotate view. It's accessible for each version from the page history view.
Slight style change: pre-wrap added on file/diff contents. git-svn-id: http://redmine.rubyforge.org/svn/trunk@1020 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
3d5381b24b
commit
31c6ebb310
|
@ -114,6 +114,11 @@ class WikiController < ApplicationController
|
|||
render_404 unless @diff
|
||||
end
|
||||
|
||||
def annotate
|
||||
@page = @wiki.find_page(params[:page])
|
||||
@annotate = @page.annotate(params[:version])
|
||||
end
|
||||
|
||||
# remove a wiki page and its history
|
||||
def destroy
|
||||
@page = @wiki.find_page(params[:page])
|
||||
|
|
|
@ -60,6 +60,14 @@ class WikiContent < ActiveRecord::Base
|
|||
data
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the previous version or nil
|
||||
def previous
|
||||
@previous ||= WikiContent::Version.find(:first,
|
||||
:order => 'version DESC',
|
||||
:include => :author,
|
||||
:conditions => ["wiki_content_id = ? AND version < ?", wiki_content_id, version])
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
require 'diff'
|
||||
require 'enumerator'
|
||||
|
||||
class WikiPage < ActiveRecord::Base
|
||||
belongs_to :wiki
|
||||
|
@ -87,6 +88,12 @@ class WikiPage < ActiveRecord::Base
|
|||
(content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil
|
||||
end
|
||||
|
||||
def annotate(version=nil)
|
||||
version = version ? version.to_i : self.content.version
|
||||
c = content.versions.find_by_version(version)
|
||||
c ? WikiAnnotate.new(c) : nil
|
||||
end
|
||||
|
||||
def self.pretty_title(str)
|
||||
(str && str.is_a?(String)) ? str.tr('_', ' ') : str
|
||||
end
|
||||
|
@ -113,3 +120,41 @@ class WikiDiff
|
|||
@diff = words_from.diff @words
|
||||
end
|
||||
end
|
||||
|
||||
class WikiAnnotate
|
||||
attr_reader :lines, :content
|
||||
|
||||
def initialize(content)
|
||||
@content = content
|
||||
current = content
|
||||
current_lines = current.text.split(/\r?\n/)
|
||||
@lines = current_lines.collect {|t| [nil, nil, t]}
|
||||
positions = []
|
||||
current_lines.size.times {|i| positions << i}
|
||||
while (current.previous)
|
||||
d = current.previous.text.split(/\r?\n/).diff(current.text.split(/\r?\n/)).diffs.flatten
|
||||
d.each_slice(3) do |s|
|
||||
sign, line = s[0], s[1]
|
||||
if sign == '+' && positions[line] && positions[line] != -1
|
||||
if @lines[positions[line]][0].nil?
|
||||
@lines[positions[line]][0] = current.version
|
||||
@lines[positions[line]][1] = current.author
|
||||
end
|
||||
end
|
||||
end
|
||||
d.each_slice(3) do |s|
|
||||
sign, line = s[0], s[1]
|
||||
if sign == '-'
|
||||
positions.insert(line, -1)
|
||||
else
|
||||
positions[line] = nil
|
||||
end
|
||||
end
|
||||
positions.compact!
|
||||
# Stop if every line is annotated
|
||||
break unless @lines.detect { |line| line[0].nil? }
|
||||
current = current.previous
|
||||
end
|
||||
@lines.each { |line| line[0] ||= current.version }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<div class="contextual">
|
||||
<%= link_to(l(:button_edit), {:action => 'edit', :page => @page.title}, :class => 'icon icon-edit') %>
|
||||
<%= link_to(l(:label_history), {:action => 'history', :page => @page.title}, :class => 'icon icon-history') %>
|
||||
</div>
|
||||
|
||||
<h2><%= @page.pretty_title %></h2>
|
||||
|
||||
<p>
|
||||
<%= l(:label_version) %> <%= link_to @annotate.content.version, :action => 'index', :page => @page.title, :version => @annotate.content.version %>
|
||||
<em>(<%= @annotate.content.author ? @annotate.content.author.name : "anonyme" %>, <%= format_time(@annotate.content.updated_on) %>)</em>
|
||||
</p>
|
||||
|
||||
<% colors = Hash.new {|k,v| k[v] = (k.size % 12) } %>
|
||||
|
||||
<table class="filecontent annotate CodeRay ">
|
||||
<tbody>
|
||||
<% line_num = 1 %>
|
||||
<% @annotate.lines.each do |line| -%>
|
||||
<tr class="bloc-<%= colors[line[0]] %>">
|
||||
<th class="line-num"><%= line_num %></th>
|
||||
<td class="revision"><%= link_to line[0], :controller => 'wiki', :action => 'index', :id => @project, :page => @page.title, :version => line[0] %></td>
|
||||
<td class="author"><%= h(line[1]) %></td>
|
||||
<td class="line-code"><pre><%= line[2] %></pre></td>
|
||||
</tr>
|
||||
<% line_num += 1 %>
|
||||
<% end -%>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<% content_for :header_tags do %>
|
||||
<%= stylesheet_link_tag 'scm' %>
|
||||
<% end %>
|
|
@ -11,6 +11,7 @@
|
|||
<th><%= l(:field_updated_on) %></th>
|
||||
<th><%= l(:field_author) %></th>
|
||||
<th><%= l(:field_comments) %></th>
|
||||
<th></th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<% show_diff = @versions.size > 1 %>
|
||||
|
@ -23,6 +24,7 @@
|
|||
<td align="center"><%= format_time(ver.updated_on) %></td>
|
||||
<td><em><%= ver.author ? ver.author.name : "anonyme" %></em></td>
|
||||
<td><%=h ver.comments %></td>
|
||||
<td align="center"><%= link_to l(:button_annotate), :action => 'annotate', :page => @page.title, :version => ver.version %></td>
|
||||
</tr>
|
||||
<% line_num += 1 %>
|
||||
<% end %>
|
||||
|
|
|
@ -71,7 +71,7 @@ Redmine::AccessControl.map do |map|
|
|||
map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
|
||||
map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
|
||||
map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member
|
||||
map.permission :view_wiki_pages, :wiki => [:index, :history, :diff, :special]
|
||||
map.permission :view_wiki_pages, :wiki => [:index, :history, :diff, :annotate, :special]
|
||||
map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment, :destroy_attachment]
|
||||
end
|
||||
|
||||
|
|
|
@ -10,6 +10,11 @@ table.filecontent th.line-num {
|
|||
width: 2%;
|
||||
padding-right: 3px;
|
||||
}
|
||||
table.filecontent td.line-code pre {
|
||||
white-space: pre-wrap; /* CSS2.1 compliant */
|
||||
white-space: -moz-pre-wrap; /* Mozilla-based browsers */
|
||||
white-space: -o-pre-wrap; /* Opera 7+ */
|
||||
}
|
||||
|
||||
/* 12 different colors for the annonate view */
|
||||
table.annotate tr.bloc-0 {background: #FFFFBF;}
|
||||
|
@ -40,6 +45,7 @@ table.annotate td.author {
|
|||
padding-right: 1em;
|
||||
width: 3%;
|
||||
background: inherit;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
table.annotate td.line-code { background-color: #fafafa; }
|
||||
|
|
|
@ -4,7 +4,7 @@ wiki_content_versions_001:
|
|||
page_id: 1
|
||||
id: 1
|
||||
version: 1
|
||||
author_id: 1
|
||||
author_id: 2
|
||||
comments: Page creation
|
||||
wiki_content_id: 1
|
||||
compression: ""
|
||||
|
|
|
@ -98,6 +98,20 @@ class WikiControllerTest < Test::Unit::TestCase
|
|||
:content => /updated/
|
||||
end
|
||||
|
||||
def test_annotate
|
||||
get :annotate, :id => 1, :page => 'CookBook_documentation', :version => 2
|
||||
assert_response :success
|
||||
assert_template 'annotate'
|
||||
# Line 1
|
||||
assert_tag :tag => 'tr', :child => { :tag => 'th', :attributes => {:class => 'line-num'}, :content => '1' },
|
||||
:child => { :tag => 'td', :attributes => {:class => 'author'}, :content => /John Smith/ },
|
||||
:child => { :tag => 'td', :content => /h1\. CookBook documentation/ }
|
||||
# Line 2
|
||||
assert_tag :tag => 'tr', :child => { :tag => 'th', :attributes => {:class => 'line-num'}, :content => '2' },
|
||||
:child => { :tag => 'td', :attributes => {:class => 'author'}, :content => /redMine Admin/ },
|
||||
:child => { :tag => 'td', :content => /Some updated \[\[documentation\]\] here/ }
|
||||
end
|
||||
|
||||
def test_rename_with_redirect
|
||||
@request.session[:user_id] = 2
|
||||
post :rename, :id => 1, :page => 'Another_page',
|
||||
|
|
Loading…
Reference in New Issue