Samwilson has uploaded a new change for review. https://gerrit.wikimedia.org/r/324657
Change subject: Add new special page for searching assessments ...................................................................... Add new special page for searching assessments This adds Special:PageAssessments with a basic search form and results table. The special page can also be transcluded, in which case the search form isn't shown (all search and sort parameters must be provided in the transclusion). Bug: T120407 Change-Id: I6ee898059ffc62bb5f2788ad83a49b650cdb1335 --- M extension.json M i18n/en.json M i18n/qqq.json A src/NamespaceSelect.php A src/Pager.php A src/SpecialPage.php 6 files changed, 304 insertions(+), 3 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/PageAssessments refs/changes/57/324657/1 diff --git a/extension.json b/extension.json index 49a9529..bd8ccd7 100644 --- a/extension.json +++ b/extension.json @@ -19,7 +19,10 @@ "PageAssessmentsHooks": "PageAssessments.hooks.php", "PageAssessmentsBody": "PageAssessmentsBody.php", "ApiQueryPageAssessments": "api/ApiQueryPageAssessments.php", - "ApiQueryProjectPages": "api/ApiQueryProjectPages.php" + "ApiQueryProjectPages": "api/ApiQueryProjectPages.php", + "PageAssessments\\SpecialPage": "src/SpecialPage.php", + "PageAssessments\\Pager": "src/Pager.php", + "PageAssessments\\NamespaceSelect": "src/NamespaceSelect.php" }, "ExtensionMessagesFiles": { "PageAssessmentsMagic": "PageAssessments.i18n.magic.php" @@ -47,6 +50,9 @@ "localBasePath": "", "remoteExtPath": "examples/PageAssessments" }, + "SpecialPages": { + "PageAssessments": "PageAssessments\\SpecialPage" + }, "config": { "PageAssessmentsOnTalkPages": true }, diff --git a/i18n/en.json b/i18n/en.json index f5a0313..2125fc9 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -16,5 +16,13 @@ "apihelp-query+projectpages-param-limit": "The maximum number of pages to return.", "apihelp-query+projectpages-example-simple-1": "Get first 10 pages associated with any WikiProject.", "apihelp-query+projectpages-example-simple-2": "Get first 10 pages associated with WikiProject <kbd>Medicine</kbd>, including assessment data.", - "apihelp-query+projectpages-example-generator": "Get page info for first 10 pages associated with WikiProject <kbd>Textile Arts</kbd>." + "apihelp-query+projectpages-example-generator": "Get page info for first 10 pages associated with WikiProject <kbd>Textile Arts</kbd>.", + "pageassessments-special": "Page assessments", + "pageassessments-project": "Project", + "pageassessments-page-namespace": "Page namespace", + "pageassessments-page-title": "Page title", + "pageassessments-search": "Search", + "pageassessments-importance": "Importance", + "pageassessments-class": "Class", + "pageassessments-timestamp": "Timestamp" } diff --git a/i18n/qqq.json b/i18n/qqq.json index 6caf8ec..def5a22 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -16,5 +16,14 @@ "apihelp-query+projectpages-param-limit": "{{doc-apihelp-param|query+projectpages|limit}}", "apihelp-query+projectpages-example-simple-1": "{{doc-apihelp-example|query+projectpages}}", "apihelp-query+projectpages-example-simple-2": "{{doc-apihelp-example|query+projectpages}}", - "apihelp-query+projectpages-example-generator": "{{doc-apihelp-example|query+projectpages}}" + "apihelp-query+projectpages-example-generator": "{{doc-apihelp-example|query+projectpages}}", + "pageassessments-special": "Name of the Special page", + "pageassessments-project": "Form label for the WikiProject search field and the results table column header", + "pageassessments-page-namespace": "Form label for the page namespace dropdown select field", + "pageassessments-page-title": "Form label for the page title search field and the results table column header", + "pageassessments-search": "Search form submit button label", + "pageassessments-importance": "Label for the search form and the results table column header", + "pageassessments-class": "Label for the search form and the results table column header", + "pageassessments-timestamp": "Label for the search form and the results table column header" + } diff --git a/src/NamespaceSelect.php b/src/NamespaceSelect.php new file mode 100644 index 0000000..49a09b4 --- /dev/null +++ b/src/NamespaceSelect.php @@ -0,0 +1,37 @@ +<?php + +namespace PageAssessments; + +use HTMLSelectNamespace; +use MediaWiki\Widget\NamespaceInputWidget; +use MWNamespace; + +/** + * This is an HTML form field for selecting non-talk namespaces. It excludes all namespaces with + * an even-numbered ID. + * + * It only overrides the OOUI widget because that's all that the PageAssessments special page needs. + */ +class NamespaceSelect extends HTMLSelectNamespace { + + /** + * Get the widget for selecting one or all non-talkspace namespace(s). + * @param string $value The currently selected value. + * @return NamespaceInputWidget + */ + public function getInputOOUI( $value ) { + $nsIds = array_keys( MWNamespace::getCanonicalNamespaces() ); + $excludedNsIds = array_filter( $nsIds, function( $ns ) { + return MWNamespace::isTalk( $ns ); + } ); + $widget = new NamespaceInputWidget( [ + 'value' => $value, + 'name' => $this->mName, + 'id' => $this->mID, + 'includeAllValue' => $this->mAllValue, + 'exclude' => $excludedNsIds, + ] ); + return $widget; + } + +} diff --git a/src/Pager.php b/src/Pager.php new file mode 100644 index 0000000..30e34a6 --- /dev/null +++ b/src/Pager.php @@ -0,0 +1,149 @@ +<?php +namespace PageAssessments; + +use LikeMatch; +use MediaWiki\MediaWikiServices; +use TablePager; +use Title; + +class Pager extends TablePager { + + /** @var boolean Should field sorting be enabled? */ + protected $sortable; + + /** + * All parameters for the main paged query. + * @return string[] + */ + public function getQueryInfo() { + $info = [ + 'tables' => [ 'page_assessments', 'page_assessments_projects', 'page', 'revision' ], + 'fields' => [ + 'project' => 'pap_project_title', + 'page' => 'pa_class', + 'importance' => 'pa_importance', + 'timestamp' => 'rev_timestamp', + 'page_title' => 'page_title', + 'page_revision' => 'pa_page_revision', + 'page_namespace' => 'page_namespace', + ], + 'conds' => [], + 'options' => [], + 'join_conds' => [ + 'page_assessments_projects' => [ 'JOIN', 'pa_project_id = pap_project_id' ], + 'page' => [ 'JOIN', 'pa_page_id = page_id' ], + 'revision' => [ 'JOIN', 'page_id = rev_page AND pa_page_revision = rev_id' ], + ], + ]; + // Project. + $project = $this->getRequest()->getVal( 'project', false ); + if ( !empty( $project ) ) { + $info['conds']['pap_project_title'] = $project; + } + // Namespace (if its set, it's either an integer >= 0, 'all', or the empty string). + $namespace = $this->getRequest()->getVal( 'namespace', false ); + if ( $namespace !== 'all' && $namespace !== '' ) { + $info['conds']['page_namespace'] = $namespace; + } + $pageTitle = $this->getRequest()->getVal( 'page_title', false ); + if ( !empty( $pageTitle ) ) { + $title = Title::newFromText( $pageTitle )->getDBkey(); + $db = $this->getDatabase(); + $info['conds'][] = 'page_title'.$db->buildLike( new LikeMatch( $title ) ); + } + return $info; + } + + /** + * Should the table be sortable? It's not when transcluded. + * @param boolean $sortable Whether to sort or not. + */ + public function setSortable( $sortable ) { + $this->sortable = (bool)$sortable; + } + + /** + * Return true if the named field should be sortable by the UI, false otherwise. + * @param string $field The field in question; matches one returned by self::getFieldNames(). + * @return boolean + */ + public function isFieldSortable( $field ) { + // Done enable sorting for transcluded pagers, because the sorting links will not be to + // the current page. + if ( $this->sortable === false ) { + // Strict check, to avoid false negative when this method is used in parent::__construct + return false; + } + $sortable = [ + 'project', + 'page', + 'timestamp', + ]; + return in_array( $field, $sortable ); + } + + /** + * Format a table cell. The return value should be HTML, but use an empty + * string not   for empty cells. Do not include the <td> and </td>. + * + * The current result row is available as $this->mCurrentRow, in case you + * need more context. + * + * @param string $name The database field name + * @param string $value The value retrieved from the database + * @return string + */ + public function formatValue( $name, $value ) { + $renderer = MediaWikiServices::getInstance()->getLinkRenderer(); + $pageTitle = Title::newFromText( + $this->mCurrentRow->page_title, + $this->mCurrentRow->page_namespace + ); + + // Page title. + if ( $name === 'page' ) { + return $renderer->makeKnownLink( $pageTitle ); + } + + // Timestamp of assessed revision. + if ( $name === 'timestamp' ) { + $lang = $this->getLanguage(); + $ts = $lang->userTimeAndDate( $this->mCurrentRow->timestamp, $this->getUser() ); + $linkQuery = [ 'oldid' => $this->mCurrentRow->page_revision ]; + return $renderer->makeKnownLink( $pageTitle, $ts, [], $linkQuery ); + } + + // All field names from self::getFieldNames() have been taken care of above, + // so this shouldn't be used. + return $value; + } + + /** + * An array mapping database field names to a textual description of the + * field name, for use in the table header. The description should be plain + * text, it will be HTML-escaped later. + * + * @return array + */ + public function getFieldNames() { + return [ + 'project' => wfMessage( 'pageassessments-project' )->text(), + 'page' => wfMessage( 'pageassessments-page-title' )->text(), + 'importance' => wfMessage( 'pageassessments-importance' )->text(), + 'class' => wfMessage( 'pageassessments-class' )->text(), + 'timestamp' => wfMessage( 'pageassessments-timestamp' )->text(), + ]; + } + + /** + * The database field name used as a default sort order. + * + * @protected + * + * @return string + */ + public function getDefaultSort() { + return 'project'; + } + +} diff --git a/src/SpecialPage.php b/src/SpecialPage.php new file mode 100644 index 0000000..609a171 --- /dev/null +++ b/src/SpecialPage.php @@ -0,0 +1,92 @@ +<?php + +namespace PageAssessments; + +use HTMLForm; +use HTMLTextField; +use SpecialPage as MediaWikiSpecialPage; + +/** + * + */ +class SpecialPage extends MediaWikiSpecialPage { + + /** + * Create this special page, giving it a name and making it transcludable. + */ + public function __construct() { + parent::__construct(); + $this->mName = 'PageAssessments'; + $this->mIncludable = true; + } + + /** + * Returns the name that goes in the \<h1\> in the special page itself, and + * also the name that will be listed in Special:Specialpages. + * + * Overridden here because we want proper sentence casing, rather than 'PageAssessments'. + * + * @return string + */ + function getDescription() { + return $this->msg( 'pageassessments-special' )->text(); + } + + /** + * Output the special page. + * @param string $parameters The parameters to the special page. + */ + public function execute( $parameters ) { + // Set up. + $out = $this->getOutput(); + $out->setPageTitle( $this->getDescription() ); + $this->addHelpLink( 'Help:Extension:PageAssessments' ); + + // Output form. + if ( !$this->including() ) { + $form = $this->getForm(); + $form->show(); + } + + // Output results (request also has 'title' when this special page is not transcluded). + $queryValues = $this->getRequest()->getQueryValues(); + unset( $queryValues['title'] ); + if ( count( $queryValues ) > 0 ) { + $pager = new Pager(); + $pager->setSortable( !$this->including() ); + $out->addParserOutput( $pager->getFullOutput() ); + } + } + + /** + * Get the search form. + * @return HTMLForm + */ + protected function getForm() { + $formDescriptor = [ + 'project' => [ + 'class' => HTMLTextField::class, + 'name' => 'project', + 'label-message' => 'pageassessments-project', + ], + 'namespace' => [ + 'class' => NamespaceSelect::class, + 'name' => 'namespace', + 'label-message' => 'pageassessments-page-namespace', + ], + 'page_title' => [ + 'class' => HTMLTextField::class, + 'name' => 'page_title', + 'label-message' => 'pageassessments-page-title', + ], + ]; + $form = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() ); + $form->setMethod( 'get' ); + $form->setSubmitTextMsg( 'pageassessments-search' ); + $form->setSubmitCallback( function() { + // No callback required, but HTMLForm says we have to set one. + } ); + return $form; + } + +} -- To view, visit https://gerrit.wikimedia.org/r/324657 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I6ee898059ffc62bb5f2788ad83a49b650cdb1335 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/PageAssessments Gerrit-Branch: master Gerrit-Owner: Samwilson <s...@samwilson.id.au> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits