@@ -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 ;
0 commit comments