Skip to content

Commit 0268848

Browse files
cci: show additional editor comments
1 parent 25f6a06 commit 0268848

File tree

8 files changed

+217
-6
lines changed

8 files changed

+217
-6
lines changed

i18n/core/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"deputy.session.row.history": "Open page history",
5151
"deputy.session.row.checkAll": "Mark all revisions as finished",
5252
"deputy.session.row.checkAll.confirm": "Mark all revisions as finished?",
53+
"deputy.session.row.additionalComments": "Discussion",
5354
"deputy.session.row.closeComments": "Closing comments",
5455
"deputy.session.row.close.sigFound": "The closing comment had a signature. It will not be automatically removed when saved.",
5556
"deputy.session.row.close.sigFound.maybe": "The closing comment might have had a signature. It will not be automatically removed when saved.",

src/css/deputy.css

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,23 @@ p.dp-messageWidget-message {
206206
vertical-align: middle;
207207
}
208208

209+
.dp-cs-row-comments {
210+
padding: 16px;
211+
background-color: rgba(0, 159, 255, 10%);
212+
margin: 4px 0;
213+
}
214+
215+
.dp-cs-row-comments > b {
216+
letter-spacing: 0.1em;
217+
font-weight: bold;
218+
text-transform: uppercase;
219+
color: rgba(0, 0, 0, 0.5);
220+
}
221+
222+
.dp-cs-row-comments hr {
223+
border-color: rgb(0, 31, 51);
224+
}
225+
209226
body.mediawiki.ltr .dp-cs-row-head > :not(:first-child):not(:last-child),
210227
body.mediawiki.ltr .dp-cs-row-head > :not(:first-child):not(:last-child) {
211228
margin-right: 16px;
@@ -255,7 +272,7 @@ body.mediawiki.rtl .dp-cs-row-head > :not(:first-child):not(:last-child) {
255272

256273
.dp-cs-row-content {
257274
padding: 16px;
258-
background-color: rgba(0, 0, 0, 4%);
275+
background-color: rgba(0, 0, 0, 6%);
259276
margin: 4px 0;
260277
}
261278

src/ui/root/DeputyContributionSurveyRow.tsx

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
7171
* The "LI" element that this row was rendered into by MediaWiki.
7272
*/
7373
originalElement?: HTMLLIElement;
74+
/**
75+
* Additional comments that may have been left by other editors.
76+
*/
77+
additionalComments: Element[];
7478
/**
7579
* Original wikitext of this element.
7680
*/
@@ -357,10 +361,85 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
357361
super();
358362
this.row = row;
359363
this.originalElement = originalElement;
364+
this.additionalComments = this.extractAdditionalComments();
360365
this.originalWikitext = originalWikitext;
361366
this.section = section;
362367
}
363368

369+
/**
370+
* Extracts HTML elements which may be additional comments left by others.
371+
* The general qualification for this is that it has to be a list block
372+
* element that comes after the main line (in this case, it's detected after
373+
* the last .
374+
* This appears in the following form in wikitext:
375+
*
376+
* ```
377+
* * [[Page]] (...) [[Special:Diff/...|...]]
378+
* *: Hello! <-- definition list block
379+
* ** What!? <-- sub ul
380+
* *# Yes. <-- sub ol
381+
* * [[Page]] (...) [[Special:Diff/...|...]]<div>...</div> <-- inline div
382+
* ```
383+
*
384+
* Everything else (`*<div>...`, `*'''...`, `*<span>`, etc.) is considered
385+
* not to be an additional comment.
386+
*
387+
* If no elements were found, this returns an empty array.
388+
*
389+
* @return An array of HTMLElements
390+
*/
391+
extractAdditionalComments(): Element[] {
392+
// COMPAT: Specific to MER-C contribution surveyor
393+
// Initialize to first successive diff link.
394+
let lastSuccessiveDiffLink = this.originalElement.querySelector(
395+
'a[href^="/wiki/Special:Diff/"]'
396+
);
397+
398+
const elements: Element[] = [];
399+
if ( !lastSuccessiveDiffLink ) {
400+
// No diff links. Get last element, check if block element, and crawl backwards.
401+
let nextDiscussionElement = this.originalElement.lastElementChild;
402+
while (
403+
nextDiscussionElement &&
404+
window.getComputedStyle( nextDiscussionElement, '' ).display === 'block'
405+
) {
406+
elements.push( nextDiscussionElement );
407+
408+
nextDiscussionElement = nextDiscussionElement.previousElementSibling;
409+
}
410+
} else {
411+
while (
412+
lastSuccessiveDiffLink.nextElementSibling &&
413+
lastSuccessiveDiffLink.nextElementSibling.tagName === 'A' &&
414+
lastSuccessiveDiffLink
415+
.nextElementSibling
416+
.getAttribute( 'href' )
417+
.startsWith( '/wiki/Special:Diff' )
418+
) {
419+
lastSuccessiveDiffLink = lastSuccessiveDiffLink.nextElementSibling;
420+
}
421+
// The first block element after `lastSuccessiveDiffLink` is likely discussion,
422+
// and everything after it is likely part of such discussion.
423+
let pushing = false;
424+
let nextDiscussionElement = lastSuccessiveDiffLink.nextElementSibling;
425+
while ( nextDiscussionElement != null ) {
426+
if (
427+
!pushing &&
428+
window.getComputedStyle( nextDiscussionElement ).display === 'block'
429+
) {
430+
pushing = true;
431+
elements.push( nextDiscussionElement );
432+
} else if ( pushing ) {
433+
elements.push( nextDiscussionElement );
434+
}
435+
436+
nextDiscussionElement = nextDiscussionElement.nextElementSibling;
437+
}
438+
}
439+
440+
return elements;
441+
}
442+
364443
/**
365444
* Load the revision data in and change the UI element respectively.
366445
*/
@@ -475,7 +554,7 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
475554
this.commentsTextInput = new OO.ui.MultilineTextInputWidget( {
476555
classes: [ 'dp-cs-row-closeComments' ],
477556
placeholder: mw.msg( 'deputy.session.row.closeComments' ),
478-
value: value,
557+
value: value ?? '',
479558
autosize: true,
480559
rows: 1
481560
} );
@@ -535,7 +614,7 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
535614
revisionList.appendChild( unwrapWidget( this.unfinishedMessageBox ) );
536615

537616
revisionList.appendChild( unwrapWidget(
538-
this.renderCommentsTextInput()
617+
this.renderCommentsTextInput( this.row.comment )
539618
) );
540619

541620
for ( const revision of diffs.values() ) {
@@ -791,6 +870,27 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
791870
</div>;
792871
}
793872

873+
/**
874+
* Renders additional comments that became part of this row.
875+
*
876+
* @return An HTML element.
877+
*/
878+
renderAdditionalComments(): JSX.Element {
879+
const additionalComments = <div class="dp-cs-row-comments">
880+
<b>{ mw.msg( 'deputy.session.row.additionalComments' ) }</b>
881+
<hr/>
882+
<div class="dp-cs-row-comments-content" dangerouslySetInnerHTML={
883+
this.additionalComments.map( e => e.innerHTML ).join( '' )
884+
} />
885+
</div>;
886+
887+
// Open all links in new tabs.
888+
additionalComments.querySelectorAll( '.dp-cs-row-comments-content a' )
889+
.forEach( a => a.setAttribute( 'target', '_blank' ) );
890+
891+
return additionalComments;
892+
}
893+
794894
/**
795895
*
796896
* @param diffs
@@ -810,6 +910,7 @@ export default class DeputyContributionSurveyRow extends EventTarget implements
810910
this.element = swapElements(
811911
this.element, <div>
812912
{ this.renderHead( diffs, contentContainer ) }
913+
{ this.additionalComments?.length > 0 && this.renderAdditionalComments() }
813914
{ contentContainer }
814915
</div>
815916
) as HTMLElement;

src/ui/root/DeputyContributionSurveySection.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ export default class DeputyContributionSurveySection implements DeputyUIElement
294294
return false;
295295
}
296296

297-
this.originalList = firstList.parentElement.removeChild( firstList ) as HTMLElement;
297+
this.originalList = firstList as HTMLElement;
298298

299299
const rowElements: Record<string, HTMLLIElement> = {};
300300
for ( let i = 0; i < this.originalList.children.length; i++ ) {
@@ -343,6 +343,9 @@ export default class DeputyContributionSurveySection implements DeputyUIElement
343343
this.wikitextLines.push( rowElement );
344344
}
345345

346+
// Remove last, this is to preserve as much state as possible
347+
firstList.parentElement.removeChild( firstList );
348+
346349
return true;
347350
}
348351

src/util/pickSequence.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Iterates over an array and returns an Iterator which checks each element
3+
* of the array sequentially for a given condition (predicated by `condition`)
4+
* and returns another array, containing an element where `true` was returned,
5+
* and every subsequent element where the check returns `false`.
6+
*
7+
* @param arr
8+
* @param condition
9+
* @yield The found sequence
10+
*/
11+
export default function* pickSequence<T>(
12+
arr: T[],
13+
condition: ( val: T ) => boolean
14+
): Iterable<T[]> {
15+
let currentValues: T[] = null;
16+
let shouldReturnValues = false;
17+
for ( const val of arr ) {
18+
if ( condition( val ) ) {
19+
shouldReturnValues = true;
20+
if ( currentValues != null ) {
21+
yield currentValues;
22+
}
23+
currentValues = [ val ];
24+
continue;
25+
}
26+
if ( shouldReturnValues ) {
27+
currentValues.push( val );
28+
}
29+
}
30+
if ( currentValues.length > 0 ) {
31+
yield currentValues;
32+
}
33+
}

tests/unit/ContributionSurveyRowParserTests.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ describe( 'ContributionSurveyRowParser line parsing tests', () => {
350350
} );
351351
} );
352352

