Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 110
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
EditIndexPage
0.00% covered (danger)
0.00%
0 / 110
0.00% covered (danger)
0.00%
0 / 8
650
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 showContentForm
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
30
 buildField
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
132
 buildCategoriesField
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
2
 getFieldNameForEntry
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 importContentFormData
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
20
 importCategoryList
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 cleanInputtedContent
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace ProofreadPage\Index;
4
5use Article;
6use LogicException;
7use MediaWiki\Content\WikitextContent;
8use MediaWiki\EditPage\EditPage;
9use MediaWiki\MediaWikiServices;
10use MediaWiki\Request\WebRequest;
11use MediaWiki\Title\Title;
12use OOUI\DropdownInputWidget;
13use OOUI\FieldLayout;
14use OOUI\FieldsetLayout;
15use OOUI\MultilineTextInputWidget;
16use OOUI\TextInputWidget;
17use ProofreadPage\Context;
18use ProofreadPage\OOUI\PagelistInputWidget;
19use ProofreadPage\Pagination\PageNumber;
20
21/**
22 * @license GPL-2.0-or-later
23 */
24class EditIndexPage extends EditPage {
25
26    /**
27     * @var Context
28     */
29    private $extContext;
30
31    /**
32     * @param Article $article Article of page to be edited
33     */
34    public function __construct( Article $article ) {
35        parent::__construct( $article );
36
37        $this->extContext = Context::getDefaultContext();
38    }
39
40    /**
41     * @inheritDoc
42     */
43    protected function showContentForm() {
44        $pageLang = $this->getTitle()->getPageLanguage();
45        $out = $this->context->getOutput();
46        $out->enableOOUI();
47        $inputOptions = [ 'lang' => $pageLang->getCode(), 'dir' => $pageLang->getDir() ];
48        if ( MediaWikiServices::getInstance()->getReadOnlyMode()->isReadOnly() ) {
49            $inputOptions['readOnly'] = '';
50        }
51
52        $content = $this->toEditContent( $this->textbox1 );
53        if ( !( $content instanceof IndexContent ) ) {
54            throw new LogicException( 'EditIndexPage is only able to display a form for IndexContent' );
55        }
56
57        $fields = [];
58        $i = 10;
59        $entries = $this->extContext->getCustomIndexFieldsParser()->parseCustomIndexFields( $content );
60        foreach ( $entries as $entry ) {
61            $inputOptions['tabIndex'] = $i;
62            if ( !$entry->isHidden() ) {
63                $fields[] = $this->buildField( $entry, $inputOptions );
64            }
65            $i++;
66        }
67
68        $inputOptions['tabIndex'] = $i;
69        $fields[] = $this->buildCategoriesField( $content->getCategories(), $inputOptions );
70
71        $out->addHTML( new FieldsetLayout( [
72            'items' => $fields,
73            'classes' => [ 'prp-index-fieldLayout' ]
74        ] ) );
75
76        $out->addModules( 'ext.proofreadpage.index' );
77    }
78
79    /**
80     * @param CustomIndexField $field
81     * @param array $inputOptions
82     * @return FieldLayout
83     */
84    private function buildField( CustomIndexField $field, $inputOptions ) {
85        $key = $this->getFieldNameForEntry( $field->getKey() );
86        $val = $field->getStringValue();
87        $out = $this->context->getOutput();
88
89        $out->addJsConfigVars( 'prpPagelistBuiltinLabels', PageNumber::getDisplayModes() );
90
91        $inputOptions['name'] = $key;
92        $inputOptions['value'] = $val;
93        $inputOptions['inputId'] = $key;
94
95        $values = $field->getPossibleValues();
96        if ( $values !== null ) {
97            $options = [];
98            foreach ( $values as $data => $label ) {
99                $options[] = [ 'data' => $data, 'label' => $label ];
100            }
101            if ( !array_key_exists( $val, $values ) && $val !== '' ) {
102                $options[] = [ 'data' => $val, 'label' => $val ];
103            }
104            $input = new DropdownInputWidget( $inputOptions + [
105                'options' => $options
106            ] );
107        } elseif ( $field->isPagelist() ) {
108            $input = new PagelistInputWidget( array_merge( [
109                'templateParameter' => $field->getKey(),
110                'rows' => $field->getSize()
111            ], $inputOptions ) );
112            $out->addModules( 'ext.proofreadpage.index.pagelist' );
113        } else {
114            if ( $field->getSize() > 1 ) {
115                $input = new MultilineTextInputWidget( $inputOptions + [
116                    'rows' => $field->getSize()
117                ] );
118            } else {
119                $input = new TextInputWidget( $inputOptions + [
120                    'type' => $field->getType() === 'number' && ( $val === '' || is_numeric( $val ) )
121                        ? 'number'
122                        : 'text',
123                ] );
124            }
125        }
126
127        $fieldLayoutArgs = [
128            'label' => $field->getLabel()
129        ];
130        if ( $field->getHelp() ) {
131            $fieldLayoutArgs += [
132                'help' => $field->getHelp(),
133                'infusable' => true,
134                'classes' => [ 'prp-fieldLayout-help' ]
135            ];
136        }
137
138        return new FieldLayout( $input, $fieldLayoutArgs );
139    }
140
141    /**
142     * @param array $categories
143     * @param array $inputOptions
144     * @return FieldLayout
145     */
146    private function buildCategoriesField( array $categories, $inputOptions ) {
147        $input = new TextInputWidget( $inputOptions + [
148            'type' => 'text',
149            'name' => 'wpPrpCategories',
150            'value' => implode( '|', array_map( static function ( Title $title ) {
151                return $title->getText();
152            }, $categories ) ),
153            'inputId' => 'wpPrpCategories'
154        ] );
155        return new FieldLayout( $input, [
156            'label' => $this->context->msg( 'proofreadpage-index-field-category-label' )->text(),
157            'help' => $this->context->msg( 'proofreadpage-index-edit-category-help' )->text(),
158            'infusable' => true,
159            'classes' => [ 'prp-fieldLayout-help' ]
160        ] );
161    }
162
163    /**
164     * Return the name of the edit field for an entry
165     *
166     * @param string $key the entry key
167     * @return string
168     */
169    protected function getFieldNameForEntry( $key ) {
170        return 'wpprpindex-' . str_replace( ' ', '_', $key );
171    }
172
173    /**
174     * @inheritDoc
175     */
176    protected function importContentFormData( &$request ) {
177        if ( $this->textbox1 !== '' ) {
178            return $this->textbox1;
179        }
180
181        $config = $this->extContext->getCustomIndexFieldsParser()->getCustomIndexFieldsConfiguration();
182        $fields = [];
183        foreach ( $config as $key => $params ) {
184            $field = $this->getFieldNameForEntry( $key );
185            $value = $this->cleanInputtedContent( $request->getText( $field ) );
186            $entry = new CustomIndexField( $key, $value, $params );
187            if ( !$entry->isHidden() ) {
188                $fields[$entry->getKey()] = new WikitextContent( $entry->getStringValue() );
189            }
190        }
191        $content = new IndexContent( $fields, $this->importCategoryList( $request ) );
192        return $content->serialize( $this->contentFormat );
193    }
194
195    /**
196     * Returns filtered list of categories from a web request.
197     * @param WebRequest $request
198     * @return Title[]
199     */
200    private function importCategoryList( WebRequest $request ) {
201        return array_filter( array_map( static function ( $text ) {
202            return Title::makeTitleSafe( NS_CATEGORY, trim( $text ) );
203        }, explode( '|', $request->getText( 'wpPrpCategories' ) ) ), static function ( $title ) {
204            return $title !== null;
205        } );
206    }
207
208    /**
209     * Clean a text before inclusion into a template
210     *
211     * @param string $value
212     * @return string
213     */
214    protected function cleanInputtedContent( $value ) {
215        // remove trailing \n \t or \r
216        $value = trim( $value );
217
218        // replace pipe symbol everywhere...
219        $value = preg_replace( '/\|/', '&!&', $value );
220
221        // ...except in links...
222        do {
223            $prev = $value;
224            $value = preg_replace( '/\[\[(.*?)&!&(.*?)\]\]/', '[[$1|$2]]', $value );
225        } while ( $value !== $prev );
226
227        // ..and in templates
228        do {
229            $prev = $value;
230            $value = preg_replace( '/\{\{(.*?)&!&(.*?)\}\}/s', '{{$1|$2}}', $value );
231        } while ( $value !== $prev );
232
233        $value = preg_replace( '/&!&/', '{{!}}', $value );
234
235        return $value;
236    }
237}