diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2007-07-14 11:25:03 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2007-07-14 11:25:03 +0000 |
commit | 5e20417e6d523372320861f1d9a446ddd75e041f (patch) | |
tree | 9f276a706577f6959fb7465e00e74c3f69258c6e /app | |
parent | bf74efcd1159d9872cdbdc55e9b859c3b2928ffc (diff) | |
download | redmine-5e20417e6d523372320861f1d9a446ddd75e041f.tar.gz redmine-5e20417e6d523372320861f1d9a446ddd75e041f.zip |
Added wiki diff.
Diff can be viewed from the page history, or directly from the project activity page for each edit.
Uses Lars Christensen's diff library.
git-svn-id: http://redmine.rubyforge.org/svn/trunk@583 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/wiki_controller.rb | 10 | ||||
-rw-r--r-- | app/helpers/application_helper.rb | 8 | ||||
-rw-r--r-- | app/helpers/wiki_helper.rb | 37 | ||||
-rw-r--r-- | app/models/wiki_page.rb | 27 | ||||
-rw-r--r-- | app/views/projects/activity.rhtml | 3 | ||||
-rw-r--r-- | app/views/wiki/diff.rhtml | 19 | ||||
-rw-r--r-- | app/views/wiki/history.rhtml | 17 | ||||
-rw-r--r-- | app/views/wiki/show.rhtml | 3 |
8 files changed, 116 insertions, 8 deletions
diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb index bebe1d5ac..d75b85b64 100644 --- a/app/controllers/wiki_controller.rb +++ b/app/controllers/wiki_controller.rb @@ -15,6 +15,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +require 'diff' + class WikiController < ApplicationController layout 'base' before_filter :find_wiki, :check_project_privacy @@ -84,12 +86,18 @@ class WikiController < ApplicationController @versions = @page.content.versions.find :all, :select => "id, author_id, comments, updated_on, version", :order => 'version DESC', - :limit => @version_pages.items_per_page, + :limit => @version_pages.items_per_page + 1, :offset => @version_pages.current.offset render :layout => false if request.xhr? end + def diff + @page = @wiki.find_page(params[:page]) + @diff = @page.diff(params[:version], params[:version_from]) + render_404 unless @diff + end + # remove a wiki page and its history def destroy @page = @wiki.find_page(params[:page]) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 3b6b19e35..5e3146ca5 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -171,6 +171,14 @@ module ApplicationHelper text = @do_textilize ? auto_link(RedCloth.new(text, [:hard_breaks]).to_html) : simple_format(auto_link(h(text))) end + # Same as Rails' simple_format helper without using paragraphs + def simple_format_without_paragraph(text) + text.to_s. + gsub(/\r\n?/, "\n"). # \r\n and \r -> \n + gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br + gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br + end + def error_messages_for(object_name, options = {}) options = options.symbolize_keys object = instance_variable_get("@#{object_name}") diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb index 32b376925..980035bd4 100644 --- a/app/helpers/wiki_helper.rb +++ b/app/helpers/wiki_helper.rb @@ -16,4 +16,41 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. module WikiHelper + + def html_diff(wdiff) + words = wdiff.words.collect{|word| h(word)} + words_add = 0 + words_del = 0 + dels = 0 + del_off = 0 + wdiff.diff.diffs.each do |diff| + add_at = nil + add_to = nil + del_at = nil + deleted = "" + diff.each do |change| + pos = change[1] + if change[0] == "+" + add_at = pos + dels unless add_at + add_to = pos + dels + words_add += 1 + else + del_at = pos unless del_at + deleted << ' ' + change[2] + words_del += 1 + end + end + if add_at + words[add_at] = '<span class="diff_in">' + words[add_at] + words[add_to] = words[add_to] + '</span>' + end + if del_at + words.insert del_at - del_off + dels + words_add, '<span class="diff_out">' + deleted + '</span>' + dels += 1 + del_off += words_del + words_del = 0 + end + end + simple_format_without_paragraph(words.join(' ')) + end end diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 562465197..074d36daa 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -15,6 +15,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +require 'diff' + class WikiPage < ActiveRecord::Base belongs_to :wiki has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy @@ -39,6 +41,17 @@ class WikiPage < ActiveRecord::Base result end + def diff(version_to=nil, version_from=nil) + version_to = version_to ? version_to.to_i : self.content.version + version_from = version_from ? version_from.to_i : version_to - 1 + version_to, version_from = version_from, version_to unless version_from < version_to + + content_to = content.versions.find_by_version(version_to) + content_from = content.versions.find_by_version(version_from) + + (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil + end + def self.pretty_title(str) (str && str.is_a?(String)) ? str.tr('_', ' ') : str end @@ -47,3 +60,17 @@ class WikiPage < ActiveRecord::Base wiki.project end end + +class WikiDiff + attr_reader :diff, :words, :content_to, :content_from + + def initialize(content_to, content_from) + @content_to = content_to + @content_from = content_from + @words = content_to.text.split(/(\s+)/) + @words = @words.select {|word| word != ' '} + words_from = content_from.text.split(/(\s+)/) + words_from = words_from.select {|word| word != ' '} + @diff = words_from.diff @words + end +end diff --git a/app/views/projects/activity.rhtml b/app/views/projects/activity.rhtml index 5e9d0f992..0caa4585a 100644 --- a/app/views/projects/activity.rhtml +++ b/app/views/projects/activity.rhtml @@ -38,7 +38,8 @@ <% elsif e.is_a? Document %> <%= e.created_on.strftime("%H:%M") %> <%=l(:label_document)%>: <%= link_to h(e.title), :controller => 'documents', :action => 'show', :id => e %><br /> <% elsif e.is_a? WikiContent.versioned_class %> - <%= e.created_on.strftime("%H:%M") %> <%=l(:label_wiki_edit)%>: <%= link_to h(WikiPage.pretty_title(e.title)), :controller => 'wiki', :page => e.title %> (<%= link_to '#' + e.version.to_s, :controller => 'wiki', :page => e.title, :version => e.version %>)<br /> + <%= e.created_on.strftime("%H:%M") %> <%=l(:label_wiki_edit)%>: <%= link_to h(WikiPage.pretty_title(e.title)), :controller => 'wiki', :page => e.title %> + (<%= link_to '#' + e.version.to_s, :controller => 'wiki', :page => e.title, :version => e.version %><%= ', ' + link_to('diff', :controller => 'wiki', :action => 'diff', :page => e.title, :version => e.version) if e.version > 1 %>)<br /> <% unless e.comments.blank? %><em><%=h e.comments %></em><% end %> <% elsif e.is_a? Changeset %> <%= e.created_on.strftime("%H:%M") %> <%=l(:label_revision)%> <%= link_to h(e.revision), :controller => 'repositories', :action => 'revision', :id => @project, :rev => e.revision %><br /> diff --git a/app/views/wiki/diff.rhtml b/app/views/wiki/diff.rhtml new file mode 100644 index 000000000..8db2df008 --- /dev/null +++ b/app/views/wiki/diff.rhtml @@ -0,0 +1,19 @@ +<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') %> +<%= link_to(l(:label_page_index), {:action => 'special', :page => 'Page_index'}, :class => 'icon icon-index') %> +</div> + +<h2><%= @page.pretty_title %></h2> + +<p> +<%= l(:label_version) %> <%= link_to @diff.content_from.version, :action => 'index', :page => @page.title, :version => @diff.content_from.version %> +<em>(<%= @diff.content_from.author ? @diff.content_from.author.name : "anonyme" %>, <%= format_time(@diff.content_from.updated_on) %>)</em> +→ +<%= l(:label_version) %> <%= link_to @diff.content_to.version, :action => 'index', :page => @page.title, :version => @diff.content_to.version %>/<%= @page.content.version %> +<em>(<%= @diff.content_to.author ? @diff.content_to.author.name : "anonyme" %>, <%= format_time(@diff.content_to.updated_on) %>)</em> +</p> + +<hr /> + +<%= html_diff(@diff) %> diff --git a/app/views/wiki/history.rhtml b/app/views/wiki/history.rhtml index 6040072ea..85b1541cc 100644 --- a/app/views/wiki/history.rhtml +++ b/app/views/wiki/history.rhtml @@ -6,26 +6,33 @@ <h3><%= l(:label_history) %></h3> +<% form_tag({:action => "diff"}, :method => :get) do %> <table class="list"> <thead><tr> <th>#</th> + <th></th> + <th></th> <th><%= l(:field_updated_on) %></th> <th><%= l(:field_author) %></th> <th><%= l(:field_comments) %></th> </tr></thead> <tbody> +<% show_diff = @versions.size > 1 %> +<% line_num = 1 %> <% @versions.each do |ver| %> <tr class="<%= cycle("odd", "even") %>"> <th align="center"><%= link_to ver.version, :action => 'index', :page => @page.title, :version => ver.version %></th> + <td align="center" width="1%"><%= radio_button_tag('version', ver.version, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('cbto-#{line_num+1}').checked=true;") if show_diff && (line_num < @versions.size) %></td> + <td align="center" width="1%"><%= radio_button_tag('version_from', ver.version, (line_num==2), :id => "cbto-#{line_num}", :onclick => "if ($('cb-#{line_num}').checked==true || $('version_from').value > #{ver.version}) {$('cb-#{line_num-1}').checked=true;}") if show_diff && (line_num > 1) %></td> <td align="center"><%= format_time(ver.updated_on) %></td> <td><em><%= ver.author ? ver.author.name : "anonyme" %></em></td> <td><%=h ver.comments %></td> </tr> +<% line_num += 1 %> <% end %> </tbody> </table> - -<p><%= pagination_links_full @version_pages, :page_param => :p %> -[ <%= @version_pages.current.first_item %> - <%= @version_pages.current.last_item %> / <%= @version_count %> ]</p> - -<p><%= link_to l(:button_back), :action => 'index', :page => @page.title %></p> +<%= submit_tag l(:label_view_diff), :class => 'small' %> +<%= pagination_links_full @version_pages, :page_param => :p %> +[ <%= @version_pages.current.first_item %> - <%= @version_pages.current.last_item %> / <%= @version_count %> ] +<% end %> diff --git a/app/views/wiki/show.rhtml b/app/views/wiki/show.rhtml index 3a830a47d..c7a2985be 100644 --- a/app/views/wiki/show.rhtml +++ b/app/views/wiki/show.rhtml @@ -9,7 +9,8 @@ <% if @content.version != @page.content.version %> <p> <%= link_to(('« ' + l(:label_previous)), :action => 'index', :page => @page.title, :version => (@content.version - 1)) + " - " if @content.version > 1 %> - <%= "#{l(:label_version)} #{@content.version}/#{@page.content.version}" %> - + <%= "#{l(:label_version)} #{@content.version}/#{@page.content.version}" %> + <%= '(' + link_to('diff', :controller => 'wiki', :action => 'diff', :page => @page.title, :version => @content.version) + ')' if @content.version > 1 %> - <%= link_to((l(:label_next) + ' »'), :action => 'index', :page => @page.title, :version => (@content.version + 1)) + " - " if @content.version < @page.content.version %> <%= link_to(l(:label_current_version), :action => 'index', :page => @page.title) %> <br /> |