353-
test( 'edge: comment after diffs', () => {
353+
test( 'edge: comment after diffs (unfinished, has comment)', () => {
354354
const parser = new ContributionSurveyRowParser(
355355
'* [[:Example]]: (1 edit, 1 major, +173) [[Special:Diff/123456|(+173)]] muy bien'
356356
);

tests/unit/browser/UtilityUnitTests.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import '../../../src/types';
22
import 'types-mediawiki';
33
import BrowserHelper from '../../util/BrowserHelper';
44

5-
describe( 'Utility function tests', () => {
5+
describe( 'Utility (on-browser) function tests', () => {
66

77
let page: BrowserHelper;
88

tests/unit/util/UtilityUnitTests.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import pickSequence from '../../../src/util/pickSequence';
2+
3+
describe( 'Utility function tests', () => {
4+
5+
test( 'pickSequence', async () => {
6+
expect( Array.from(
7+
pickSequence(
8+
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ],
9+
( v ) => v % 3 === 0
10+
)
11+
) ).toStrictEqual(
12+
[
13+
[ 3, 4, 5 ],
14+
[ 6, 7, 8 ],
15+
[ 9, 10 ]
16+
]
17+
);
18+
} );
19+
20+
test( 'pickSequence', async () => {
21+
expect( Array.from(
22+
pickSequence(
23+
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ],
24+
( v ) => v % 2 === 0
25+
)
26+
) ).toStrictEqual(
27+
[
28+
[ 2, 3 ], [ 4, 5 ], [ 6, 7 ],
29+
[ 8, 9 ], [ 10 ]
30+
]
31+
);
32+
} );
33+
34+
test( 'pickSequence', async () => {
35+
expect( Array.from(
36+
pickSequence(
37+
[
38+
'* line 1',
39+
'* line 2',
40+
'*: comment for line 2',
41+
'* line 3',
42+
'* line 4'
43+
],
44+
( v ) => /\*[^:*#]/.test( v )
45+
)
46+
) ).toStrictEqual(
47+
[
48+
[ '* line 1' ],
49+
[ '* line 2', '*: comment for line 2' ],
50+
[ '* line 3' ],
51+
[ '* line 4' ]
52+
]
53+
);
54+
} );
55+
56+
} );

0 commit comments

Comments
 (0)