summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/html_word_diff.rb36
-rw-r--r--test/models/page_test.rb18
2 files changed, 47 insertions, 7 deletions
diff --git a/lib/html_word_diff.rb b/lib/html_word_diff.rb
index 1f28cf5..aa0cb86 100644
--- a/lib/html_word_diff.rb
+++ b/lib/html_word_diff.rb
@@ -1,4 +1,5 @@
1require 'diff/lcs' 1require 'diff/lcs'
2require 'cgi'
2 3
3module HtmlWordDiff 4module HtmlWordDiff
4 TOKEN_REGEXP = /<[^>]*>|[[:space:]]+|[[:alnum:]]+|[^[:space:][:alnum:]<>]/ 5 TOKEN_REGEXP = /<[^>]*>|[[:space:]]+|[[:alnum:]]+|[^[:space:][:alnum:]<>]/
@@ -10,11 +11,12 @@ module HtmlWordDiff
10 when '=' 11 when '='
11 html << new_token 12 html << new_token
12 when '-' 13 when '-'
13 html << "<del>#{old_token}</del>" 14 html << wrap_removed(old_token)
14 when '+' 15 when '+'
15 html << "<ins>#{new_token}</ins>" 16 html << wrap_inserted(new_token)
16 when '!' 17 when '!'
17 html << "<del>#{old_token}</del><ins>#{new_token}</ins>" 18 html << wrap_removed(old_token)
19 html << wrap_inserted(new_token)
18 end 20 end
19 end 21 end
20 html 22 html
@@ -29,12 +31,12 @@ module HtmlWordDiff
29 old_out << old_token 31 old_out << old_token
30 new_out << new_token 32 new_out << new_token
31 when '-' 33 when '-'
32 old_out << "<del>#{old_token}</del>" 34 old_out << wrap_removed(old_token)
33 when '+' 35 when '+'
34 new_out << "<ins>#{new_token}</ins>" 36 new_out << wrap_inserted(new_token)
35 when '!' 37 when '!'
36 old_out << "<del>#{old_token}</del>" 38 old_out << wrap_removed(old_token)
37 new_out << "<ins>#{new_token}</ins>" 39 new_out << wrap_inserted(new_token)
38 end 40 end
39 end 41 end
40 [old_out, new_out] 42 [old_out, new_out]
@@ -49,4 +51,24 @@ module HtmlWordDiff
49 def self.tokenize(html) 51 def self.tokenize(html)
50 html.to_s.scan(TOKEN_REGEXP) 52 html.to_s.scan(TOKEN_REGEXP)
51 end 53 end
54
55 def self.tag_token?(token)
56 token.to_s.match?(/\A<[^>]*>\z/)
57 end
58
59 def self.wrap_removed(token)
60 if tag_token?(token)
61 %(<del class="diff_structural" title="removed: #{CGI.escapeHTML(token)}">\u00b6</del>)
62 else
63 "<del>#{token}</del>"
64 end
65 end
66
67 def self.wrap_inserted(token)
68 if tag_token?(token)
69 %(<ins class="diff_structural" title="added: #{CGI.escapeHTML(token)}">\u00b6</ins>)
70 else
71 "<ins>#{token}</ins>"
72 end
73 end
52end 74end
diff --git a/test/models/page_test.rb b/test/models/page_test.rb
index ac5691a..3868a53 100644
--- a/test/models/page_test.rb
+++ b/test/models/page_test.rb
@@ -210,4 +210,22 @@ class PageTest < ActiveSupport::TestCase
210 assert_match "<del>Old</del>", old_html 210 assert_match "<del>Old</del>", old_html
211 assert_match "<ins>New</ins>", new_html 211 assert_match "<ins>New</ins>", new_html
212 end 212 end
213
214 test "diff_against handles an inserted paragraph split without corrupting the document" do
215 n = Node.root.children.create! :slug => "paragraph_split_test"
216 d = n.find_or_create_draft @user1
217 d.body = "<p>Der Vortragsraum ist ab 19 Uhr geöffnet, der Zugang erfolgt über den Hinterhof.</p>"
218 d.save!
219 n.publish_draft!
220
221 d2 = n.find_or_create_draft @user1
222 d2.body = "<p>Der Vortragsraum ist ab 19 Uhr geöffnet,</p>\n<p>der Zugang erfolgt über den Hinterhof.</p>"
223 d2.save!
224
225 diff = d2.diff_against(n.head)
226 fragment = Nokogiri::HTML::DocumentFragment.parse(diff[:body])
227
228 assert_equal 2, fragment.css('ins.diff_structural').length
229 assert_match "der Zugang erfolgt über den Hinterhof.", fragment.text
230 end
213end 231end