1<?php
2
3use MediaWiki\Widget\TitleInputWidget;
4
5/**
6 * Implements a text input field for page titles.
7 * Automatically does validation that the title is valid,
8 * as well as autocompletion if using the OOUI display format.
9 *
10 * Optional parameters:
11 * 'namespace' - Namespace the page must be in
12 * 'relative' - If true and 'namespace' given, strip/add the namespace from/to the title as needed
13 * 'creatable' - Whether to validate the title is creatable (not a special page)
14 * 'exists' - Whether to validate that the title already exists
15 *
16 * @stable to extend
17 * @since 1.26
18 */
19class HTMLTitleTextField extends HTMLTextField {
20	/**
21	 * @stable to call
22	 * @inheritDoc
23	 */
24	public function __construct( $params ) {
25		$params += [
26			'namespace' => false,
27			'relative' => false,
28			'creatable' => false,
29			'exists' => false,
30			// This overrides the default from HTMLFormField
31			'required' => true,
32		];
33
34		parent::__construct( $params );
35	}
36
37	public function validate( $value, $alldata ) {
38		// Default value (from getDefault()) is null, which breaks Title::newFromTextThrow() below
39		if ( $value === null ) {
40			$value = '';
41		}
42
43		if ( !$this->mParams['required'] && $value === '' ) {
44			// If this field is not required and the value is empty, that's okay, skip validation
45			return parent::validate( $value, $alldata );
46		}
47
48		try {
49			if ( !$this->mParams['relative'] ) {
50				$title = Title::newFromTextThrow( $value );
51			} else {
52				// Can't use Title::makeTitleSafe(), because it doesn't throw useful exceptions
53				$title = Title::newFromTextThrow( Title::makeName( $this->mParams['namespace'], $value ) );
54			}
55		} catch ( MalformedTitleException $e ) {
56			return $this->msg( $e->getErrorMessage(), $e->getErrorMessageParameters() );
57		}
58
59		$text = $title->getPrefixedText();
60		if ( $this->mParams['namespace'] !== false &&
61			!$title->inNamespace( $this->mParams['namespace'] )
62		) {
63			return $this->msg( 'htmlform-title-badnamespace', $text, $this->mParams['namespace'] );
64		}
65
66		if ( $this->mParams['creatable'] && !$title->canExist() ) {
67			return $this->msg( 'htmlform-title-not-creatable', $text );
68		}
69
70		if ( $this->mParams['exists'] && !$title->exists() ) {
71			return $this->msg( 'htmlform-title-not-exists', $text );
72		}
73
74		return parent::validate( $value, $alldata );
75	}
76
77	protected function getInputWidget( $params ) {
78		if ( $this->mParams['namespace'] !== false ) {
79			$params['namespace'] = $this->mParams['namespace'];
80		}
81		$params['relative'] = $this->mParams['relative'];
82		return new TitleInputWidget( $params );
83	}
84
85	protected function shouldInfuseOOUI() {
86		return true;
87	}
88
89	protected function getOOUIModules() {
90		// FIXME: TitleInputWidget should be in its own module
91		return [ 'mediawiki.widgets' ];
92	}
93
94	public function getInputHtml( $value ) {
95		// add mw-searchInput class to enable search suggestions for non-OOUI, too
96		$this->mClass .= 'mw-searchInput';
97
98		// return the HTMLTextField html
99		return parent::getInputHTML( $value );
100	}
101
102	protected function getDataAttribs() {
103		return [
104			'data-mw-searchsuggest' => FormatJson::encode( [
105				'wrapAsLink' => false,
106			] ),
107		];
108	}
109}
110