Merge "Refactor thread summary getters"

This commit is contained in:
jenkins-bot 2022-09-06 22:17:26 +00:00 committed by Gerrit Code Review
commit 0632bfc92e
6 changed files with 110 additions and 58 deletions

View file

@ -149,20 +149,20 @@ class CommentFormatter {
}
// Visual enhancements: topic containers
$summary = $headingItem->getThreadSummary();
if ( $summary['commentCount'] ) {
$latestReplyJSON = static::getJsonForCommentMarker( $summary['latestReply'] );
$latestReplyItem = $headingItem->getLatestReply();
if ( $latestReplyItem ) {
$latestReplyJSON = static::getJsonForCommentMarker( $latestReplyItem );
$latestReply = $doc->createComment(
// Timestamp output varies by user timezone, so is formatted later
'__DTLATESTCOMMENTTHREAD__' . htmlspecialchars( $latestReplyJSON, ENT_NOQUOTES ) . '__'
);
$commentCount = $doc->createComment(
'__DTCOMMENTCOUNT__' . $summary['commentCount'] . '__'
'__DTCOMMENTCOUNT__' . $headingItem->getCommentCount() . '__'
);
$authorCount = $doc->createComment(
'__DTAUTHORCOUNT__' . count( $summary['authors'] ) . '__'
'__DTAUTHORCOUNT__' . count( $headingItem->getAuthorsBelow() ) . '__'
);
// Topic subscriptions
@ -201,7 +201,9 @@ class CommentFormatter {
$headingElement->appendChild( $bar );
}
$tocInfo[ $headingItem->getLinkableTitle() ] = $summary;
$tocInfo[ $headingItem->getLinkableTitle() ] = [
'commentCount' => $headingItem->getCommentCount(),
];
}
/**

View file

@ -979,7 +979,7 @@ class CommentParser {
// (e.g. dozens of threads titled "question" on [[Wikipedia:Help desk]]: https://w.wiki/fbN),
// include the oldest timestamp in the thread (i.e. date the thread was started) in the
// heading ID.
$oldestComment = $threadItem->getThreadSummary()['oldestReply'];
$oldestComment = $threadItem->getOldestReply();
if ( $oldestComment ) {
$id .= '-' . $oldestComment->getTimestampString();
}
@ -1013,7 +1013,7 @@ class CommentParser {
if ( $threadItem instanceof ContentHeadingItem ) {
$name = 'h-';
$mainComment = $threadItem->getThreadSummary()['oldestReply'];
$mainComment = $threadItem->getOldestReply();
} elseif ( $threadItem instanceof ContentCommentItem ) {
$name = 'c-';
$mainComment = $threadItem;

View file

@ -30,6 +30,11 @@ abstract class ContentThreadItem implements JsonSerializable, ThreadItem {
protected $id = null;
protected $replies = [];
protected $authors = null;
protected $commentCount;
protected $oldestReply;
protected $latestReply;
/**
* @param string $type `heading` or `comment`
* @param int $level Indentation level
@ -46,10 +51,11 @@ abstract class ContentThreadItem implements JsonSerializable, ThreadItem {
/**
* Get summary metadata for a thread.
*
* @return array Information about the comments below
*/
public function getThreadSummary(): array {
private function calculateThreadSummary(): void {
if ( $this->authors !== null ) {
return;
}
$authors = [];
$commentCount = 0;
$oldestReply = null;
@ -84,43 +90,57 @@ abstract class ContentThreadItem implements JsonSerializable, ThreadItem {
array_walk( $replies, $threadScan );
ksort( $authors );
return [
'authors' => array_keys( $authors ),
'commentCount' => $commentCount,
'oldestReply' => $oldestReply,
'latestReply' => $latestReply,
];
$this->authors = array_keys( $authors );
$this->commentCount = $commentCount;
$this->oldestReply = $oldestReply;
$this->latestReply = $latestReply;
}
/**
* Get the list of authors in the comment tree below this thread item.
* Get the list of authors in the tree below this thread item.
*
* Usually called on a HeadingItem to find all authors in a thread.
*
* @return string[] Author usernames
*/
public function getAuthorsBelow(): array {
$authors = [];
$getAuthorSet = static function ( ContentThreadItem $threadItem ) use ( &$authors, &$getAuthorSet ) {
if ( $threadItem instanceof ContentCommentItem ) {
$authors[ $threadItem->getAuthor() ] = true;
}
// Get the set of authors in the same format from each reply
foreach ( $threadItem->getReplies() as $reply ) {
$getAuthorSet( $reply );
}
};
foreach ( $this->getReplies() as $reply ) {
$getAuthorSet( $reply );
}
ksort( $authors );
return array_keys( $authors );
$this->calculateThreadSummary();
return $this->authors;
}
/**
* Get the list of thread items in the comment tree below this thread item.
* Get the number of comment items in the tree below this thread item.
*
* @return int
*/
public function getCommentCount(): int {
$this->calculateThreadSummary();
return $this->commentCount;
}
/**
* Get the latest reply in the tree below this thread item, null if there are no replies
*
* @return ContentCommentItem|null
*/
public function getLatestReply(): ?ContentCommentItem {
$this->calculateThreadSummary();
return $this->latestReply;
}
/**
* Get the oldest reply in the tree below this thread item, null if there are no replies
*
* @return ContentCommentItem|null
*/
public function getOldestReply(): ?ContentCommentItem {
$this->calculateThreadSummary();
return $this->oldestReply;
}
/**
* Get a flat list of thread items in the comment tree below this thread item.
*
* @return ContentThreadItem[] Thread items
*/

View file

@ -956,7 +956,7 @@ Parser.prototype.computeId = function ( threadItem, previousItems ) {
// (e.g. dozens of threads titled "question" on [[Wikipedia:Help desk]]: https://w.wiki/fbN),
// include the oldest timestamp in the thread (i.e. date the thread was started) in the
// heading ID.
var oldestComment = threadItem.getThreadSummary().oldestReply;
var oldestComment = threadItem.getOldestReply();
if ( oldestComment ) {
id += '-' + oldestComment.getTimestampString();
}
@ -990,7 +990,7 @@ Parser.prototype.computeName = function ( threadItem ) {
if ( threadItem instanceof HeadingItem ) {
name = 'h-';
mainComment = threadItem.getThreadSummary().oldestReply;
mainComment = threadItem.getOldestReply();
} else if ( threadItem instanceof CommentItem ) {
name = 'c-';
mainComment = threadItem;

View file

@ -39,6 +39,11 @@ function ThreadItem( type, level, range ) {
this.warnings = [];
this.rootNode = null;
this.authors = null;
this.commentCount = null;
this.oldestReply = null;
this.latestReply = null;
}
OO.initClass( ThreadItem );
@ -112,11 +117,12 @@ ThreadItem.static.newFromJSON = function ( json, rootNode ) {
};
/**
* Get summary metadata for a thread.
*
* @return {Object} Information about the comments below
* Calculate summary metadata for a thread.
*/
ThreadItem.prototype.getThreadSummary = function () {
ThreadItem.prototype.calculateThreadSummary = function () {
if ( this.authors ) {
return;
}
var authors = {};
var commentCount = 0;
var oldestReply = null;
@ -142,12 +148,10 @@ ThreadItem.prototype.getThreadSummary = function () {
}
this.replies.forEach( threadScan );
return {
authors: Object.keys( authors ).sort(),
commentCount: commentCount,
oldestReply: oldestReply,
latestReply: latestReply
};
this.authors = Object.keys( authors ).sort();
this.commentCount = commentCount;
this.oldestReply = oldestReply;
this.latestReply = latestReply;
};
/**
@ -158,18 +162,38 @@ ThreadItem.prototype.getThreadSummary = function () {
* @return {string[]} Author usernames
*/
ThreadItem.prototype.getAuthorsBelow = function () {
var authors = {};
function getAuthorSet( comment ) {
if ( comment.type === 'comment' ) {
authors[ comment.author ] = true;
}
// Get the set of authors in the same format from each reply
comment.replies.forEach( getAuthorSet );
}
this.calculateThreadSummary();
return this.authors;
};
this.replies.forEach( getAuthorSet );
/**
* Get the number of comment items in the tree below this thread item.
*
* @return {number}
*/
ThreadItem.prototype.getCommentCount = function () {
this.calculateThreadSummary();
return this.commentCount;
};
return Object.keys( authors ).sort();
/**
* Get the latest reply in the tree below this thread item, null if there are no replies
*
* @return {CommentItem|null}
*/
ThreadItem.prototype.getLatestReply = function () {
this.calculateThreadSummary();
return this.latestReply;
};
/**
* Get the oldest reply in the tree below this thread item, null if there are no replies
*
* @return {CommentItem|null}
*/
ThreadItem.prototype.getOldestReply = function () {
this.calculateThreadSummary();
return this.oldestReply;
};
/**

View file

@ -91,6 +91,12 @@ module.exports.serializeComments = function ( parent, root ) {
// Unimportant
delete parent.rootNode;
// Ignore generated properties
delete parent.authors;
delete parent.commentCount;
delete parent.oldestReply;
delete parent.latestReply;
parent.replies.forEach( function ( comment ) {
module.exports.serializeComments( comment, root );
} );