Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
98.86% |
173 / 175 |
|
83.33% |
5 / 6 |
CRAP | |
0.00% |
0 / 1 |
| ImportPreviewPage | |
98.86% |
173 / 175 |
|
83.33% |
5 / 6 |
13 | |
0.00% |
0 / 1 |
| getHtml | |
98.33% |
118 / 120 |
|
0.00% |
0 / 1 |
3 | |||
| buildShowChangesButtonHtml | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
1 | |||
| buildEditSummaryHtml | |
100.00% |
25 / 25 |
|
100.00% |
1 / 1 |
5 | |||
| buildImportIdentityFormSnippet | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 | |||
| buildCategoriesSnippet | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
1 | |||
| wasEdited | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace FileImporter\Html; |
| 4 | |
| 5 | use FileImporter\Data\ImportPlan; |
| 6 | use FileImporter\Services\CategoryExtractor; |
| 7 | use MediaWiki\EditPage\EditPage; |
| 8 | use MediaWiki\Html\Html; |
| 9 | use MediaWiki\Linker\Linker; |
| 10 | use MediaWiki\MediaWikiServices; |
| 11 | use MediaWiki\Registration\ExtensionRegistry; |
| 12 | use OOUI\ButtonInputWidget; |
| 13 | use OOUI\ButtonWidget; |
| 14 | use OOUI\TextInputWidget; |
| 15 | |
| 16 | /** |
| 17 | * Page displaying the preview of the import before it has happened. |
| 18 | * |
| 19 | * @license GPL-2.0-or-later |
| 20 | * @author Addshore |
| 21 | */ |
| 22 | class ImportPreviewPage extends SpecialPageHtmlFragment { |
| 23 | |
| 24 | public const ACTION_BUTTON = 'action'; |
| 25 | public const ACTION_EDIT_TITLE = 'edittitle'; |
| 26 | public const ACTION_EDIT_INFO = 'editinfo'; |
| 27 | public const ACTION_SUBMIT = 'submit'; |
| 28 | public const ACTION_VIEW_DIFF = 'viewdiff'; |
| 29 | |
| 30 | public function getHtml( ImportPlan $importPlan ): string { |
| 31 | // TODO: Inject |
| 32 | if ( ExtensionRegistry::getInstance()->isLoaded( 'CentralAuth' ) ) { |
| 33 | $config = $this->getContext()->getConfig(); |
| 34 | $sourceEditingEnabled = $config->get( 'FileImporterSourceWikiTemplating' ); |
| 35 | $sourceDeletionEnabled = $config->get( 'FileImporterSourceWikiDeletion' ); |
| 36 | } else { |
| 37 | $sourceEditingEnabled = false; |
| 38 | $sourceDeletionEnabled = false; |
| 39 | } |
| 40 | |
| 41 | $text = $importPlan->getFileInfoText(); |
| 42 | $title = $importPlan->getTitle(); |
| 43 | |
| 44 | $details = $importPlan->getDetails(); |
| 45 | $textRevisionsCount = count( $details->getTextRevisions()->toArray() ); |
| 46 | $fileRevisionsCount = count( $details->getFileRevisions()->toArray() ); |
| 47 | $categoriesSnippet = $this->buildCategoriesSnippet( $importPlan ); |
| 48 | |
| 49 | return Html::openElement( |
| 50 | 'form', |
| 51 | [ |
| 52 | 'action' => $this->getPageTitle()->getLocalURL(), |
| 53 | 'method' => 'POST', |
| 54 | ] |
| 55 | ) . |
| 56 | Html::hidden( 'wpUnicodeCheck', EditPage::UNICODE_CHECK ) . |
| 57 | ( new HelpBanner( $this ) )->getHtml() . |
| 58 | $this->msg( 'fileimporter-previewnote' )->parseAsBlock() . |
| 59 | Html::rawElement( |
| 60 | 'div', |
| 61 | [ 'class' => 'mw-importfile-header' ], |
| 62 | Html::element( |
| 63 | 'h2', |
| 64 | [], |
| 65 | $title->getText() |
| 66 | ) . |
| 67 | new ButtonInputWidget( |
| 68 | [ |
| 69 | 'classes' => [ 'mw-importfile-rightAlign' ], |
| 70 | 'label' => $this->msg( 'fileimporter-edittitle' )->plain(), |
| 71 | 'type' => 'submit', |
| 72 | 'name' => self::ACTION_BUTTON, |
| 73 | 'value' => self::ACTION_EDIT_TITLE |
| 74 | ] |
| 75 | ) |
| 76 | ) . |
| 77 | Linker::makeExternalImage( $details->getImageDisplayUrl(), $title->getPrefixedText() ) . |
| 78 | Html::rawElement( |
| 79 | 'div', |
| 80 | [ 'class' => 'mw-importfile-header' ], |
| 81 | Html::element( |
| 82 | 'h2', |
| 83 | [], |
| 84 | $this->msg( 'fileimporter-heading-fileinfo' )->plain() |
| 85 | ) . |
| 86 | new ButtonInputWidget( |
| 87 | [ |
| 88 | 'classes' => [ 'mw-importfile-rightAlign' ], |
| 89 | 'label' => $this->msg( 'fileimporter-editinfo' )->plain(), |
| 90 | 'type' => 'submit', |
| 91 | 'name' => self::ACTION_BUTTON, |
| 92 | 'value' => self::ACTION_EDIT_INFO |
| 93 | ] |
| 94 | ) |
| 95 | ) . |
| 96 | Html::rawElement( |
| 97 | 'div', |
| 98 | [ 'class' => 'mw-importfile-parsedContent' ], |
| 99 | ( new TextRevisionSnippet( $this ) )->getHtml( |
| 100 | $details->getTextRevisions()->getLatest(), |
| 101 | $text |
| 102 | ) |
| 103 | ) . |
| 104 | $categoriesSnippet . |
| 105 | Html::element( 'h2', [], $this->msg( 'fileimporter-heading-filehistory' )->plain() ) . |
| 106 | $this->msg( |
| 107 | 'fileimporter-filerevisions', |
| 108 | [ |
| 109 | $fileRevisionsCount, |
| 110 | $fileRevisionsCount, |
| 111 | ] |
| 112 | )->parseAsBlock() . |
| 113 | ( new SourceWikiCleanupSnippet( |
| 114 | $sourceEditingEnabled, |
| 115 | $sourceDeletionEnabled |
| 116 | ) )->getHtml( $importPlan, $this->getUser() ) . |
| 117 | Html::openElement( 'div', [ 'class' => 'mw-importfile-importOptions' ] ) . |
| 118 | $this->buildEditSummaryHtml( $importPlan ) . |
| 119 | $this->msg( |
| 120 | 'fileimporter-textrevisions', |
| 121 | [ |
| 122 | $textRevisionsCount, |
| 123 | $textRevisionsCount, |
| 124 | ] |
| 125 | )->parseAsBlock() . |
| 126 | Html::element( |
| 127 | 'input', |
| 128 | [ |
| 129 | 'type' => 'hidden', |
| 130 | 'name' => 'token', |
| 131 | 'value' => $this->getUser()->getEditToken() |
| 132 | ] |
| 133 | ) . |
| 134 | new ButtonInputWidget( |
| 135 | [ |
| 136 | 'classes' => [ 'mw-importfile-import-submit' ], |
| 137 | 'label' => $this->msg( 'fileimporter-import' )->plain(), |
| 138 | 'type' => 'submit', |
| 139 | 'flags' => [ 'primary', 'progressive' ], |
| 140 | 'name' => self::ACTION_BUTTON, |
| 141 | 'value' => self::ACTION_SUBMIT, |
| 142 | 'infusable' => true |
| 143 | ] |
| 144 | ) . |
| 145 | ( $this->wasEdited( $importPlan ) ? $this->buildShowChangesButtonHtml() : '' ) . |
| 146 | new ButtonWidget( |
| 147 | [ |
| 148 | 'classes' => [ 'mw-importfile-import-cancel' ], |
| 149 | 'label' => $this->msg( 'fileimporter-cancel' )->plain(), |
| 150 | 'href' => $importPlan->getRequest()->getUrl()->getUrl() |
| 151 | ] |
| 152 | ) . |
| 153 | Html::element( 'span', [], $this->msg( 'fileimporter-import-wait' )->plain() ) . |
| 154 | $this->buildImportIdentityFormSnippet( $importPlan ) . |
| 155 | // End of mw-importfile-importOptions |
| 156 | Html::closeElement( 'div' ) . |
| 157 | Html::closeElement( 'form' ); |
| 158 | } |
| 159 | |
| 160 | private function buildShowChangesButtonHtml(): ButtonInputWidget { |
| 161 | return new ButtonInputWidget( |
| 162 | [ |
| 163 | 'classes' => [ 'mw-importfile-import-diff' ], |
| 164 | 'label' => $this->msg( 'fileimporter-viewdiff' )->plain(), |
| 165 | 'name' => self::ACTION_BUTTON, |
| 166 | 'value' => self::ACTION_VIEW_DIFF, |
| 167 | 'type' => 'submit', |
| 168 | ] |
| 169 | ); |
| 170 | } |
| 171 | |
| 172 | /** |
| 173 | * @return string |
| 174 | */ |
| 175 | private function buildEditSummaryHtml( ImportPlan $importPlan ) { |
| 176 | $summary = $importPlan->getRequest()->getIntendedSummary(); |
| 177 | if ( $summary === null ) { |
| 178 | $replacements = $importPlan->getNumberOfTemplateReplacements(); |
| 179 | $summary = $replacements > 0 |
| 180 | ? $this->msg( |
| 181 | 'fileimporter-auto-replacements-summary', |
| 182 | $replacements |
| 183 | )->inContentLanguage()->text() |
| 184 | : null; |
| 185 | } |
| 186 | if ( $summary === null |
| 187 | && !$this->wasEdited( $importPlan ) |
| 188 | ) { |
| 189 | return ''; |
| 190 | } |
| 191 | |
| 192 | return Html::element( |
| 193 | 'p', |
| 194 | [], |
| 195 | $this->msg( 'fileimporter-editsummary' )->plain() |
| 196 | ) . |
| 197 | new TextInputWidget( |
| 198 | [ |
| 199 | 'name' => 'intendedRevisionSummary', |
| 200 | 'classes' => [ 'mw-importfile-import-summary' ], |
| 201 | 'value' => $summary, |
| 202 | 'infusable' => true |
| 203 | ] |
| 204 | ); |
| 205 | } |
| 206 | |
| 207 | private function buildImportIdentityFormSnippet( ImportPlan $importPlan ): string { |
| 208 | return ( new ImportIdentityFormSnippet( [ |
| 209 | 'clientUrl' => $importPlan->getRequest()->getUrl(), |
| 210 | 'intendedFileName' => $importPlan->getFileName(), |
| 211 | 'intendedWikitext' => $importPlan->getFileInfoText(), |
| 212 | 'actionStats' => json_encode( $importPlan->getActionStats() ), |
| 213 | 'validationWarnings' => json_encode( $importPlan->getValidationWarnings() ), |
| 214 | 'importDetailsHash' => $importPlan->getDetails()->getOriginalHash(), |
| 215 | ] ) )->getHtml(); |
| 216 | } |
| 217 | |
| 218 | /** |
| 219 | * @return string HTML snippet for a box showing the categories, or empty string if there are |
| 220 | * no categories. |
| 221 | */ |
| 222 | private function buildCategoriesSnippet( ImportPlan $importPlan ) { |
| 223 | /** @var CategoryExtractor $categoryExtractor */ |
| 224 | $categoryExtractor = MediaWikiServices::getInstance() |
| 225 | ->getService( 'FileImporterCategoryExtractor' ); |
| 226 | [ $visibleCategories, $hiddenCategories ] = $categoryExtractor->getCategoriesGrouped( |
| 227 | $importPlan->getFileInfoText(), |
| 228 | $importPlan->getTitle(), |
| 229 | $this->getUser() |
| 230 | ); |
| 231 | return ( new CategoriesSnippet( |
| 232 | $visibleCategories, |
| 233 | $hiddenCategories |
| 234 | ) )->getHtml(); |
| 235 | } |
| 236 | |
| 237 | /** |
| 238 | * @return bool |
| 239 | */ |
| 240 | private function wasEdited( ImportPlan $importPlan ) { |
| 241 | return $importPlan->wasFileInfoTextChanged() || |
| 242 | $importPlan->getNumberOfTemplateReplacements() > 0; |
| 243 | } |
| 244 | |
| 245 | } |