nokodiff 0.4.2 → 1.0.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 +12 -11
- data/app/assets/stylesheets/nokodiff.scss +451 -29
- data/lib/nokodiff/changes_in_fragments.rb +4 -4
- data/lib/nokodiff/differ.rb +94 -64
- data/lib/nokodiff/formatting_helpers.rb +19 -1
- data/lib/nokodiff/text_node_diffs.rb +16 -1
- data/lib/nokodiff/version.rb +1 -1
- metadata +21 -109
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9b38060ba01f5d6e38c752d5b3736072cfb7ddb867b3f9ab85292ef731946695
|
|
4
|
+
data.tar.gz: 333e94464a25ee00c03c00c54210ef1a5c07f52804d1e8299a84cd20338c5a22
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e1fd5d24c4c18f1d61b3f12afe10a1358a15b5504c2dd6ce1d28baadc37d156826b2dc45c309722c933691f4ae2f1a4e019dbdc4396dfece72e590772fbf5084
|
|
7
|
+
data.tar.gz: f962ce7effdf2bb103fe28c07c936fd8694e6edbb4e72059d0c46671887513bfcaf2d6ee31109446014dc7841332e34ba255b263c3712280e5cb75eaf711d401
|
data/README.md
CHANGED
|
@@ -66,7 +66,7 @@ In your application.scss file include:
|
|
|
66
66
|
@import "nokodiff";
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
This will include the styling for
|
|
69
|
+
This will include the styling for `.diff`, `.del`, `.ins` and other classes and `<span>` tags to allow colour coding, highlighting, and underlining of changes.
|
|
70
70
|
|
|
71
71
|
### More complex diffing with `data-diff-key`
|
|
72
72
|
|
|
@@ -111,9 +111,7 @@ Output:
|
|
|
111
111
|
<p>First paragraph</p>
|
|
112
112
|
</div>
|
|
113
113
|
<div data-diff-key="zm7q">
|
|
114
|
-
|
|
115
|
-
<ins aria-label="added content"><p>Second paragraph</p></ins>
|
|
116
|
-
</div>
|
|
114
|
+
<p class="diff ins"><span class="visually-hidden">Added content </span>Second paragraph</p>
|
|
117
115
|
</div>
|
|
118
116
|
</div>
|
|
119
117
|
```
|
|
@@ -154,15 +152,18 @@ Output:
|
|
|
154
152
|
|
|
155
153
|
```html
|
|
156
154
|
<div>
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
<div class="diff">
|
|
160
|
-
<del aria-label="removed content"><p><span class="diff-marker">S</span>e<span class="diff-marker">cond</span> paragraph</p></del>
|
|
155
|
+
<div data-diff-key="ixn4">
|
|
156
|
+
<p>First paragraph</p>
|
|
161
157
|
</div>
|
|
162
|
-
<div
|
|
163
|
-
|
|
158
|
+
<div data-diff-key="zm7q">
|
|
159
|
+
<p class="diff del">
|
|
160
|
+
<span class="diff-marker"><span class="visually-hidden">Diff marker </span><span class="visually-hidden">Removed content </span>S</span>e<span class="diff-marker"><span class="visually-hidden">Diff marker </span>cond</span> paragraph
|
|
161
|
+
</p>
|
|
162
|
+
|
|
163
|
+
<p class="diff ins">
|
|
164
|
+
<span class="diff-marker"><span class="visually-hidden">Diff marker </span><span class="visually-hidden">Added content </span>N</span>e<span class="diff-marker"><span class="visually-hidden">Diff marker </span>w</span> paragraph
|
|
165
|
+
</p>
|
|
164
166
|
</div>
|
|
165
|
-
</div>
|
|
166
167
|
</div>
|
|
167
168
|
```
|
|
168
169
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// stylelint-disable selector-no-qualifying-type, max-nesting-depth
|
|
2
|
-
// Diff of two editions
|
|
3
1
|
$added-color: #e6fff3;
|
|
4
2
|
$diff-marker-added-color: #99ffcf;
|
|
5
3
|
$removed-color: #fadede;
|
|
@@ -7,66 +5,490 @@ $diff-marker-removed-color: #f3aeac;
|
|
|
7
5
|
$text-colour: #0b0c0c;
|
|
8
6
|
$light-grey: #f3f2f1;
|
|
9
7
|
$black: #0b0c0c;
|
|
8
|
+
$comparison-sidebar-width: 40px;
|
|
9
|
+
$comparison-sidebar-padding: 15px;
|
|
10
|
+
$comparison-sidebar-offset: $comparison-sidebar-width + $comparison-sidebar-padding;
|
|
11
|
+
|
|
12
|
+
@mixin diff-block {
|
|
13
|
+
position: relative;
|
|
14
|
+
background: $added-color;
|
|
15
|
+
padding-left: $comparison-sidebar-padding;
|
|
16
|
+
margin-left: -$comparison-sidebar-padding;
|
|
17
|
+
width: calc(100% + $comparison-sidebar-padding);
|
|
18
|
+
|
|
19
|
+
&:before {
|
|
20
|
+
content: " ";
|
|
21
|
+
position: absolute;
|
|
22
|
+
left: -$comparison-sidebar-width;
|
|
23
|
+
width: $comparison-sidebar-width;
|
|
24
|
+
height: 100%;
|
|
25
|
+
font-weight: normal;
|
|
26
|
+
min-height: 1.5em;
|
|
27
|
+
line-height: 1.5em;
|
|
28
|
+
text-align: center;
|
|
29
|
+
z-index: 10;
|
|
30
|
+
background: $diff-marker-added-color;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.visually-hidden {
|
|
35
|
+
position: absolute !important;
|
|
36
|
+
width: 1px !important;
|
|
37
|
+
height: 1px !important;
|
|
38
|
+
// If margin is set to a negative value it can cause text to be announced in
|
|
39
|
+
// the wrong order in VoiceOver for OSX
|
|
40
|
+
margin: 0 !important;
|
|
41
|
+
padding: 0 !important;
|
|
42
|
+
overflow: hidden !important;
|
|
43
|
+
|
|
44
|
+
clip: rect(0 0 0 0) !important;
|
|
45
|
+
clip-path: inset(50%) !important;
|
|
46
|
+
|
|
47
|
+
border: 0 !important;
|
|
48
|
+
|
|
49
|
+
// For long content, line feeds are not interpreted as spaces and small width
|
|
50
|
+
// causes content to wrap 1 word per line:
|
|
51
|
+
// https://medium.com/@jessebeach/beware-smushed-off-screen-accessible-text-5952a4c2cbfe
|
|
52
|
+
white-space: nowrap !important;
|
|
53
|
+
|
|
54
|
+
// Prevent users from selecting or copying visually-hidden text. This prevents
|
|
55
|
+
// a user unintentionally copying more text than they intended and needing to
|
|
56
|
+
// manually trim it down again.
|
|
57
|
+
user-select: none !important;
|
|
58
|
+
}
|
|
10
59
|
|
|
11
60
|
.compare-editions {
|
|
12
61
|
position: relative;
|
|
13
|
-
border-left:
|
|
14
|
-
padding:
|
|
62
|
+
border-left: $comparison-sidebar-width solid $light-grey;
|
|
63
|
+
padding: $comparison-sidebar-padding;
|
|
64
|
+
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
|
|
65
|
+
|
|
66
|
+
td::before {
|
|
67
|
+
// Backup to handle any inputted classes which make use of a ::before attached to a td element
|
|
68
|
+
// unsetting all styles for it will prevent it interfering with the ::before that we need to use
|
|
69
|
+
// for the diff marker
|
|
70
|
+
all: unset;
|
|
71
|
+
}
|
|
15
72
|
|
|
16
73
|
.diff {
|
|
17
74
|
position: static;
|
|
18
75
|
margin-bottom: 10px;
|
|
19
76
|
|
|
20
|
-
del, ins {
|
|
21
|
-
|
|
77
|
+
&.del, &.ins {
|
|
78
|
+
&:is(li){ display: list-item; }
|
|
79
|
+
|
|
80
|
+
position: relative;
|
|
22
81
|
display: block;
|
|
23
82
|
text-decoration: none;
|
|
24
|
-
|
|
83
|
+
background-color: transparent;
|
|
25
84
|
}
|
|
26
85
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
86
|
+
&::after {
|
|
87
|
+
content: "";
|
|
88
|
+
position: absolute;
|
|
89
|
+
top: 0;
|
|
90
|
+
bottom: 0;
|
|
91
|
+
left: -$comparison-sidebar-padding;
|
|
92
|
+
min-height: 1.5em;
|
|
93
|
+
right: 0;
|
|
94
|
+
display: block;
|
|
95
|
+
z-index: -1;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
&.del {
|
|
99
|
+
&::after { background-color: $removed-color; }
|
|
30
100
|
|
|
31
101
|
span.diff-marker {
|
|
32
|
-
font-weight: normal;
|
|
33
102
|
background-color: $diff-marker-removed-color;
|
|
34
103
|
border-bottom: 2px dashed $black;
|
|
35
104
|
}
|
|
36
105
|
}
|
|
37
106
|
|
|
38
|
-
ins {
|
|
39
|
-
background-color: $added-color;
|
|
40
|
-
padding-bottom: 2px;
|
|
107
|
+
&.ins {
|
|
108
|
+
&::after { background-color: $added-color; }
|
|
41
109
|
|
|
42
110
|
span.diff-marker {
|
|
43
|
-
font-weight: normal;
|
|
44
111
|
background-color: $diff-marker-added-color;
|
|
45
112
|
border-bottom: 2px dashed $black;
|
|
46
113
|
}
|
|
47
114
|
}
|
|
48
115
|
|
|
49
|
-
|
|
50
|
-
|
|
116
|
+
&::before {
|
|
117
|
+
// Some govuk styles use ::before in ways we need to override to make this work
|
|
118
|
+
border-radius: unset !important;
|
|
119
|
+
border: unset !important;
|
|
120
|
+
|
|
51
121
|
position: absolute;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
122
|
+
top: 0;
|
|
123
|
+
left: -$comparison-sidebar-offset;
|
|
124
|
+
width: $comparison-sidebar-width;
|
|
125
|
+
height: 100%;
|
|
126
|
+
min-height: 1.5em;
|
|
55
127
|
line-height: 1.5em;
|
|
56
128
|
text-align: center;
|
|
129
|
+
font-weight: normal;
|
|
57
130
|
z-index: 10;
|
|
58
131
|
}
|
|
132
|
+
|
|
133
|
+
&.del::before {
|
|
134
|
+
color: $text-colour;
|
|
135
|
+
background-color: $diff-marker-removed-color;
|
|
136
|
+
content: "−" !important;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
&.ins::before {
|
|
140
|
+
color: $text-colour;
|
|
141
|
+
background-color: $diff-marker-added-color;
|
|
142
|
+
content: "+" !important;
|
|
143
|
+
}
|
|
59
144
|
}
|
|
60
145
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
content: "−";
|
|
146
|
+
// Govspeak-specific overrides
|
|
147
|
+
.gem-c-govspeak & {
|
|
148
|
+
&::before { min-height: 5em; }
|
|
65
149
|
}
|
|
66
150
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
background-color: $diff-marker-added-color;
|
|
70
|
-
content: "+";
|
|
151
|
+
.diff .gem-c-button.govuk-button{
|
|
152
|
+
margin-top: 22px;
|
|
71
153
|
}
|
|
72
|
-
|
|
154
|
+
|
|
155
|
+
.form-download .diff {
|
|
156
|
+
padding-top: 10px;
|
|
157
|
+
padding-bottom: 3px;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Inset/callout elements overrides
|
|
161
|
+
|
|
162
|
+
.address, .contact {
|
|
163
|
+
.diff{
|
|
164
|
+
$address-offset: -16px;
|
|
165
|
+
|
|
166
|
+
&::after {
|
|
167
|
+
left: -$comparison-sidebar-padding + $address-offset;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
&::before {
|
|
171
|
+
left: -$comparison-sidebar-offset + $address-offset;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.help-notice {
|
|
177
|
+
$help-notice-offset: -45px;
|
|
178
|
+
|
|
179
|
+
&:before {
|
|
180
|
+
display: none;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
p {
|
|
184
|
+
position: relative;
|
|
185
|
+
|
|
186
|
+
&:before {
|
|
187
|
+
content: "!";
|
|
188
|
+
font-weight: 700;
|
|
189
|
+
border-radius: 50%;
|
|
190
|
+
color: var(--govuk-body-background-colour, #ffffff);
|
|
191
|
+
background: var(--govuk-text-colour, #0b0c0c);
|
|
192
|
+
font-size: 30px;
|
|
193
|
+
line-height: 29px;
|
|
194
|
+
text-align: center;
|
|
195
|
+
position: absolute;
|
|
196
|
+
margin-top: -5px;
|
|
197
|
+
left: $help-notice-offset;
|
|
198
|
+
min-width: 35px;
|
|
199
|
+
min-height: 35px;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
&:first-child:after {
|
|
203
|
+
content: ".";
|
|
204
|
+
display: block;
|
|
205
|
+
clear: both;
|
|
206
|
+
visibility: hidden;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.diff {
|
|
211
|
+
&::after, &::before {
|
|
212
|
+
top: -15px;
|
|
213
|
+
min-height: calc(1.5em + 30px);
|
|
214
|
+
left: -$comparison-sidebar-padding + $help-notice-offset;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
&::before {
|
|
218
|
+
left: -$comparison-sidebar-offset + $help-notice-offset;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.example, .info-notice {
|
|
224
|
+
$callout-parent-offset: -10px;
|
|
225
|
+
$callout-child-offset: -30px;
|
|
226
|
+
|
|
227
|
+
&.diff {
|
|
228
|
+
&::after {
|
|
229
|
+
left: -$comparison-sidebar-padding + $callout-parent-offset;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
&::before {
|
|
233
|
+
left: -$comparison-sidebar-offset + $callout-parent-offset;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.diff {
|
|
238
|
+
&::after {
|
|
239
|
+
left: -$comparison-sidebar-padding + $callout-child-offset;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
&::before {
|
|
243
|
+
left: -$comparison-sidebar-offset + $callout-child-offset;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// List-specific overrides for non-govuk lists
|
|
249
|
+
$non-govuk-list-offset: -40px;
|
|
250
|
+
|
|
251
|
+
li span.diff, ul span.diff{
|
|
252
|
+
&::after {
|
|
253
|
+
left: -$comparison-sidebar-padding + $non-govuk-list-offset;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
&::before {
|
|
257
|
+
left: -$comparison-sidebar-offset + $non-govuk-list-offset;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// List-specific overrides for govuk lists as we apply a non-standard offset to lists
|
|
262
|
+
$govuk-list-offset: -20px;
|
|
263
|
+
|
|
264
|
+
.gem-c-govspeak & {
|
|
265
|
+
ul.list-no-bullets {
|
|
266
|
+
list-style: none;
|
|
267
|
+
padding-left: 0;
|
|
268
|
+
|
|
269
|
+
span.diff:before {
|
|
270
|
+
left: -$comparison-sidebar-width - $comparison-sidebar-padding;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
ul li span.diff, ul span.diff {
|
|
275
|
+
&::after {
|
|
276
|
+
left: -$comparison-sidebar-padding + $govuk-list-offset;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
&::before {
|
|
280
|
+
left: -$comparison-sidebar-offset + $govuk-list-offset;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
ol li span.diff {
|
|
285
|
+
list-style-type: decimal;
|
|
286
|
+
|
|
287
|
+
&::after {
|
|
288
|
+
left: $comparison-sidebar-padding;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
&::before {
|
|
292
|
+
left: $comparison-sidebar-offset;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
ol:not(.steps) span.diff {
|
|
297
|
+
&::before {
|
|
298
|
+
left: -75px;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
&::after {
|
|
302
|
+
left: -75px;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Deal with the number values of ordered lists (including steps)
|
|
307
|
+
// by changing the increment value depending on sequence of diffs
|
|
308
|
+
ol {
|
|
309
|
+
counter-reset: item 0;
|
|
310
|
+
list-style: none;
|
|
311
|
+
margin-left: 20px;
|
|
312
|
+
|
|
313
|
+
li {
|
|
314
|
+
position: relative;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
li:before {
|
|
318
|
+
position: absolute;
|
|
319
|
+
left: -20px;
|
|
320
|
+
counter-increment: item 1;
|
|
321
|
+
content: counter(item);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Over-ride style for <li> elements inside a span.diff
|
|
325
|
+
// Ideally the markup would be changed so this is not needed
|
|
326
|
+
&.steps > span.diff > li:before {
|
|
327
|
+
left: 0;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
li:has(.diff) + li:not(:has(.diff)),
|
|
331
|
+
li:not(:has(.diff)) + li:has(.diff),
|
|
332
|
+
li:not(:has(.diff)) + li:not(:has(.diff)) {
|
|
333
|
+
&:before {
|
|
334
|
+
counter-increment: item 1;
|
|
335
|
+
content: counter(item);
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
li:has(.del) + li:has(.ins) {
|
|
340
|
+
&:before {
|
|
341
|
+
counter-increment: item 0;
|
|
342
|
+
content: counter(item);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// This is required to over-ride the visually-hidden element
|
|
347
|
+
// that is otherwise assigned the first counter
|
|
348
|
+
// when a new set of steps are added
|
|
349
|
+
& > span.steps > span + li:before {
|
|
350
|
+
content: "1";
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
//govuk "steps"-style ol overrides
|
|
355
|
+
$steps-list-offset: -48px;
|
|
356
|
+
|
|
357
|
+
ol.steps {
|
|
358
|
+
@extend .steps;
|
|
359
|
+
|
|
360
|
+
&:has(>span.diff) {
|
|
361
|
+
@include diff-block;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
margin-left: -$comparison-sidebar-padding;
|
|
365
|
+
width: calc(100% + $comparison-sidebar-padding);
|
|
366
|
+
|
|
367
|
+
li {
|
|
368
|
+
position: relative;
|
|
369
|
+
margin-top: 0.75em;
|
|
370
|
+
margin-bottom: 0.75em;
|
|
371
|
+
padding-top: 0;
|
|
372
|
+
padding-bottom: 0;
|
|
373
|
+
|
|
374
|
+
& > p {
|
|
375
|
+
margin-left: $comparison-sidebar-padding;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
&:has(.del) {
|
|
379
|
+
background: $removed-color;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
&:has(.ins) {
|
|
383
|
+
background: $added-color;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
&::before {
|
|
387
|
+
top: 0;
|
|
388
|
+
margin-left: $comparison-sidebar-padding;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
& > span {
|
|
392
|
+
margin-left: $comparison-sidebar-padding;
|
|
393
|
+
|
|
394
|
+
p {
|
|
395
|
+
margin-bottom: 0;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
li span.diff {
|
|
401
|
+
margin-bottom: 0;
|
|
402
|
+
|
|
403
|
+
&::before {
|
|
404
|
+
left: -$comparison-sidebar-offset + $steps-list-offset;
|
|
405
|
+
height: 100%;
|
|
406
|
+
width: $comparison-sidebar-width;
|
|
407
|
+
min-height: auto; // 1.6em;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Table-specific overrides
|
|
414
|
+
$table-row-offset: -2px;
|
|
415
|
+
|
|
416
|
+
table {
|
|
417
|
+
overflow-x: visible;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// This element is generated before new tables
|
|
421
|
+
// We need to remove it from the display and
|
|
422
|
+
// style the table that follows it as a new element
|
|
423
|
+
& > span.diff.ins {
|
|
424
|
+
display: none;
|
|
425
|
+
|
|
426
|
+
& + table {
|
|
427
|
+
@include diff-block;
|
|
428
|
+
|
|
429
|
+
&:before {
|
|
430
|
+
content: "+";
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
& > span.diff.del {
|
|
436
|
+
display: none;
|
|
437
|
+
|
|
438
|
+
& + table {
|
|
439
|
+
@include diff-block;
|
|
440
|
+
|
|
441
|
+
&:before {
|
|
442
|
+
content: "−";
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
tr.diff {
|
|
448
|
+
position: static;
|
|
449
|
+
transform: scale(1);
|
|
450
|
+
|
|
451
|
+
&.del, &.ins {
|
|
452
|
+
display: table-row;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
&.del::after, &.ins::after {
|
|
456
|
+
left: -$comparison-sidebar-padding + $table-row-offset;
|
|
457
|
+
// Need to account for border in row element
|
|
458
|
+
height: 100%;
|
|
459
|
+
top: 1px;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Attaching a ::before psuedoelement to a <tr> creates a phantom column so we need to hide it
|
|
463
|
+
// and instead attach one to the first-child <td>
|
|
464
|
+
&::before {
|
|
465
|
+
display: none;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
td:first-child::before, th:first-child::before {
|
|
469
|
+
position: absolute;
|
|
470
|
+
left: -$comparison-sidebar-offset;
|
|
471
|
+
width: $comparison-sidebar-width;
|
|
472
|
+
height: 100%;
|
|
473
|
+
min-height: 1.5em;
|
|
474
|
+
top: 1px;
|
|
475
|
+
line-height: 1.5em;
|
|
476
|
+
text-align: center;
|
|
477
|
+
z-index: 10;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
&.del td:first-child::before, &.del th:first-child::before {
|
|
481
|
+
color: $text-colour;
|
|
482
|
+
background-color: $diff-marker-removed-color;
|
|
483
|
+
content: "−";
|
|
484
|
+
font-weight: normal;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
&.ins td:first-child::before, &.ins th:first-child::before {
|
|
488
|
+
color: $text-colour;
|
|
489
|
+
background-color: $diff-marker-added-color;
|
|
490
|
+
content: "+";
|
|
491
|
+
font-weight: normal;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
@@ -43,18 +43,18 @@ module Nokodiff
|
|
|
43
43
|
append_accumulated_text(before_fragment, accumulated_before_text)
|
|
44
44
|
append_accumulated_text(after_fragment, accumulated_after_text)
|
|
45
45
|
|
|
46
|
-
before_fragment.add_child(
|
|
47
|
-
after_fragment.add_child(
|
|
46
|
+
before_fragment.add_child(wrap_character_as_change(change.old_element, before_fragment))
|
|
47
|
+
after_fragment.add_child(wrap_character_as_change(change.new_element, after_fragment))
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
def emphasise_deletion(change)
|
|
51
51
|
append_accumulated_text(before_fragment, accumulated_before_text)
|
|
52
|
-
before_fragment.add_child(
|
|
52
|
+
before_fragment.add_child(wrap_character_as_change(change.old_element, before_fragment))
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def emphasise_addition(change)
|
|
56
56
|
append_accumulated_text(after_fragment, accumulated_after_text)
|
|
57
|
-
after_fragment.add_child(
|
|
57
|
+
after_fragment.add_child(wrap_character_as_change(change.new_element, after_fragment))
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
def append_accumulated_text(fragment, accumulated_text)
|
data/lib/nokodiff/differ.rb
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
module Nokodiff
|
|
2
2
|
class Differ
|
|
3
|
+
include FormattingHelpers
|
|
4
|
+
|
|
5
|
+
BOTTOM_LEVEL_ELEMENTS = %w[p li tr h1 h2 h3 h4 h5 h6].freeze
|
|
6
|
+
|
|
3
7
|
def initialize(before, after)
|
|
4
8
|
@before = before
|
|
5
9
|
@after = after
|
|
@@ -13,9 +17,9 @@ module Nokodiff
|
|
|
13
17
|
when :changed
|
|
14
18
|
changed_block(diff[:before], diff[:after])
|
|
15
19
|
when :deleted
|
|
16
|
-
diff[:before].
|
|
20
|
+
diff[:before].text? ? build_deleted_text_html(diff[:before]) : build_deleted_element_html(diff[:before])
|
|
17
21
|
when :added
|
|
18
|
-
diff[:after].
|
|
22
|
+
diff[:after].text? ? build_added_text_html(diff[:after]) : build_added_element_html(diff[:after])
|
|
19
23
|
end
|
|
20
24
|
}.join("\n")
|
|
21
25
|
end
|
|
@@ -60,21 +64,15 @@ module Nokodiff
|
|
|
60
64
|
end
|
|
61
65
|
|
|
62
66
|
def changed_block(before_node, after_node)
|
|
63
|
-
if structurally_similar?(before_node, after_node) &&
|
|
67
|
+
if structurally_similar?(before_node, after_node) && !treat_element_as_single_change?(before_node)
|
|
64
68
|
inner_diff = Differ.new(before_node, after_node).to_html
|
|
65
69
|
rebuild_element(after_node, inner_diff)
|
|
70
|
+
elsif both_text_nodes?(before_node, after_node)
|
|
71
|
+
before_node, after_node = diff_raw_text(before_node, after_node)
|
|
72
|
+
build_deleted_text_html(before_node) + build_added_text_html(after_node)
|
|
66
73
|
else
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
else
|
|
70
|
-
diff_sub_elements(before_node, after_node)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
if before_node.name == "li"
|
|
74
|
-
deleted_li(before_diff) + added_li(after_diff)
|
|
75
|
-
else
|
|
76
|
-
deleted_block(before_diff) + added_block(after_diff)
|
|
77
|
-
end
|
|
74
|
+
before_node, after_node = diff_sub_elements(before_node, after_node)
|
|
75
|
+
build_deleted_element_html(before_node) + build_added_element_html(after_node)
|
|
78
76
|
end
|
|
79
77
|
end
|
|
80
78
|
|
|
@@ -88,13 +86,11 @@ module Nokodiff
|
|
|
88
86
|
before_node.name == after_node.name
|
|
89
87
|
end
|
|
90
88
|
|
|
91
|
-
# We want all
|
|
92
|
-
#
|
|
93
|
-
#
|
|
94
|
-
def
|
|
95
|
-
before_node.name
|
|
96
|
-
!before_node.name.match(/^h[1-6]$/) &&
|
|
97
|
-
before_node.name != "li"
|
|
89
|
+
# We want to treat all content within certain elements as single changes, even if they are structurally different,
|
|
90
|
+
# to avoid overwhelming the user with changes, and ensure any nested elements are included within the diff,
|
|
91
|
+
# rather than being treated as added or removed content on their own.
|
|
92
|
+
def treat_element_as_single_change?(before_node)
|
|
93
|
+
BOTTOM_LEVEL_ELEMENTS.include?(before_node.name)
|
|
98
94
|
end
|
|
99
95
|
|
|
100
96
|
def rebuild_element(template_node, inner_html)
|
|
@@ -118,19 +114,15 @@ module Nokodiff
|
|
|
118
114
|
end
|
|
119
115
|
|
|
120
116
|
def diff_sub_elements(before_html, after_html)
|
|
121
|
-
|
|
122
|
-
|
|
117
|
+
before_fragment = before_html.dup
|
|
118
|
+
after_fragment = after_html.dup
|
|
123
119
|
|
|
124
|
-
|
|
120
|
+
Nokodiff::TextNodeDiffs.new(before_fragment, after_fragment).call
|
|
125
121
|
|
|
126
122
|
merge_adjacent_highlighted_changes(before_fragment)
|
|
127
123
|
merge_adjacent_highlighted_changes(after_fragment)
|
|
128
124
|
|
|
129
|
-
|
|
130
|
-
[before_fragment.inner_html, after_fragment.inner_html]
|
|
131
|
-
else
|
|
132
|
-
[before_fragment.to_html, after_fragment.to_html]
|
|
133
|
-
end
|
|
125
|
+
[before_fragment, after_fragment]
|
|
134
126
|
end
|
|
135
127
|
|
|
136
128
|
def merge_adjacent_highlighted_changes(node)
|
|
@@ -143,7 +135,7 @@ module Nokodiff
|
|
|
143
135
|
node.children.each_cons(2) do |left, right|
|
|
144
136
|
next unless node_is_a_change?(left) && node_is_a_change?(right)
|
|
145
137
|
|
|
146
|
-
left.
|
|
138
|
+
left.children += right.children
|
|
147
139
|
right.remove
|
|
148
140
|
|
|
149
141
|
merge_adjacent_highlighted_changes(node)
|
|
@@ -159,40 +151,78 @@ module Nokodiff
|
|
|
159
151
|
node.to_html
|
|
160
152
|
end
|
|
161
153
|
|
|
162
|
-
def
|
|
163
|
-
|
|
164
|
-
<
|
|
165
|
-
<
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
</
|
|
177
|
-
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
def
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
154
|
+
def build_deleted_text_html(html)
|
|
155
|
+
<<~HTML
|
|
156
|
+
<span class="diff del">
|
|
157
|
+
<span class="visually-hidden">Removed content </span>
|
|
158
|
+
#{html}
|
|
159
|
+
</span>
|
|
160
|
+
HTML
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def build_added_text_html(html)
|
|
164
|
+
<<~HTML
|
|
165
|
+
<span class="diff ins">
|
|
166
|
+
<span class="visually-hidden">Added content </span>
|
|
167
|
+
#{html}
|
|
168
|
+
</span>
|
|
169
|
+
HTML
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def build_added_element_html(element)
|
|
173
|
+
if element.name == "tr"
|
|
174
|
+
insert_table_row_change_marker(element, "Added row")
|
|
175
|
+
class_string = "#{element['class']&.gsub('del', '')} diff ins".strip
|
|
176
|
+
|
|
177
|
+
<<~HTML
|
|
178
|
+
<#{element.name} class="#{class_string}">
|
|
179
|
+
#{element.inner_html}
|
|
180
|
+
</#{element.name}>
|
|
181
|
+
HTML
|
|
182
|
+
|
|
183
|
+
else
|
|
184
|
+
# Entirely new steps OLs require that the div also have the .steps class
|
|
185
|
+
# This is either a bug or weakness in the actual govuk CSS for that class
|
|
186
|
+
class_string = element["class"].nil? ? nil : " class= \"#{element['class']}\""
|
|
187
|
+
span_class_string = element["class"]&.include?("steps") ? "diff ins steps" : "diff ins"
|
|
188
|
+
|
|
189
|
+
<<~HTML
|
|
190
|
+
<#{element.name}#{class_string}>
|
|
191
|
+
<span class="#{span_class_string}">
|
|
192
|
+
<span class="visually-hidden">Added content </span>
|
|
193
|
+
#{element.inner_html}
|
|
194
|
+
</span>
|
|
195
|
+
</#{element.name}>
|
|
196
|
+
HTML
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def build_deleted_element_html(element)
|
|
201
|
+
if element.name == "tr"
|
|
202
|
+
insert_table_row_change_marker(element, "Removed row")
|
|
203
|
+
class_string = "#{element['class']&.gsub('ins', '')} diff del".strip
|
|
204
|
+
|
|
205
|
+
<<~HTML
|
|
206
|
+
<#{element.name} class="#{class_string}">
|
|
207
|
+
#{element.inner_html}
|
|
208
|
+
</#{element.name}>
|
|
209
|
+
HTML
|
|
210
|
+
|
|
211
|
+
else
|
|
212
|
+
# Entirely removed steps OLs require that the span also have the .steps class
|
|
213
|
+
# This is either a bug or weakness in the actual govuk CSS for that class
|
|
214
|
+
class_string = element["class"].nil? ? nil : " class= \"#{element['class']}\""
|
|
215
|
+
span_class_string = element["class"]&.include?("steps") ? "diff del steps" : "diff del"
|
|
216
|
+
|
|
217
|
+
<<~HTML
|
|
218
|
+
<#{element.name}#{class_string}>
|
|
219
|
+
<span class="#{span_class_string}">
|
|
220
|
+
<span class="visually-hidden">Removed content </span>
|
|
221
|
+
#{element.inner_html}
|
|
222
|
+
</span>
|
|
223
|
+
</#{element.name}>
|
|
224
|
+
HTML
|
|
225
|
+
end
|
|
196
226
|
end
|
|
197
227
|
end
|
|
198
228
|
end
|
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
module Nokodiff
|
|
2
2
|
module FormattingHelpers
|
|
3
|
-
def
|
|
3
|
+
def wrap_character_as_change(char, fragment)
|
|
4
4
|
Nokogiri::XML::Node.new("span", fragment.document).tap do |n|
|
|
5
5
|
n.content = char
|
|
6
6
|
n["class"] = "diff-marker"
|
|
7
7
|
end
|
|
8
8
|
end
|
|
9
|
+
|
|
10
|
+
def wrap_node_as_change(node)
|
|
11
|
+
return unless node
|
|
12
|
+
|
|
13
|
+
wrapper = Nokogiri::XML::Node.new("span", node.document)
|
|
14
|
+
wrapper["class"] = "diff-marker"
|
|
15
|
+
|
|
16
|
+
node.replace(wrapper)
|
|
17
|
+
wrapper.add_child(node)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def insert_table_row_change_marker(element, message)
|
|
21
|
+
marker = Nokogiri::XML::Node.new("span", element.document)
|
|
22
|
+
marker.content = "#{message} "
|
|
23
|
+
marker["class"] = "visually-hidden"
|
|
24
|
+
|
|
25
|
+
element.children.first.prepend_child(marker)
|
|
26
|
+
end
|
|
9
27
|
end
|
|
10
28
|
end
|
|
@@ -16,8 +16,10 @@ module Nokodiff
|
|
|
16
16
|
attr_accessor :before_fragment, :after_fragment
|
|
17
17
|
|
|
18
18
|
def diff_text_nodes(before_node, after_node)
|
|
19
|
-
if before_node
|
|
19
|
+
if !contains_another_element?(before_node) && !contains_another_element?(after_node)
|
|
20
20
|
diff_text_node_content(before_node, after_node)
|
|
21
|
+
elsif mixed_text_and_element_nodes(before_node, after_node)
|
|
22
|
+
mark_nodes_as_changed(before_node, after_node)
|
|
21
23
|
elsif before_node&.element? || after_node&.element?
|
|
22
24
|
before_children = before_node ? before_node.children.to_a : []
|
|
23
25
|
after_children = after_node ? after_node.children.to_a : []
|
|
@@ -30,6 +32,19 @@ module Nokodiff
|
|
|
30
32
|
end
|
|
31
33
|
end
|
|
32
34
|
|
|
35
|
+
def contains_another_element?(node)
|
|
36
|
+
node && !node.text?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def mixed_text_and_element_nodes(before_node, after_node)
|
|
40
|
+
(before_node&.text? && after_node&.element?) || (before_node&.element? && after_node&.text?)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def mark_nodes_as_changed(before_node, after_node)
|
|
44
|
+
wrap_node_as_change(before_node)
|
|
45
|
+
wrap_node_as_change(after_node)
|
|
46
|
+
end
|
|
47
|
+
|
|
33
48
|
def diff_text_node_content(before_text_node, after_text_node)
|
|
34
49
|
before_chars = get_chars(before_text_node)
|
|
35
50
|
after_chars = get_chars(after_text_node)
|
data/lib/nokodiff/version.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: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GOV.UK Dev
|
|
@@ -23,20 +23,34 @@ dependencies:
|
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: byebug
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
26
40
|
- !ruby/object:Gem::Dependency
|
|
27
41
|
name: rake
|
|
28
42
|
requirement: !ruby/object:Gem::Requirement
|
|
29
43
|
requirements:
|
|
30
44
|
- - '='
|
|
31
45
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 13.
|
|
46
|
+
version: 13.4.2
|
|
33
47
|
type: :development
|
|
34
48
|
prerelease: false
|
|
35
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
50
|
requirements:
|
|
37
51
|
- - '='
|
|
38
52
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 13.
|
|
53
|
+
version: 13.4.2
|
|
40
54
|
- !ruby/object:Gem::Dependency
|
|
41
55
|
name: rspec-html-matchers
|
|
42
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -71,14 +85,14 @@ dependencies:
|
|
|
71
85
|
requirements:
|
|
72
86
|
- - '='
|
|
73
87
|
- !ruby/object:Gem::Version
|
|
74
|
-
version: 5.2.
|
|
88
|
+
version: 5.2.1
|
|
75
89
|
type: :development
|
|
76
90
|
prerelease: false
|
|
77
91
|
version_requirements: !ruby/object:Gem::Requirement
|
|
78
92
|
requirements:
|
|
79
93
|
- - '='
|
|
80
94
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: 5.2.
|
|
95
|
+
version: 5.2.1
|
|
82
96
|
- !ruby/object:Gem::Dependency
|
|
83
97
|
name: simplecov
|
|
84
98
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -93,40 +107,6 @@ dependencies:
|
|
|
93
107
|
- - ">="
|
|
94
108
|
- !ruby/object:Gem::Version
|
|
95
109
|
version: '0'
|
|
96
|
-
- !ruby/object:Gem::Dependency
|
|
97
|
-
name: actionview
|
|
98
|
-
requirement: !ruby/object:Gem::Requirement
|
|
99
|
-
requirements:
|
|
100
|
-
- - ">="
|
|
101
|
-
- !ruby/object:Gem::Version
|
|
102
|
-
version: '6'
|
|
103
|
-
- - "<"
|
|
104
|
-
- !ruby/object:Gem::Version
|
|
105
|
-
version: 8.1.4
|
|
106
|
-
type: :runtime
|
|
107
|
-
prerelease: false
|
|
108
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
109
|
-
requirements:
|
|
110
|
-
- - ">="
|
|
111
|
-
- !ruby/object:Gem::Version
|
|
112
|
-
version: '6'
|
|
113
|
-
- - "<"
|
|
114
|
-
- !ruby/object:Gem::Version
|
|
115
|
-
version: 8.1.4
|
|
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'
|
|
130
110
|
- !ruby/object:Gem::Dependency
|
|
131
111
|
name: diff-lcs
|
|
132
112
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -141,74 +121,6 @@ dependencies:
|
|
|
141
121
|
- - ">="
|
|
142
122
|
- !ruby/object:Gem::Version
|
|
143
123
|
version: '0'
|
|
144
|
-
- !ruby/object:Gem::Dependency
|
|
145
|
-
name: gds-api-adapters
|
|
146
|
-
requirement: !ruby/object:Gem::Requirement
|
|
147
|
-
requirements:
|
|
148
|
-
- - ">="
|
|
149
|
-
- !ruby/object:Gem::Version
|
|
150
|
-
version: '101.0'
|
|
151
|
-
- - "<"
|
|
152
|
-
- !ruby/object:Gem::Version
|
|
153
|
-
version: '103.3'
|
|
154
|
-
type: :runtime
|
|
155
|
-
prerelease: false
|
|
156
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
157
|
-
requirements:
|
|
158
|
-
- - ">="
|
|
159
|
-
- !ruby/object:Gem::Version
|
|
160
|
-
version: '101.0'
|
|
161
|
-
- - "<"
|
|
162
|
-
- !ruby/object:Gem::Version
|
|
163
|
-
version: '103.3'
|
|
164
|
-
- !ruby/object:Gem::Dependency
|
|
165
|
-
name: govspeak
|
|
166
|
-
requirement: !ruby/object:Gem::Requirement
|
|
167
|
-
requirements:
|
|
168
|
-
- - ">="
|
|
169
|
-
- !ruby/object:Gem::Version
|
|
170
|
-
version: 10.6.3
|
|
171
|
-
type: :runtime
|
|
172
|
-
prerelease: false
|
|
173
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
174
|
-
requirements:
|
|
175
|
-
- - ">="
|
|
176
|
-
- !ruby/object:Gem::Version
|
|
177
|
-
version: 10.6.3
|
|
178
|
-
- !ruby/object:Gem::Dependency
|
|
179
|
-
name: rails
|
|
180
|
-
requirement: !ruby/object:Gem::Requirement
|
|
181
|
-
requirements:
|
|
182
|
-
- - ">="
|
|
183
|
-
- !ruby/object:Gem::Version
|
|
184
|
-
version: '6'
|
|
185
|
-
- - "<"
|
|
186
|
-
- !ruby/object:Gem::Version
|
|
187
|
-
version: 8.1.4
|
|
188
|
-
type: :runtime
|
|
189
|
-
prerelease: false
|
|
190
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
191
|
-
requirements:
|
|
192
|
-
- - ">="
|
|
193
|
-
- !ruby/object:Gem::Version
|
|
194
|
-
version: '6'
|
|
195
|
-
- - "<"
|
|
196
|
-
- !ruby/object:Gem::Version
|
|
197
|
-
version: 8.1.4
|
|
198
|
-
- !ruby/object:Gem::Dependency
|
|
199
|
-
name: view_component
|
|
200
|
-
requirement: !ruby/object:Gem::Requirement
|
|
201
|
-
requirements:
|
|
202
|
-
- - "~>"
|
|
203
|
-
- !ruby/object:Gem::Version
|
|
204
|
-
version: '4'
|
|
205
|
-
type: :runtime
|
|
206
|
-
prerelease: false
|
|
207
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
208
|
-
requirements:
|
|
209
|
-
- - "~>"
|
|
210
|
-
- !ruby/object:Gem::Version
|
|
211
|
-
version: '4'
|
|
212
124
|
email:
|
|
213
125
|
- govuk-dev@digital.cabinet-office.gov.uk
|
|
214
126
|
executables: []
|
|
@@ -237,14 +149,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
237
149
|
requirements:
|
|
238
150
|
- - ">="
|
|
239
151
|
- !ruby/object:Gem::Version
|
|
240
|
-
version: '3.
|
|
152
|
+
version: '3.3'
|
|
241
153
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
242
154
|
requirements:
|
|
243
155
|
- - ">="
|
|
244
156
|
- !ruby/object:Gem::Version
|
|
245
157
|
version: '0'
|
|
246
158
|
requirements: []
|
|
247
|
-
rubygems_version: 4.0.
|
|
159
|
+
rubygems_version: 4.0.21
|
|
248
160
|
specification_version: 4
|
|
249
161
|
summary: A Ruby Gem to highlight additions, deletions and character level changes
|
|
250
162
|
while preserving original HTML
|