DynamicPageList3/includes/Heading/Heading.php

417 lines
8.9 KiB
PHP
Raw Normal View History

2020-11-22 20:02:14 +00:00
<?php
2021-10-01 22:52:30 +00:00
namespace MediaWiki\Extension\DynamicPageList3\Heading;
2020-11-22 20:02:14 +00:00
use MediaWiki\Extension\DynamicPageList3\Article;
use MediaWiki\Extension\DynamicPageList3\Lister\Lister;
use MediaWiki\Extension\DynamicPageList3\Parameters;
2021-10-01 22:52:30 +00:00
use Sanitizer;
2020-11-22 20:02:14 +00:00
class Heading {
/**
* Listing style for this class.
*
2021-10-01 22:52:30 +00:00
* @var int|null
2020-11-22 20:02:14 +00:00
*/
public $style = null;
/**
* List(Section) Start
2021-10-01 22:52:30 +00:00
* Use %s for attribute placement. Example: <div%s>
2020-11-22 20:02:14 +00:00
*
2021-02-22 23:48:01 +00:00
* @var string
2020-11-22 20:02:14 +00:00
*/
public $listStart = '';
/**
* List(Section) End
*
2021-02-22 23:48:01 +00:00
* @var string
2020-11-22 20:02:14 +00:00
*/
public $listEnd = '';
/**
* Item Start
2021-10-01 22:52:30 +00:00
* Use %s for attribute placement. Example: <div%s>
2020-11-22 20:02:14 +00:00
*
2021-02-22 23:48:01 +00:00
* @var string
2020-11-22 20:02:14 +00:00
*/
public $itemStart = '';
/**
* Item End
*
2021-02-22 23:48:01 +00:00
* @var string
2020-11-22 20:02:14 +00:00
*/
public $itemEnd = '';
/**
* Extra list HTML attributes.
*
2021-10-01 22:52:30 +00:00
* @var string
2020-11-22 20:02:14 +00:00
*/
public $listAttributes = '';
/**
* Extra item HTML attributes.
*
2021-10-01 22:52:30 +00:00
* @var string
2020-11-22 20:02:14 +00:00
*/
public $itemAttributes = '';
/**
* If the article count per heading should be shown.
*
2021-02-22 23:48:01 +00:00
* @var bool
2020-11-22 20:02:14 +00:00
*/
protected $showHeadingCount = false;
/**
2021-10-01 22:52:30 +00:00
* Parameters
2020-11-22 20:02:14 +00:00
*
2021-10-01 22:52:30 +00:00
* @var Parameters
2020-11-22 20:02:14 +00:00
*/
2021-10-01 22:52:30 +00:00
protected $parameters;
2020-11-22 20:02:14 +00:00
/**
2021-10-01 22:52:30 +00:00
* @param Parameters $parameters
2020-11-22 20:02:14 +00:00
*/
2021-02-22 23:48:01 +00:00
public function __construct( Parameters $parameters ) {
$this->setListAttributes( $parameters->getParameter( 'hlistattr' ) );
$this->setItemAttributes( $parameters->getParameter( 'hitemattr' ) );
$this->setShowHeadingCount( $parameters->getParameter( 'headingcount' ) );
2020-11-22 20:02:14 +00:00
$this->parameters = $parameters;
}
/**
* Get a new List subclass based on user selection.
*
2021-10-01 22:52:30 +00:00
* @param string $style
* @param Parameters $parameters
* @return mixed
2020-11-22 20:02:14 +00:00
*/
2021-10-01 22:52:30 +00:00
public static function newFromStyle( $style, Parameters $parameters ) {
2021-02-22 23:48:01 +00:00
$style = strtolower( $style );
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
switch ( $style ) {
2020-11-22 20:02:14 +00:00
case 'definition':
2021-10-01 22:52:30 +00:00
$class = DefinitionHeading::class;
2020-11-22 20:02:14 +00:00
break;
case 'h1':
case 'h2':
case 'h3':
case 'h4':
case 'h5':
case 'h6':
case 'header':
2021-10-01 22:52:30 +00:00
$class = TieredHeading::class;
2020-11-22 20:02:14 +00:00
break;
case 'ordered':
2021-10-01 22:52:30 +00:00
$class = OrderedHeading::class;
2020-11-22 20:02:14 +00:00
break;
case 'unordered':
2021-10-01 22:52:30 +00:00
$class = UnorderedHeading::class;
2020-11-22 20:02:14 +00:00
break;
default:
return null;
}
2021-02-22 23:48:01 +00:00
return new $class( $parameters );
2020-11-22 20:02:14 +00:00
}
/**
2021-10-01 22:52:30 +00:00
* Get the Parameters object this object was constructed with.
2020-11-22 20:02:14 +00:00
*
2021-10-01 22:52:30 +00:00
* @return Parameters
2020-11-22 20:02:14 +00:00
*/
public function getParameters() {
return $this->parameters;
}
/**
* Set extra list attributes.
*
2021-10-01 22:52:30 +00:00
* @param string $attributes
2020-11-22 20:02:14 +00:00
*/
2021-02-22 23:48:01 +00:00
public function setListAttributes( $attributes ) {
2021-10-01 22:52:30 +00:00
$this->listAttributes = Sanitizer::fixTagAttributes( $attributes, 'ul' );
2020-11-22 20:02:14 +00:00
}
/**
* Set extra item attributes.
*
2021-10-01 22:52:30 +00:00
* @param string $attributes
2020-11-22 20:02:14 +00:00
*/
2021-02-22 23:48:01 +00:00
public function setItemAttributes( $attributes ) {
2021-10-01 22:52:30 +00:00
$this->itemAttributes = Sanitizer::fixTagAttributes( $attributes, 'li' );
2020-11-22 20:02:14 +00:00
}
/**
* Set if the article count per heading should be shown.
*
2021-10-01 22:52:30 +00:00
* @param bool $show
2020-11-22 20:02:14 +00:00
*/
2021-02-22 23:48:01 +00:00
public function setShowHeadingCount( $show = false ) {
$this->showHeadingCount = boolval( $show );
2020-11-22 20:02:14 +00:00
}
/**
* Return the list style.
*
2021-10-01 22:52:30 +00:00
* @return int
2020-11-22 20:02:14 +00:00
*/
public function getStyle() {
return $this->style;
}
/**
* Format a list of articles into all lists with headings as needed.
*
2021-10-01 22:52:30 +00:00
* @param array $articles
* @param Lister $lister
* @return string
2020-11-22 20:02:14 +00:00
*/
2021-02-22 23:48:01 +00:00
public function format( $articles, Lister $lister ) {
$columns = $this->getParameters()->getParameter( 'columns' );
$rows = $this->getParameters()->getParameter( 'rows' );
$rowSize = $this->getParameters()->getParameter( 'rowsize' );
$rowColFormat = $this->getParameters()->getParameter( 'rowcolformat' );
2020-11-22 20:02:14 +00:00
$count = 0;
$headings = Article::getHeadings();
$output = '';
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
if ( !empty( $headings ) ) {
if ( $columns != 1 || $rows != 1 ) {
2021-10-01 22:52:30 +00:00
$hspace = 2;
2020-11-22 20:02:14 +00:00
// repeat outer tags for each of the specified columns / rows in the output
// we assume that a heading roughly takes the space of two articles
2021-02-22 23:48:01 +00:00
$count = count( $articles ) + $hspace * count( $headings );
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
if ( $columns != 1 ) {
2020-11-22 20:02:14 +00:00
$iGroup = $columns;
} else {
$iGroup = $rows;
}
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
$nsize = floor( $count / $iGroup );
2021-10-01 22:52:30 +00:00
$rest = $count - ( floor( $nsize ) * floor( $iGroup ) );
2021-02-22 23:48:01 +00:00
if ( $rest > 0 ) {
2020-11-22 20:02:14 +00:00
$nsize += 1;
}
2021-10-01 22:52:30 +00:00
2020-11-22 20:02:14 +00:00
$output .= "{|" . $rowColFormat . "\n|\n";
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
if ( $nsize < $hspace + 1 ) {
2021-10-01 22:52:30 +00:00
$nsize = $hspace + 1;
2020-11-22 20:02:14 +00:00
}
2021-10-01 22:52:30 +00:00
2020-11-22 20:02:14 +00:00
$output .= $this->getListStart();
$nstart = 0;
2021-10-01 22:52:30 +00:00
$greml = $nsize;
$g = 0;
2020-11-22 20:02:14 +00:00
$offset = 0;
2021-02-22 23:48:01 +00:00
foreach ( $headings as $headingCount ) {
2020-11-22 20:02:14 +00:00
$headingStart = $nstart - $offset;
$headingLink = $articles[$headingStart]->mParentHLink;
$output .= $this->getItemStart() . $headingLink . $this->getItemEnd();
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
if ( $this->showHeadingCount ) {
$output .= $this->articleCountMessage( $headingCount );
2020-11-22 20:02:14 +00:00
}
2021-10-01 22:52:30 +00:00
2020-11-22 20:02:14 +00:00
$offset += $hspace;
$nstart += $hspace;
$portion = $headingCount;
$greml -= $hspace;
2021-10-01 22:52:30 +00:00
2020-11-22 20:02:14 +00:00
do {
$greml -= $portion;
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
if ( $greml > 0 ) {
$output .= $lister->formatList( $articles, $nstart - $offset, $portion );
2020-11-22 20:02:14 +00:00
$nstart += $portion;
$portion = 0;
break;
} else {
2021-02-22 23:48:01 +00:00
$output .= $lister->formatList( $articles, $nstart - $offset, $portion + $greml );
$nstart += ( $portion + $greml );
$portion = ( -$greml );
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
if ( $columns != 1 ) {
2020-11-22 20:02:14 +00:00
$output .= "\n|valign=top|\n";
} else {
$output .= "\n|-\n|\n";
}
2021-10-01 22:52:30 +00:00
2020-11-22 20:02:14 +00:00
++$g;
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
if ( $nstart + $nsize > $count ) {
2020-11-22 20:02:14 +00:00
$nsize = $count - $nstart;
}
2021-10-01 22:52:30 +00:00
2020-11-22 20:02:14 +00:00
$greml = $nsize;
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
if ( $greml <= 0 ) {
2020-11-22 20:02:14 +00:00
break;
}
}
2021-02-22 23:48:01 +00:00
} while ( $portion > 0 );
2021-10-01 22:52:30 +00:00
2020-11-22 20:02:14 +00:00
$output .= $this->getItemEnd();
}
2021-10-01 22:52:30 +00:00
2020-11-22 20:02:14 +00:00
$output .= $this->listEnd;
$output .= "\n|}\n";
} else {
$output .= $this->getListStart();
$headingStart = 0;
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
foreach ( $headings as $headingCount ) {
2020-11-22 20:02:14 +00:00
$headingLink = $articles[$headingStart]->mParentHLink;
2021-02-22 23:48:01 +00:00
$output .= $this->formatItem( $headingStart, $headingCount, $headingLink, $articles, $lister );
2020-11-22 20:02:14 +00:00
$headingStart += $headingCount;
}
2021-10-01 22:52:30 +00:00
2020-11-22 20:02:14 +00:00
$output .= $this->listEnd;
}
2021-02-22 23:48:01 +00:00
} elseif ( $columns != 1 || $rows != 1 ) {
2020-11-22 20:02:14 +00:00
// repeat outer tags for each of the specified columns / rows in the output
$nstart = 0;
2021-10-01 22:52:30 +00:00
$count = count( $articles );
2021-02-22 23:48:01 +00:00
if ( $columns != 1 ) {
2020-11-22 20:02:14 +00:00
$iGroup = $columns;
} else {
$iGroup = $rows;
}
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
$nsize = floor( $count / $iGroup );
2021-10-01 22:52:30 +00:00
$rest = $count - ( floor( $nsize ) * floor( $iGroup ) );
2021-02-22 23:48:01 +00:00
if ( $rest > 0 ) {
2020-11-22 20:02:14 +00:00
$nsize += 1;
}
2021-10-01 22:52:30 +00:00
2020-11-22 20:02:14 +00:00
$output .= "{|" . $rowColFormat . "\n|\n";
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
for ( $g = 0; $g < $iGroup; $g++ ) {
2021-10-01 22:52:30 +00:00
$output .= $lister->formatList( $articles, $nstart, (int)$nsize );
2021-02-22 23:48:01 +00:00
if ( $columns != 1 ) {
2020-11-22 20:02:14 +00:00
$output .= "\n|valign=top|\n";
} else {
$output .= "\n|-\n|\n";
}
2021-10-01 22:52:30 +00:00
$nstart += $nsize;
2021-02-22 23:48:01 +00:00
if ( $nstart + $nsize > $count ) {
2020-11-22 20:02:14 +00:00
$nsize = $count - $nstart;
}
}
2021-10-01 22:52:30 +00:00
2020-11-22 20:02:14 +00:00
$output .= "\n|}\n";
2021-02-22 23:48:01 +00:00
} elseif ( $rowSize > 0 ) {
2020-11-22 20:02:14 +00:00
// repeat row header after n lines of output
$nstart = 0;
2021-10-01 22:52:30 +00:00
$nsize = $rowSize;
$count = count( $articles );
2020-11-22 20:02:14 +00:00
$output .= '{|' . $rowColFormat . "\n|\n";
2021-10-01 22:52:30 +00:00
2020-11-22 20:02:14 +00:00
do {
2021-02-22 23:48:01 +00:00
if ( $nstart + $nsize > $count ) {
2020-11-22 20:02:14 +00:00
$nsize = $count - $nstart;
}
2021-10-01 22:52:30 +00:00
$output .= $lister->formatList( $articles, $nstart, (int)$nsize );
2020-11-22 20:02:14 +00:00
$output .= "\n|-\n|\n";
2021-10-01 22:52:30 +00:00
$nstart += $nsize;
2021-02-22 23:48:01 +00:00
if ( $nstart >= $count ) {
2020-11-22 20:02:14 +00:00
break;
}
2021-02-22 23:48:01 +00:00
} while ( true );
2021-10-01 22:52:30 +00:00
2020-11-22 20:02:14 +00:00
$output .= "\n|}\n";
} else {
2021-10-01 22:52:30 +00:00
// Even though the headingmode is not none there were no headings, but still results. Output them anyway.
2021-02-22 23:48:01 +00:00
$output .= $lister->formatList( $articles, 0, count( $articles ) );
2020-11-22 20:02:14 +00:00
}
return $output;
}
/**
* Format a heading group.
*
2021-10-01 22:52:30 +00:00
* @param int $headingStart
* @param int $headingCount
* @param string $headingLink
* @param array $articles
* @param Lister $lister
* @return string
2020-11-22 20:02:14 +00:00
*/
2021-02-22 23:48:01 +00:00
public function formatItem( $headingStart, $headingCount, $headingLink, $articles, Lister $lister ) {
2020-11-22 20:02:14 +00:00
$item = '';
$item .= $this->getItemStart() . $headingLink;
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
if ( $this->showHeadingCount ) {
$item .= $this->articleCountMessage( $headingCount );
2020-11-22 20:02:14 +00:00
}
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
$item .= $lister->formatList( $articles, $headingStart, $headingCount );
2020-11-22 20:02:14 +00:00
$item .= $this->getItemEnd();
return $item;
}
/**
* Return $this->listStart with attributes replaced.
*
2021-10-01 22:52:30 +00:00
* @return string
2020-11-22 20:02:14 +00:00
*/
public function getListStart() {
2021-02-22 23:48:01 +00:00
return sprintf( $this->listStart, $this->listAttributes );
2020-11-22 20:02:14 +00:00
}
/**
* Return $this->itemStart with attributes replaced.
*
2021-10-01 22:52:30 +00:00
* @return string
2020-11-22 20:02:14 +00:00
*/
public function getItemStart() {
2021-02-22 23:48:01 +00:00
return sprintf( $this->itemStart, $this->itemAttributes );
2020-11-22 20:02:14 +00:00
}
/**
* Return $this->itemEnd with attributes replaced.
*
2021-10-01 22:52:30 +00:00
* @return string
2020-11-22 20:02:14 +00:00
*/
public function getItemEnd() {
return $this->itemEnd;
}
/**
* Get the article count message appropriate for this list.
*
2021-10-01 22:52:30 +00:00
* @param int $count
* @return string
2020-11-22 20:02:14 +00:00
*/
2021-02-22 23:48:01 +00:00
protected function articleCountMessage( $count ) {
$orderMethods = $this->getParameters()->getParameter( 'ordermethods' );
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
if ( isset( $orderMethods[0] ) && $orderMethods[0] === 'category' ) {
2020-11-22 20:02:14 +00:00
$message = 'categoryarticlecount';
} else {
$message = 'dpl_articlecount';
}
2021-10-01 22:52:30 +00:00
2021-02-22 23:48:01 +00:00
return '<p>' . wfMessage( $message, $count )->escaped() . '</p>';
2020-11-22 20:02:14 +00:00
}
}