nokodiff 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +28 -0
- data/app/assets/stylesheets/nokodiff.scss +31 -34
- data/lib/nokodiff/differ.rb +73 -24
- data/lib/nokodiff/formatting_helpers.rb +0 -4
- data/lib/nokodiff/text_node_diffs.rb +0 -11
- data/lib/nokodiff/version.rb +1 -1
- data/lib/nokodiff.rb +1 -0
- metadata +16 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9195a8ebd9adf0496df31641acd77e7fa84616b809ecb45cf86cd82346c3dd11
|
|
4
|
+
data.tar.gz: 7bc5d7fe060b960d7ac4fecf58f1f1e1f15b12d421a42552f0fb134cd61cc489
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cd3a8e7d3386676defd112e12a8153d0c2f4af5256fe5c503e81bb6e47ca45395e97d34f8756dd0ad9b600c2719c8c94a9dd9341de14130b502e17634b37c5d9
|
|
7
|
+
data.tar.gz: 8af7196b25ff0eb368046046895b625f8df80394d8fa09c5076ba6d16f6721aa869a20823f026726dc2a50fd30354250104b9336c7ab2599d0176a43c674248e
|
data/README.md
CHANGED
|
@@ -22,6 +22,34 @@ or add it to your Gemfile
|
|
|
22
22
|
gem "nokodiff"
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
## Local Development
|
|
26
|
+
|
|
27
|
+
The gem includes a dummy Rails application located in `spec/dummy`. It can be used to preview `Nokodiff` in a real browser environment without needing to integrate with an external host app.
|
|
28
|
+
|
|
29
|
+
To get the dummy app running you need to:
|
|
30
|
+
|
|
31
|
+
### Install dependencies
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
bundle install
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Navigate to the app and install dependencies
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
cd spec/dummy
|
|
41
|
+
bundle install
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Start the server
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
bin/rails server
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The dummy app will now be running on `localhost:3000`
|
|
51
|
+
If you want to edit the content you are testing it is located in `spec/dummy/app/controllers/application_controller.rb`, alongside the code calling `Nokodiff.diff(@before, @after)`
|
|
52
|
+
|
|
25
53
|
## Usage
|
|
26
54
|
|
|
27
55
|
In the controller:
|
|
@@ -9,56 +9,53 @@ $light-grey: #f3f2f1;
|
|
|
9
9
|
$black: #0b0c0c;
|
|
10
10
|
|
|
11
11
|
.compare-editions {
|
|
12
|
-
|
|
12
|
+
position: relative;
|
|
13
13
|
border-left: 40px solid $light-grey;
|
|
14
14
|
padding: 15px;
|
|
15
15
|
|
|
16
16
|
.diff {
|
|
17
|
-
|
|
18
|
-
padding: 0 15px;
|
|
19
|
-
word-wrap: break-word;
|
|
17
|
+
position: static;
|
|
20
18
|
margin-bottom: 10px;
|
|
21
|
-
position: relative;
|
|
22
19
|
|
|
23
|
-
del,
|
|
24
|
-
|
|
25
|
-
text-decoration: none;
|
|
20
|
+
del, ins, ul, li {
|
|
21
|
+
position: static !important;
|
|
26
22
|
display: block;
|
|
27
|
-
|
|
23
|
+
text-decoration: none;
|
|
28
24
|
border-radius: 3px;
|
|
29
25
|
}
|
|
30
|
-
}
|
|
31
26
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
del {
|
|
28
|
+
background-color: $removed-color;
|
|
29
|
+
padding-bottom: 2px;
|
|
35
30
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
31
|
+
span.diff-marker {
|
|
32
|
+
font-weight: normal;
|
|
33
|
+
background-color: $diff-marker-removed-color;
|
|
34
|
+
border-bottom: 2px dashed $black;
|
|
35
|
+
}
|
|
40
36
|
}
|
|
41
|
-
}
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
ins {
|
|
39
|
+
background-color: $added-color;
|
|
40
|
+
padding-bottom: 2px;
|
|
46
41
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
42
|
+
span.diff-marker {
|
|
43
|
+
font-weight: normal;
|
|
44
|
+
background-color: $diff-marker-added-color;
|
|
45
|
+
border-bottom: 2px dashed $black;
|
|
46
|
+
}
|
|
51
47
|
}
|
|
52
|
-
}
|
|
53
48
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
49
|
+
del::before,
|
|
50
|
+
ins::before {
|
|
51
|
+
position: absolute;
|
|
52
|
+
left: -40px;
|
|
53
|
+
width: 40px;
|
|
54
|
+
height: 1.5em;
|
|
55
|
+
line-height: 1.5em;
|
|
56
|
+
text-align: center;
|
|
57
|
+
z-index: 10;
|
|
58
|
+
}
|
|
62
59
|
}
|
|
63
60
|
|
|
64
61
|
del::before {
|
data/lib/nokodiff/differ.rb
CHANGED
|
@@ -11,7 +11,7 @@ module Nokodiff
|
|
|
11
11
|
when :unchanged
|
|
12
12
|
unchanged_block(diff[:before])
|
|
13
13
|
when :changed
|
|
14
|
-
|
|
14
|
+
changed_block(diff[:before], diff[:after])
|
|
15
15
|
when :deleted
|
|
16
16
|
deleted_block(diff[:before])
|
|
17
17
|
when :added
|
|
@@ -26,17 +26,80 @@ module Nokodiff
|
|
|
26
26
|
before_nodes = @before.children.to_a
|
|
27
27
|
after_nodes = @after.children.to_a
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
before_html_strings = before_nodes.map { |n| n.to_html.strip }
|
|
30
|
+
after_html_strings = after_nodes.map { |n| n.to_html.strip }
|
|
31
|
+
|
|
32
|
+
Diff::LCS.sdiff(before_html_strings, after_html_strings).map do |change|
|
|
33
|
+
case change.action
|
|
34
|
+
when "="
|
|
35
|
+
{
|
|
36
|
+
status: :unchanged,
|
|
37
|
+
before: before_nodes[change.old_position],
|
|
38
|
+
after: after_nodes[change.new_position],
|
|
39
|
+
}
|
|
40
|
+
when "!"
|
|
41
|
+
{
|
|
42
|
+
status: :changed,
|
|
43
|
+
before: before_nodes[change.old_position],
|
|
44
|
+
after: after_nodes[change.new_position],
|
|
45
|
+
}
|
|
46
|
+
when "-"
|
|
47
|
+
{
|
|
48
|
+
status: :deleted,
|
|
49
|
+
before: before_nodes[change.old_position],
|
|
50
|
+
after: nil,
|
|
51
|
+
}
|
|
52
|
+
when "+"
|
|
53
|
+
{
|
|
54
|
+
status: :added,
|
|
55
|
+
before: nil,
|
|
56
|
+
after: after_nodes[change.new_position],
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
34
61
|
|
|
35
|
-
|
|
62
|
+
def changed_block(before_node, after_node)
|
|
63
|
+
if structurally_similar?(before_node, after_node)
|
|
64
|
+
inner_diff = Differ.new(before_node, after_node).to_html
|
|
65
|
+
rebuild_element(after_node, inner_diff)
|
|
66
|
+
elsif before_node.text? && after_node.text?
|
|
67
|
+
before_diff, after_diff = diff_raw_text(before_node, after_node)
|
|
68
|
+
deleted_block(before_diff) + added_block(after_diff)
|
|
69
|
+
else
|
|
70
|
+
before_diff, after_diff = diff_sub_elements(before_node, after_node)
|
|
71
|
+
deleted_block(before_diff) + added_block(after_diff)
|
|
36
72
|
end
|
|
37
73
|
end
|
|
38
74
|
|
|
39
|
-
def
|
|
75
|
+
def structurally_similar?(before_node, after_node)
|
|
76
|
+
before_node.element? &&
|
|
77
|
+
after_node.element? &&
|
|
78
|
+
before_node.name == after_node.name &&
|
|
79
|
+
before_node.name != "p"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def rebuild_element(template_node, inner_html)
|
|
83
|
+
result = template_node.dup
|
|
84
|
+
result.inner_html = inner_html
|
|
85
|
+
result.to_html
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def diff_raw_text(before_text, after_text)
|
|
89
|
+
diff = Diff::LCS.sdiff(before_text.text.chars, after_text.text.chars)
|
|
90
|
+
before_fragment, after_fragment = Nokodiff::ChangesInFragments.new(diff).call
|
|
91
|
+
[merge_fragment_spans(before_fragment), merge_fragment_spans(after_fragment)]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def merge_fragment_spans(fragment)
|
|
95
|
+
doc = fragment.document
|
|
96
|
+
wrapper = Nokogiri::XML::Node.new("span", doc)
|
|
97
|
+
wrapper.inner_html = fragment.to_html
|
|
98
|
+
merge_adjacent_highlighted_changes(wrapper)
|
|
99
|
+
wrapper.inner_html
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def diff_sub_elements(before_html, after_html)
|
|
40
103
|
before_dup = before_html.dup
|
|
41
104
|
after_dup = after_html.dup
|
|
42
105
|
|
|
@@ -48,20 +111,6 @@ module Nokodiff
|
|
|
48
111
|
[before_fragment.to_html, after_fragment.to_html]
|
|
49
112
|
end
|
|
50
113
|
|
|
51
|
-
def set_change_status(before_node, after_node)
|
|
52
|
-
if before_node && after_node
|
|
53
|
-
if before_node.to_html.strip == after_node.to_html.strip
|
|
54
|
-
{ status: :unchanged, before: before_node, after: after_node }
|
|
55
|
-
else
|
|
56
|
-
{ status: :changed, before: before_node, after: after_node }
|
|
57
|
-
end
|
|
58
|
-
elsif before_node
|
|
59
|
-
{ status: :deleted, before: before_node, after: nil }
|
|
60
|
-
elsif after_node
|
|
61
|
-
{ status: :added, before: nil, after: after_node }
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
114
|
def merge_adjacent_highlighted_changes(node)
|
|
66
115
|
return unless node.element?
|
|
67
116
|
|
|
@@ -84,8 +133,8 @@ module Nokodiff
|
|
|
84
133
|
node.name == "span" && node["class"] == "diff-marker"
|
|
85
134
|
end
|
|
86
135
|
|
|
87
|
-
def unchanged_block(
|
|
88
|
-
|
|
136
|
+
def unchanged_block(node)
|
|
137
|
+
node.to_html
|
|
89
138
|
end
|
|
90
139
|
|
|
91
140
|
def deleted_block(html)
|
|
@@ -31,9 +31,6 @@ module Nokodiff
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def diff_text_node_content(before_text_node, after_text_node)
|
|
34
|
-
return highlighted_change(before_text_node) if text_removed?(before_text_node, after_text_node)
|
|
35
|
-
return highlighted_change(after_text_node) if text_added?(before_text_node, after_text_node)
|
|
36
|
-
|
|
37
34
|
before_chars = before_text_node.text.chars
|
|
38
35
|
after_chars = after_text_node.text.chars
|
|
39
36
|
|
|
@@ -44,13 +41,5 @@ module Nokodiff
|
|
|
44
41
|
before_text_node.replace(before_fragment)
|
|
45
42
|
after_text_node.replace(after_fragment)
|
|
46
43
|
end
|
|
47
|
-
|
|
48
|
-
def text_removed?(before_node, after_node)
|
|
49
|
-
before_node && after_node.nil?
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def text_added?(before_node, after_node)
|
|
53
|
-
before_node.nil? && after_node
|
|
54
|
-
end
|
|
55
44
|
end
|
|
56
45
|
end
|
data/lib/nokodiff/version.rb
CHANGED
data/lib/nokodiff.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: nokodiff
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GOV.UK Dev
|
|
@@ -113,6 +113,20 @@ dependencies:
|
|
|
113
113
|
- - "<"
|
|
114
114
|
- !ruby/object:Gem::Version
|
|
115
115
|
version: 8.1.3
|
|
116
|
+
- !ruby/object:Gem::Dependency
|
|
117
|
+
name: byebug
|
|
118
|
+
requirement: !ruby/object:Gem::Requirement
|
|
119
|
+
requirements:
|
|
120
|
+
- - ">="
|
|
121
|
+
- !ruby/object:Gem::Version
|
|
122
|
+
version: '0'
|
|
123
|
+
type: :runtime
|
|
124
|
+
prerelease: false
|
|
125
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
126
|
+
requirements:
|
|
127
|
+
- - ">="
|
|
128
|
+
- !ruby/object:Gem::Version
|
|
129
|
+
version: '0'
|
|
116
130
|
- !ruby/object:Gem::Dependency
|
|
117
131
|
name: diff-lcs
|
|
118
132
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -230,7 +244,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
230
244
|
- !ruby/object:Gem::Version
|
|
231
245
|
version: '0'
|
|
232
246
|
requirements: []
|
|
233
|
-
rubygems_version: 4.0.
|
|
247
|
+
rubygems_version: 4.0.9
|
|
234
248
|
specification_version: 4
|
|
235
249
|
summary: A Ruby Gem to highlight additions, deletions and character level changes
|
|
236
250
|
while preserving original HTML
|